8
$\begingroup$

I want Mathematica to periodically autosave my notebooks to the temp folder. And in case of front-end crash i want to see the dialog after restart with the following choices:

  • recover from autosaved drafts
  • discard drafts and open last manually saved versions
  • start a new session

Ideally i would like to make a fully automated solution that doesn't requre to execute any commands each time i open a new notebook.

Do you have any suggestions how to implement this functionality?

There is a hidden NotebookAutoSave option which saves notebook at every evaluation, but it has several disadvantages. It overwrites manually saved notebook and if i accidentally delete an important code (and evalute something) i'm unable to restore from the manually saved file. In OS X a built-in backup system can help, but when notebook is saved after each evaluation i get too many versions. There is also no possibility to distinguish manually saved version from all that autosaves in the Time Machine.

Another problem with NotebookAutoSave is that it is only triggered by the evaluation. It doesn't help when i write code, open built-in help and front-end crashes during help browsing process.

$\endgroup$
1

1 Answer 1

4
$\begingroup$

Motivated by the same concerns, I wrote the following code and added it to my init.m file. There are two main entries you'll want to change to use this. The global variable $SwapDirectory is where the swap files are saved (by swap file, I mean it in the VIm sense; an "extra" copy of your notebook, separate from your manually saved copy that periodically saves any new work). The swap files are organized within the swap directory in a directory structure which "mirrors" their original file locations, and have ".swp" appended to their file names. The other variable you might want to change is the number of seconds between autosaves, indicated by the "300" (corresponding to 5 minutes) near the bottom of the code below. At the appropriate times, this code will (automatically in the background) save swap files for ALL open notebooks, unless they are unmodified from their manually-saved versions (this exception makes the code more efficient, and more importantly, prevents the storage of swap files for documentation notebooks, for example).

Some things to note:
1) the Mathematica Put command seems to have trouble writing to network drives, even when offline access is enabled. Therefore, it is probably best to choose a SwapDirectory that is on your local machine.

2) Within SwapDirectory, you should create a sub-directory called "Recovery". This is where the AutoSaveSwap routine will make an initial save of any notebooks for which there is NO existing manual save location.

3) I have not designed an automatic dialog like you were hoping for for the front-end, but recovering any given notebook is easy. Simply evaluate


RecoverSwap["filePath"]
where "filePath" is a string representing the filePath of the MANUALLY-SAVED copy of the file (i.e., not the file that was created by AutoSave). This will then pop up a window containing the most recent auto-saved version of the file. The manually saved version is NEVER overwritten, unless you explicitly choose to do so. Once the recovered version pops up, you can save it whereever you like, or discard it at your discretion.

4) You should probably add this code to the KERNEL version of init.m ($UserBaseDirectory/Kernel/init.m) rather than the frontend version... this way, if you quit and restart the kernel, the autosave feature will also restart. On the other hand, this means that you must evaluate at least one expression after each start or restart to begin auto-saving. Once this initial evaluation is done, you do NOT need to have evaluated a cell for it to be backed up (unlike the built-in autosave utility).

Hope this helps someone! Feel free to respond with any questions, suggestions, or requests for improvement you may have. And, if you find this post useful, upvotes would be most appeciated! Take care.


$SwapDirectory= "C:\\Users\\pacoj\\Swap Files\\"; 
SaveSwap[nb_NotebookObject]:=Module[
    {fileName, swapFileName, nbout, nbdir, nbdirout, recoveryDir},
    If[ ! SameQ[Quiet[NotebookFileName[nb]], $Failed],
    (* if the notebook is already saved to the file system *)
        fileName = Last[ FileNameSplit[ NotebookFileName[nb]] ];
        swapFileName = fileName <> ".swp";
        nbdir = Rest[FileNameSplit @ NotebookDirectory[nb]];
        nbdirout= FileNameJoin[ FileNameSplit[$SwapDirectory]~Join~nbdir]<>"\\";
        If[!DirectoryQ[nbdirout], CreateDirectory[nbdirout]];
        nbout = NotebookGet[nb];
        Put[nbout, nbdirout <> swapFileName],
        (* else, if the file has never been saved, save as untitled *)
        recoveryDir= $SwapDirectory <> "Recovery\\";
        fileName= ("WindowTitle" /. NotebookInformation[nb])<>".nb";
        NotebookSave[nb, recoveryDir <> fileName]
    ] 
]; 
RecoverSwap::noswp= "swap file 1 not found in expected location";
    RecoverSwap[nbfilename_String]:=Module[
    {fileName, swapFileName, nbin, nbdir, nbdirout},
    fileName= Last[ FileNameSplit[ nbfilename] ];
    swapFileName= fileName <> ".swp";
    nbdir= Most[ Rest[FileNameSplit @ nbfilename] ];
    nbdirout= FileNameJoin[ FileNameSplit[$SwapDirectory]~Join~nbdir]<>"\\";
    If[ FileNames[swapFileName, {nbdirout}] == {},
       Message[RecoverSwap::noswp,nbdirout <> swapFileName]; Return[],
       nbin= Get[nbdirout <> swapFileName]; NotebookPut[nbin]
    ] 
]; 
AutoSaveSwaps= CreateScheduledTask[
    SaveSwap /@ Select[Notebooks[], "ModifiedInMemory" /. NotebookInformation[#]&],
    300 
] 
StartScheduledTask[AutoSaveSwaps] 

$\endgroup$
1
  • $\begingroup$ There seems to be an interesting quirk with this on Mac. I found a copy of my entire Mathematica application in the Swap folder, ".../SwapFolder/Applications/Mathematica". However, the original application is untouched. And I can already confirm that this saved me over an hour of work when Mathematica crashed the same day I implemented this. Many thanks! $\endgroup$ Commented Feb 4, 2015 at 17:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.