12

Sometimes when working on larger pieces of code or on a larger package I really miss the option to bookmark the current line/position in the code.

Since the front-end is quite extendable my question is: How could one implement bookmarks in the fronted when editing a package (.m) file?

So the requirements are that a short cut (e.g. Ctrl-Alt-Numpad 1) would set the bookmark and another short cut (e.g. Ctrl-Numpad 1) would move the cursor to the bookmark.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
Ajasja
  • 13,634
  • 2
  • 46
  • 104
  • One of the possible ways I was thinking about is to insert a marker string (eg (* ::Bookmarks::1:: *) ) at the current cursor position and then somehow find the string and move the cursor there again. But of course I'd except any answer that fulfils the bookmar requirements. – Ajasja May 11 '12 at 14:24
  • 2
    Not what you have been asking for, but you can do this in Workbench. Seen that WB has other benefits for code development, perhaps this is an option. –  May 11 '12 at 14:28
  • @ruebenko Yes, I know, I'm trying to see if I can put off using WB for now. (At least until I have to start writing documentation and unit tests) – Ajasja May 11 '12 at 14:31
  • I think the best solution is to use cell tags. Use the menu item "Add/Remove Cell Tags" from the Cell menu or the cell's context menu, and give it a descriptive name. To find it again, use "Find Bookmark". I guess you could bind those actions to keys as well. – celtschk May 11 '12 at 14:35
  • 2
    The problem is that the fixed "line of code" is not a good notion for the FrontEnd. You can associate a bookmark with a given cell (by using Cell tags, for instance), but I would not try to do that with, say, 10-th (or whatever) line of code. – Leonid Shifrin May 11 '12 at 14:35
  • To second what Leonid said, the parser has no definition of what a line is. This can make for interesting (and useless, IMO) error messages. – rcollyer May 11 '12 at 14:38
  • @LeonidShifrin But if one is editing a package (.m file) then the notion of a line is well (or at least better) defined. – Ajasja May 11 '12 at 14:38
  • 1
    It is possible to create a hyperlink to a cell, it seems (check some links in the docs), but not to a certain position within a cell. Is a link to a cell 'good enough' for you? – Szabolcs May 11 '12 at 14:41
  • @Szabolcs No, I'd prefer a specific position inside the cell. – Ajasja May 11 '12 at 14:42
  • @celtschk Unless I'm doing something wrong it appears that tags are not saved inside a .m file – Ajasja May 11 '12 at 14:43
  • Better, but still not so well - this is a property of the language. Mathematica is an expression-based language, and as such, has some impedance mismatch with the line numbers. I expressed my thoughts on that in more detail here – Leonid Shifrin May 11 '12 at 14:44
  • @Ajasja I'm afraid you might be out of luck. The problem is: how can we keep the bookmark anchored on a fixed position inside the cell when the cell is being edited? It is possible to attach extra info to a cell, but I'm not sure how robust this could be with parts of a cell. (The debugger does do something like this, so there might be a way...) What if the expression used as anchor gets deleted during editing? (I'm just thinking aloud...) – Szabolcs May 11 '12 at 14:46
  • @Szabolcs You can also bookmark to a given position within a cell - using the same set of functions I was using for my real-time code highlighting engine. It is another question how useful this will be. – Leonid Shifrin May 11 '12 at 14:46
  • 1
    @Szabolcs You can insert a comment (* BOOKMARK *) and then just find it again. I don't mind if such comments are visible. The front end already uses special comment tags in packages, for example (* ::Code::Bold:: *). This is where I got my original idea from. – Ajasja May 11 '12 at 14:52
  • @LeonidShifrin Well Developer`CellInformation certanly seems useful, but when I tried it it just returns $Failed (This is what I tried DeveloperCellInformation[EvaluationNotebook[]]`) – Ajasja May 11 '12 at 14:58
  • Upon reflecting a bit, I really think that general notebooks are a bad match for bookmarking - they are too dynamic for that. Chances are that you will constantly find dead links because cells were deleted, moved, changed, etc. This may be different if you impose stronger restrictions on what can be done with your cells, but this means some additional interface/tools, through which you will then be working with such notebooks. So, bookmarking can IMO exist only as a part of some larger infrastructure developed for some more specific set of tasks. – Leonid Shifrin May 11 '12 at 14:58
  • Sometimes it indeed returns $Failed. I wasn't able to fully understand what are these conditions. I was able to make it work reliably for code cells ("Program" style text cells), which I use for the highlighter. I am actually thinking of switching to those also for my Mathematica coding - I just have to generate a highlighter for Mathematica language, and add semantic highlighting module. No time for that so far, hopefully soon... – Leonid Shifrin May 11 '12 at 15:01
  • @LeonidShifrin Well I think for plain text files (eg .m) A bookmark is an extremely useful tool. – Ajasja May 11 '12 at 15:04
  • No question about that. But notebooks are fundamentally not plain text files, being themselves Mathematica expressions. – Leonid Shifrin May 11 '12 at 15:07
  • @Ajasja: Ah, I overlooked that detail with the .m file. Possibly because I don't usually edit .m filed with Mathematica, but either create them as autosave packages from regular notebooks or edit them with XEmacs. – celtschk May 11 '12 at 15:24

1 Answers1

5

This answer implements Ajasja's suggestion from the comments to use comments (e.g., (* ::BOOKMARK::7:: *) ) as bookmarks and simply finds them with NotebookFind.

The following code (when inserted into KeyEventTranslations.tr) binds Ctrl-Alt-Numpad 1 to creating a (sequentially numbered) bookmark comment at the cursor location and Ctrl-Numpad 1 to cycling through the bookmark comments.

One could also modify this code to bind a number of named bookmarks to specific shortcuts.

Item[KeyEvent["Keypad1", Modifiers -> {Control, Command}],
    FrontEndExecute[{
        NotebookWrite[InputNotebook[], " (* ::BOOKMARK::" <> 
            Block[{Inherited = 1}, 
                ToString[Increment[CurrentValue[InputNotebook[], {TaggingRules, 
                "BookmarkCounter"}]]]] <> ":: *) " ]
    }],
    MenuEvaluator->Automatic
],

Item[KeyEvent["Keypad1", Modifiers -> {Control}],
    FrontEndExecute[{
        FrontEnd`NotebookFind[FrontEnd`InputNotebook[], "(* ::BOOKMARK:"]
    }]
], 
dws
  • 801
  • 8
  • 9