reddit / emacs

I'm looking for simple bookmarks but with robust link destination definitions

publicvoit · 2022-02-02 14:03
Hi, It was until last year that I've switched from "keeping frequently used link targets on top of each Orgdown file" to "using [bookmark.el](https://www.emacswiki.org/emacs/BookMarks#bookmark) to store and retrieve frequently used headings". Unfortunately, bookmark.el does use **bookmark definitions that do often break** when the absolute position within an Orgdown file is changed. That happens mostly when I add a substantial number of lines before the bookmark position. When I did get it correctly, this is because its absolute position is changed and the bookmark points to a wrong spot because the context-strings of the definition files can't help any more to fix the exact position. There are things like [bookmark+](https://www.emacswiki.org/emacs/BookmarkPlus) which extend the functionality and versatility. I don't know if they do use a different and more robust bookmark definition. I'm really only using `C-x r m` to set a bookmark at the current location and `C-x r b` to jump to a bookmark. I'm not planning of using more features than this in the future. Hence: **if I'm just looking for that reduced use-cases but with robust bookmark definitions: where should I look?** Update: I think I need to explain why "search" is not equivalent to "bookmarks/favorites". With bookmarks, I deliberately choose a very small sub-set of Orgdown headings I visit frequently. Currently, I do have around 100 bookmarks and almost 30.000 headings in total. With this bookmark selection, I just have to type in enough characters to be unique among 100 entries. If I choose search, I would have to type in much more characters and maybe I'm still not unique enough so that I get the jump target I'm looking for many times a day. As a direct consequence, IDs alone do not solve that issue as long as there is no functionality to search only within a subset of IDs. If there is no bookmark add-on or replacement that is able to handle robust links (with or without IDs, whatever), I have to live with constantly broken bookmarks or switch back to the list of ID-links on top of each Orgdown file, which is much less efficient as you can imagine. **Solved**: see [https://www.reddit.com/r/emacs/comments/siphk3/comment/hvgx4bg/?utm\_source=reddit&utm\_medium=web2x&context=3](https://www.reddit.com/r/emacs/comments/siphk3/comment/hvgx4bg/?utm_source=reddit&utm_medium=web2x&context=3) and my comment on it [https://www.reddit.com/r/emacs/comments/siphk3/comment/hzcr3uh/?utm\_source=reddit&utm\_medium=web2x&context=3](https://www.reddit.com/r/emacs/comments/siphk3/comment/hzcr3uh/?utm_source=reddit&utm_medium=web2x&context=3)
rguy84 · 2022-02-02 14:57
If you are only talking about org, there is functionality built-in. If you use or want to use helm, there's `helm-org-rifle`, that has some functionality that can help. I have things in a few org files, which I usually have open, so I just type in keywords and I am to my headline.
publicvoit · 2022-02-02 15:33
I see what you're proposing. I do search quite frequently. Unfortunately, this is not what I want here. Using search, my search space is the current file or all agenda files (I don't use anything else). This is quite large in my cases. Therefore, I'd like to keep a small set of manually curated target headings as bookmarks where the search space is very limited. This requires me to type in only very few characters until I limited the search result to my target in question. And yes, I'm talking about Org only. What is the bookmark functionality you're referring?
[deleted] · 2022-02-02 16:00
[deleted]
gmfawcett · 2022-02-02 16:20
What about adding custom IDs on your headings? That's how I keep robust links, but maybe it doesn't help in your case. https://orgmode.org/manual/Handling-Links.html
publicvoit · 2022-02-02 16:36
I am using custom IDs but this doesn't solve the bookmarking and bookmark retrieval workflow as long as there is no "this is a list of manually selected IDs which I want to jump to" functionality I'm not aware of yet.
rguy84 · 2022-02-02 17:18
Just saw your username, so I assume know about `org-goto`, but that probably won't help. some time ago, I found a function that automatically creates an UUID with a capture, so i am wondering if you can hack it to use a UUID vs location.
[deleted] · 2022-02-02 17:29
I am going to [leave this here.](https://braintool.org/) I have no clue if it helps with this too much though.
gmfawcett · 2022-02-02 19:11
Got it. That's a shame. I'm not a bookmark user, most of my so-called bookmarks are in org files. I know nothing about `bookmark.el`, so I am speaking really generally (i.e, ignorantly!). Design-wise it would be nice if `bookmark` could query the target buffer at bookmark creation time, find its major mode, and have a mode-specific generator function be called. So `org-bookmark-creation-hook` could return a custom-ID bookmark.
_viz_ · 2022-02-03 02:39
If all you wish for is a robust bookmark definition, then write one yourself? Bookmark definitions are sufficiently flexible enough to not worry about details like these. You can use a non-default bookmark-make-record-function to add any arbitrary data to the record, and you can add a 'handler' key to the record to jump to the definition as you wish.
publicvoit · 2022-02-03 08:31
For that, I should have understood how to read elisp code, modify and test it in a much better fashion.
oantolin · 2022-02-03 20:46
Hi Karl! Are the links produced by `org-store-link` robust enough for you? If so, it's pretty easy to teach `bookmark.el` to use Org links when bookmarking. I wrote some code for this purpose: (defun handle-org-bookmark (bookmark) "Handle bookmarks which have Org links." (org-link-open-from-string (alist-get 'org-link bookmark))) (defun bookmark-org-link-to-here () "Bookmark the org link that `org-store-link' would make." (interactive) (when-let ((link (substring-no-properties (org-store-link nil)))) `(,(when (string-match org-link-bracket-re link) (match-string-no-properties 2 link)) (org-link . ,link) (handler . handle-org-bookmark) (position . ,(point)) ,@(when buffer-file-name `((filename . ,(abbreviate-file-name buffer-file-name))))))) (defun use-org-link-for-bookmarks () "Configure bookmarks to current buffer to use Org links." (interactive) (setq-local bookmark-make-record-function #'bookmark-org-link-to-here)) (add-hook 'org-mode-hook #'use-org-link-for-bookmarks) The way this works is that `C-x r m` uses the function stored in the variable `bookmark-make-record-function` to create the bookmarks it stores. The created bookmarks can specify arbitrary extra data including what function `C-x r b` should use to jump to that bookmark, called a handler. So here, when you use the `use-org-link-for-bookmarks` command in a particular buffer, it will set the `bookmark-make-record-function` locally in that buffer to `bookmark-org-link-to-here` which includes some of normal data that bookmarks use (filename when visiting a file, point position) and additionally stores (1) an Org link obtained from `org-store-link`, and (2) the information that this bookmark should be handled by `handle-org-bookmark` (a function which uses `org-link-open-from-string` on the stored link). The last line adds a hook so that any Org mode buffer you open after wards will use this enhanced bookmarking. If you want it available in any buffers you already have open, just use `M-x use-org-link-for-bookmarks` in those buffers. Note that this doesn't just make it possible to robustly link to Org file headings, but also to any location where `org-store-link` works.
publicvoit · 2022-02-03 21:20
This is brilliant. I'll try to apply this in the next days. Most probably I'll mix it with my `my-id-get-or-generate()` from [my config](https://github.com/novoid/dot-emacs/blob/master/config.org) that generates a human-readable slug in any case.
publicvoit · 2022-03-04 19:24
Thanks again for your snippet. I found some time playing around and pimping it a bit. You can find my `my-handle-org-bookmark` on [https://github.com/novoid/dot-emacs/blob/master/config.org](https://github.com/novoid/dot-emacs/blob/master/config.org) I found out that `org-link-open-from-string` is much faster from within the buffer containing the link target. So I added a `find-file`. Furthermore, I do have a nice function to generate human-readable ID properties: `my-id-get-or-generate`. By simply calling that in the bookmark function makes sure that the current heading does have an ID and thus use that for the bookmark. You have improved my daily Org-mode life for a significant amount with your snippet!
oantolin · 2022-03-04 19:30
Great! I'm glad the basic idea solved your problem and it's good that you automated the ID creation. (And the bit about opening the file first making `org-link-open-from-string` faster is funny, it sounds like a performance bug in Org.)
publicvoit · 2022-03-05 11:36
Something weird is going on since I activated the change. It seems to be the case that my `my-id-get-or-generate` is called probably each minute, causing an ID generated (of not already found) of the current heading. Since I only changed that part of my configuration, I suspect that `bookmark-org-link-to-here` is periodically called where I added my function. I do have a long and maybe complex configuration. I just removed the two functions and the hook from my config and the behavior is gone. Do you have any idea about that? What might be a candidate to call this function that often in the background?
oantolin · 2022-03-05 23:51
That's weird! It shouldn't be happening: the bookmark creation function should only be called when you set a bookmark. I'd suggest instrumenting `my-id-get-or-generate` to find out how it is getting called: `M-x debug-on-entry RET my-id-get-or-generate RET`. That way the next time is called you'll be sent to the debugger and you can see which function called it. To cancel the instrumentation you use `M-x cancel-debug-on-entry`.
publicvoit · 2022-03-06 09:59
Stupid me, I should have known myself to use the all-mighty `debug-on-entry` process. It revealed that my recent addition of [https://github.com/alphapapa/dogears.el](https://github.com/alphapapa/dogears.el) by alphapapa is using the bookmark subsystem. I [started a discussion on dogears by asking alphapapa if it is possible to let the bookmark function know that it is invoked by dogears to omit the generating of the ID](https://github.com/alphapapa/dogears.el/issues/13). Thank you!
oantolin · 2022-03-06 16:39
You know, if the dogears problem cannot be easily solved, what you could do instead is: Add a variable to control whether or not to generate IDs: (defvar should-generate-id nil) Modify the `my-bookmark-org-link-to-here` to check the variable first, so replace the call to `my-id-get-or-generate` with: (when should-generate-id (my-id-get-or-generate)) Next, write a little wrapper around `bookmark-set` that you will use in Org Mode buffers: (defun my-bookmark-set-with-id () (interactive) (let ((should-generate-id t)) (call-interactively #'bookmark-set))) And bind that to whatever key you normally use for `bookmark-set` in Org mode buffers: (with-eval-after-load 'org (define-key org-mode-map (kbd "C-x r m") #'my-bookmark-set-with-id))