For a long time I wanted to add a thing similar to what’s known to anyone who ever used lsp-mode in Emacs with lenses feature enabled. lsp-mode can show number of references for any given function.
I wanted a similar thing in Org-Roam - to see number of backlinks next to a heading.
Finally, I’ve got to figure that out. I borrowed the initial implementation of the idea from here: My Doom Emacs configurations · Hieu Phay
Although there, the author doing something similar, yet not the exact thing - they are displaying number of references (backlinks) next to each link. I wanted to see the numbers for headings.
Another departure from the original implementation - instead of using (org-element-map)
, I decided to use regex-based approach - org-element-map has to scan the entire buffer and could be costly, regex should be much faster. Too bad there isn’t yet solid org-mode treesitter grammar - that would’ve even better.
Here’s the code:
(defface org-roam-count-overlay-face
'((t :inherit org-list-dt :height 0.6 :underline nil :weight light))
"Face for Org Roam count overlay.")
(defun org-roam--count-overlay-make (pos count)
(let* ((overlay-value (propertize
(format "│%d│ " count)
'face 'org-roam-count-overlay-face
'display '(raise 0.3)))
(ov (make-overlay pos pos (current-buffer) nil t)))
(overlay-put ov 'roam-backlinks-count count)
(overlay-put ov 'priority 1)
(overlay-put ov 'after-string overlay-value)))
(defun org-roam--count-overlay-remove-all ()
(dolist (ov (overlays-in (point-min) (point-max)))
(when (overlay-get ov 'roam-backlinks-count)
(delete-overlay ov))))
(defun org-roam--count-overlay-make-all ()
(save-excursion
(goto-char (point-min))
(org-roam--count-overlay-remove-all)
(while (re-search-forward "^\\(*+ \\)\\(.*$\\)\n\\(:properties:\\)\n\\(?:.*\n\\)*?:id:\\s-+\\([^[:space:]\n]+\\)" nil :no-error)
(when-let* ((pos (match-beginning 2))
(id (string-trim (substring-no-properties (match-string 4))))
(count (caar
(org-roam-db-query
[:select (funcall count source)
:from links
:where (= dest $s1)
:and (= type "id")]
id))))
(when (< 0 count)
(org-roam--count-overlay-make pos count))))))
;;;###autoload
(define-minor-mode org-roam-count-overlay-mode
"Display backlink count for org-roam links."
:after-hook
(if org-roam-count-overlay-mode
(progn
(org-roam--count-overlay-make-all)
(add-hook 'after-save-hook #'org-roam--count-overlay-make-all nil t))
(org-roam--count-overlay-remove-all)
(remove-hook 'after-save-hook #'org-roam--count-overlay-remove-all t)))
You may want to grab it directly from my config, most likely I won’t be updating it here every time I make changes.
Here’s a screenshot:
Note that I couldn’t figure out how to place the overlay at the end of the heading - it only works when the heading is not collapsed, so I had to add the at the front of the heading.
Hope someone finds this helpful.