org-randomnote
org-randomnote copied to clipboard
Suggestion
Hi,
I ran across this package the other day and have a small suggestion. You currently use org-map-entries
with line-number-at-pos
, which is convenient, but slow, as it has to map across every entry in the file, whether it will be used or not.
Instead, you can use a simpler algorithm within a file which will be much faster, like this:
(defun ap/org-random-heading (top-level)
"Go to random heading in current buffer."
(interactive "P")
(goto-char (random (buffer-size)))
(if (org-before-first-heading-p)
(outline-next-heading)
(org-back-to-heading)
(when top-level
(cl-loop until (not (org-up-heading-safe))))))
And with a prefix arg, you can make it go to only top-level headings.
Wonderful! Would you like to submit a PR with this change?
No, thank you, because I just use this function directly from my own config. :) Just thought I'd share it in case you find it useful.
Question - wouldn't this implementation have the downside of making the function less random, in that headings with larger content would be more likely to come up?
I hadn't thought of that. I suppose you're right. Good catch. Of course, in most cases, the performance difference probably doesn't matter. In larger files (e.g. I have a large one with 1800+ headings), it might be preferable. So I guess it depends on how big your files are and how much of a probability purist you are, haha. ;)
BTW, another approach, which would be slower than this but faster than org-map-entries
, and which shouldn't be biased toward large entries, would be to do a regexp search through the file looking for lines starting with *
, collect the positions, and choose a random one. Something like:
(defun org-random-entry ()
(interactive)
(widen)
(goto-char (point-min))
(cl-loop while (re-search-forward (rx bol "* ") nil t)
collect (point) into positions
finally do (progn
(goto-char (seq-random-elt positions))
(org-reveal))))
Thank you! I am very open to this implementation change. Is there a way to profile the default implementation vs this alternate implementation? If someone sends that and a PR I will accept it.
On Sun, Nov 18, 2018 at 8:56 PM alphapapa [email protected] wrote:
BTW, another approach, which would be slower than this but faster than org-map-entries, and which shouldn't be biased toward large entries, would be to do a regexp search through the file looking for lines starting with * , collect the positions, and choose a random one. Something like:
(defun org-random-entry () (interactive) (widen) (goto-char (point-min)) (cl-loop while (re-search-forward (rx bol "* ") nil t) collect (point) into positions finally do (progn (goto-char (seq-random-elt positions)) (org-reveal))))
— You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/mwfogleman/org-randomnote/issues/4#issuecomment-439771761, or mute the thread https://github.com/notifications/unsubscribe-auth/ACuwIimh-1EFHijKq8051fgZJ1iLZJtRks5uwjn8gaJpZM4UkppU .
-- Tasshin Michael Fogleman Website https://www.tasshin.com/ | Hostwriting http://www.hostwriting.com/ | Mind Body Attention http://mindbodyattention.com/
See the bench-multi
macro at https://alphapapa.github.io/emacs-package-dev-handbook
As mentioned at https://github.com/melpa/melpa/pull/6603#issuecomment-569169666, here's an implementation that uses org-ql
. It's simple, fast, flexible, and should be evenly weighted:
(cl-defun org-goto-random-heading (&key (buffers (list (current-buffer)))
regexp)
(let* ((entries (org-ql-select buffers
`(regexp ,regexp)
:action '(cons (current-buffer) (point))))
(entry (seq-random-elt entries)))
(pop-to-buffer (car entry))
(goto-char (cdr entry))))
Use it like:
(org-goto-random-heading :buffers "~/org/main.org" :regexp "Emacs")