9
$\begingroup$

When I open a Mathematica file it goes to the beginning of the notebook, but I have a big Mathematica (ver. 11) file with many "input" and "output" cells, and I want to go back to the location in the notebook at the time when the notebook was closed. Is there any solution for that. For instance in Adobe acrobat there is such an option where if you check that option, then the next time you open a PDF file, it goes directly to the same page where you were before you close it.

Thanks!

$\endgroup$
  • $\begingroup$ There is "Navigate/Last Edit location" (Ctrl Q) in Eclipse (Wolfram Workbench). I find Wolfram Workbench much faster to navigate large Mathematica files than the notebook FrontEnd. E.g. 1500 lines need a second in the FrontEnd to parse and open, but nearly no time in Eclipse. $\endgroup$ – Rolf Mertig Jun 4 '18 at 9:14
  • $\begingroup$ True, Eclipse is far superior to notebooks for code. However, notebooks to offer a lot of functionality that Eclipse doesn't and sometimes you don't escape the need for them, especially for the purposes of reporting results. $\endgroup$ – Sjoerd Smit Jun 4 '18 at 10:19
  • $\begingroup$ @SjoerdSmit You can have .nb files in Eclipse, too. And just run the .m files from .nb and get all kind of reporting. But for editing (and that is the issue here) I truly think that an IDE like Eclipse or IntelliJ is just far superior. $\endgroup$ – Rolf Mertig Jun 4 '18 at 11:52
  • $\begingroup$ I'm not quite sure what you mean by that. Yes, you can have a notebook open in Eclipse, but it will be just plain text without any form of interactivity and you'll be looking at the raw cell and box forms of whatever's in the notebook. Not many people are going to be comfortable with that. If you use notebooks as a document (where the code is interspersed with section headings and text), Eclipse is only useful for editing the code in your package files. The notebook that contains the actual story behind the code can still be large. $\endgroup$ – Sjoerd Smit Jun 4 '18 at 14:54
4
$\begingroup$

You can make use of the notebook options NotebookEventActions and NotebookDynamicExpression to do this. The idea is to store the ExpressionUUID of the selected cell into the notebook tagging rules option when the notebook is closed. If the cursor is between cells, then use either the next cell if it exists, or the previous cell otherwise. Then, when the notebook is opened, move the cursor to the cell with the stored ExpressionUUID. One downside is that since this depends on NotebookDynamicExpression, you will get the Enable Dynamics popup.

At any rate, here is a NotebookEventActions option that stores the ExpressionUUID:

NotebookEventActions -> {
    "WindowClose" :> With[{nb = EvaluationNotebook[]},
        CurrentValue[nb, {TaggingRules, "LastCell"}] = CurrentValue[
            Replace[SelectedCells[nb],
                {} :> (
                    SelectionMove[nb, Next, Cell];
                    Replace[
                        SelectedCells[nb],
                        {} :> (
                            SelectionMove[nb, Previous, Cell];
                            SelectedCells[nb]
                        )
                    ]
                )
            ],
            ExpressionUUID
        ]
    ]
}

And, here is a NotebookDynamicExpression option that moves the cursor to the stored ExpressionUUID:

NotebookDynamicExpression :> With[
    {uu = CurrentValue[EvaluationNotebook[], {TaggingRules, "LastCell"}]},
    Pause[.1];
    SelectionMove[
        First @ Cells[ExpressionUUID -> uu],
        All,
        CellContents
    ]
]

I included a Pause[.1] wait. Without this pause, I think the SelectionMove request happens before the front end is ready.

You will also note that I always select the contents of the desired cell. With more work, it is possible to record the position of the cursor in more detail, and also to restore the cursor to its original state, even if that original state were between cells, in the middle of a cell etc.

For visualization purposes, I create a notebook below with the needed options, and with some preexisting cells. I executed the following code, and saved the resulting notebook as temp.nb:

CreateDocument[
    {
    ExpressionCell[Defer@Defer[Dynamic][CurrentValue[Cells[],ExpressionUUID]],"Input"],
    ExpressionCell[Dynamic[CurrentValue[Cells[],ExpressionUUID]],"Output"],
    ExpressionCell[Defer[1+1],"Input"],
    ExpressionCell[1+1,"Output"],
    ExpressionCell[Defer[AbsoluteCurrentValue[WindowTitle]],"Input"],
    ExpressionCell[Dynamic@AbsoluteCurrentValue[WindowTitle],"Output"]
    },

    WindowMargins->{{0,Automatic},{Automatic,0}},
    WindowSize->{500,500},
    NotebookEventActions -> {
        "WindowClose" :> With[{nb = EvaluationNotebook[]},
            CurrentValue[nb, {TaggingRules, "LastCell"}] = CurrentValue[
                Replace[SelectedCells[nb],
                    {} :> (
                        SelectionMove[nb, Next, Cell];
                        Replace[
                            SelectedCells[nb],
                            {} :> (
                                SelectionMove[nb, Previous, Cell];
                                SelectedCells[nb]
                            )
                        ]
                    )
                ],
                ExpressionUUID
            ]
        ]
    },
    NotebookDynamicExpression :> With[
        {uu = CurrentValue[EvaluationNotebook[], {TaggingRules, "LastCell"}]},
        Pause[.1];
        SelectionMove[
            First @ Cells[ExpressionUUID -> uu],
            All,
            CellContents
        ]
    ]
];

An animation of saving and opening the above notebook after moving the cursor follows:

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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