After reading some of the comments, I thought I'd post this solution I had done some years ago. It does not work through the Bookmarks. As noted, that requires converting things like FE`a$$712
to $CellContext`a$$
-- someone may know how to do that easily. I suspect it could be done.
The code below accomplishes the same intention as the OP. It saves the current state in a cell, and it can read the cell when the Manipulate is reevaluated. The cell is identified by a tag. If it doesn't exist, one is created at the current insertion point when the "Save" button is clicked.
Drawbacks: You have to define what a state is in the code -- in the example, it's {a, b}
, which appears in both the save and reset button/menu actions. That can be inconvenient if in development you add and subtract a lot of variables. One also might wish the cell with the bookmarks was hidden.
SelectCellWithTag[tag_] :=
If[NotebookFind[EvaluationNotebook[], tag, Next, CellTags,
AutoScroll -> False] =!= $Failed,
SelectionMove[EvaluationNotebook[], All, CellContents,
AutoScroll -> False],
SelectionMove[EvaluationNotebook[], After, Cell,
AutoScroll -> False];
NotebookWrite[EvaluationNotebook[],
Cell[BoxData["{}"], "Input", CellTags -> {tag},
ShowCellTags -> True],
All, AutoScroll -> False];
SelectionMove[EvaluationNotebook[], All, CellContents,
AutoScroll -> False]
];
ReadCellContents[] := ToExpression@NotebookRead[EvaluationNotebook[]];
Manipulate[
a + b,
{a, 0, 1}, {b, 0, 1},
{{save, SelectCellWithTag["BOOKMARKS"]; ReadCellContents[]},
Button["Save", SelectCellWithTag["BOOKMARKS"];
NotebookWrite[EvaluationNotebook[],
ToBoxes[save = Append[ReadCellContents[], {a, b}]],
AutoScroll -> False]] & },
{reset, ActionMenu["Reset", (#1 :> ({a, b} = #1) & ) /@ save,
Appearance -> "PopupMenu"] & },
SaveDefinitions -> True
]
Addendum
Combining an idea from @Ajasja with the above, the following perhaps does the trick using bookmarks:
SelectCellWithTag[tag_] :=
If[NotebookFind[EvaluationNotebook[], tag, Next, CellTags,
AutoScroll -> False] =!= $Failed,
SelectionMove[EvaluationNotebook[], All, CellContents,
AutoScroll -> False],
SelectionMove[EvaluationNotebook[], After, Cell,
AutoScroll -> False];
NotebookWrite[EvaluationNotebook[],
Cell[BoxData@ToBoxes[ExportString[{}, "Package"]], "Input",
CellTags -> {tag}, ShowCellTags -> True], All,
AutoScroll -> False];
SelectionMove[EvaluationNotebook[], All, CellContents,
AutoScroll -> False]];
ReadCellContents[] := ToExpression@NotebookRead[EvaluationNotebook[]];
Manipulate[a + b, {a, 0, 1}, {b, 0, 1},
Button["Save bookmarks", SelectCellWithTag["BOOKMARKS"];
NotebookWrite[EvaluationNotebook[],
ToBoxes[StringReplace[
ExportString[Typeset`bookmarkList$$, "Package"],
Shortest["FE`" ~~ v : ___ ~~ "$$"] ~~ DigitCharacter ... :> "$CellContext`" <> v <> "$$"]],
AutoScroll -> False]],
Button["Restore bookmarks", SelectCellWithTag["BOOKMARKS"];
Typeset`bookmarkList$$ = ImportString@ReadCellContents[]],
Initialization :> (SelectCellWithTag["BOOKMARKS"];
Typeset`bookmarkList$$ = ImportString@ReadCellContents[]),
SaveDefinitions -> True]
I think if you change your variables during development, even bookmarks may become invalid.
Edits: 1. Added button as asked in comment. 2. Improved the StringReplace
pattern after suggestion by @iztok.
InputForm
and see how the manually added bookmarks ended up asBookmarks
option of theManipulate
$\endgroup$Typeset`bookmarkList$$
. But I'm not sure how to get at the context, since Manipulate does some slight of hand with variable localizations... $\endgroup$Cases["the manipulate", (Bookmarks->b_)->b, Infinity]
$\endgroup$Bookmarks
mechanism. The real-life use case is that many people will be using a complex manipulate notebook for some experiential analysis. And will probably not appreciate there bookmarks list being deleted on each redeploy (the redeploys will be frequent at the beginning:) $\endgroup$