16
$\begingroup$

I want to run some code automatically after saving my notebook. Is there a $ variable or setting for this?

$\endgroup$
0

2 Answers 2

21
$\begingroup$

Yes, it can be easily implemented with FrontEndExecute, e.g.:

SetOptions[EvaluationNotebook[], NotebookEventActions -> 
  {{"MenuCommand", "Save"} :> Print["HEY"], PassEventsDown -> True}];

You can insert any code instead of Print command


Edit

Above code executes Print["HEY"] before saving the notebook, because you catch the event at the beginning, do some work and release it back to program with PassEventsDown.

To evaluate some code after saving - one has to handle full event manually. The simplest would be just remove PassEventsDown and instead of Print["HEY"] write (NotebookSave[]; Print[123]):

SetOptions[EvaluationNotebook[], NotebookEventActions ->
    {{"MenuCommand", "Save"} :> (NotebookSave[]; Print[123])}]

Unfortunately, this will "intercept" also saving event triggered by "Save As" command and it will always save file with its old name even if we change name in "Save As" window.

$\endgroup$
3
  • 1
    $\begingroup$ @funnypony If you replace "HEY" with NotebookFileName[] and try to save notebook as file with different name, you'll get old file name, or $Failed if notebook was not saved before. So it seems that this code is evaluated before saving the notebook. Is there a way to really evaluate code after notebook was saved? $\endgroup$
    – jkuczm
    Commented Dec 7, 2014 at 17:04
  • 1
    $\begingroup$ @jkuczm yes it saves after Print just because you catch the event at the beginning, do some work and release it back to pogram with passeventsdown. To evaluate some code after saving - one has to handle full event manually. The simplest would be just remove passeventdown and instead Print[] write {NotebookSave[]; Print[123]} but! it will work only with saved notebooks, it can't handle SaveAs command.. Unfortunately, I don't know how to catch only SaveAs command.. $\endgroup$
    – funnyp0ny
    Commented Dec 8, 2014 at 13:48
  • $\begingroup$ @funnypony +1 I found your answer useful nonetheless. $\endgroup$
    – jkuczm
    Commented Dec 8, 2014 at 23:04
3
$\begingroup$

Adding to @funnypony's answer, if we really need to execute code after saving a notebook and we don't want to break "Save As" functionality, then we can use following workaround.

  1. In "Save" action use NotebookSave[] and code we want to execute after it.
  2. In "SaveRename" action put code assigning new "Save" notebook action. This new "Save" action will restore previous NotebookEventActions and pass events down.

Whole thing would look like this:

$notebookEventActions = {
{"MenuCommand", "Save"} :> (
    Print["before Save: ", NotebookFileName[], " last modified: ",
        FileDate@NotebookFileName[]];
    NotebookSave[];
    Print["after Save: ", NotebookFileName[], " last modified: ",
        FileDate@NotebookFileName[]]
),
{"MenuCommand", "SaveRename"} :> (
    SetOptions[
        EvaluationNotebook[],
        NotebookEventActions -> {
            {"MenuCommand", "Save"} :>
                SetOptions[
                    EvaluationNotebook[],
                    NotebookEventActions -> $notebookEventActions
                    ],
                PassEventsDown -> True
            }
        ];
        NotebookSave[Interactive -> True]
    )
};

SetOptions[EvaluationNotebook[], NotebookEventActions -> $notebookEventActions]

Now using "Save" command will print "before Save: ..." text, then save notebook, then print "after Save: " text. Using "Save As" will work as if it was not modified at all.

$\endgroup$

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.