This is an open thread for any sort of tips and tricks we have accumulated for org, org-roam or any other things related to our favourite life planning software!
I might as well start it off
(defadvice! yeet/org-roam-in-own-workspace-a (&rest _) "Open all roam buffers in there own workspace." :before #'org-roam-node-find :before #'org-roam-node-random :before #'org-roam-buffer-display-dedicated :before #'org-roam-buffer-toggle (when (featurep! :ui workspaces) (+workspace-switch "*roam*" t)))
this piece of advice switches to a dedicated roam workspace before opening any roam buffer, it saves me littering org roam buffers all over my workspaces, though this may not be for everyone.
A little function I found browsing someone’s dotfiles.
;; a useful function I took from (https://github.com/SqrtMinusOne/dotfiles/blob/4b176a5bb1a5e20a7fdd7398b74df79701267a7e/.emacs.d/init.el) (defun kev/org-link-copy (&optional arg) "Extract URL from org-mode link and add it to kill ring." (interactive "P") (let* ((link (org-element-lineage (org-element-context) '(link) t)) (type (org-element-property :type link)) (url (org-element-property :path link)) (url (concat type ":" url))) (kill-new url) (message (concat "Copied URL: " url))))
- Create a heading like below
* Snippets :PROPERTIES: :header-args:snippet: :mkdirp yes :tangle (expand-file-name (downcase (elt (org-get-outline-path t) (- (length (org-get-outline-path t)) 1))) (expand-file-name (downcase (elt (org-get-outline-path t) 1)) "snippets")) :END:
- Create a hook
(add-hook! 'org-babel-pre-tangle-hook (when (file-directory-p "snippets") (require 'async) (async-start (lambda () (delete-directory "snippets" t (not (null delete-by-moving-to-trash)))) (lambda (result) (print! "Delete snippets dir got: " result)))))
Then, under the “Snippets” heading a structure like
org-roam I use manual alphanumeric IDs instead of the traditional Timestamp. In this case, I prefer that my links show the ID as part of the description to point me out the note’s address directly in the text. Something like this:
[[id:2a1b][2a1b My great note]]
I had to modify two functions to create the behavior.
org-roam-node-insert-id I changed the
(concat id " " description)
(defun maikol/org-roam-node-insert-id (&optional filter-fn &key templates info) "Find an Org-roam node and insert (where the point is) an \"id:\" link to it. FILTER-FN is a function to filter out nodes: it takes an `org-roam-node', and when nil is returned the node will be filtered out. The TEMPLATES, if provided, override the list of capture templates (see `org-roam-capture-'.) The INFO, if provided, is passed to the underlying `org-roam-capture-'." (interactive) (unwind-protect ;; Group functions together to avoid inconsistent state on quit (atomic-change-group (let* (region-text beg end (_ (when (region-active-p) (setq beg (set-marker (make-marker) (region-beginning))) (setq end (set-marker (make-marker) (region-end))) (setq region-text (org-link-display-format (buffer-substring-no-properties beg end))))) (node (org-roam-node-read region-text filter-fn)) (description (or region-text (org-roam-node-formatted node)))) (if (org-roam-node-id node) (progn (when region-text (delete-region beg end) (set-marker beg nil) (set-marker end nil)) (let* ((id (org-roam-node-id node)) (description (concat id " " description))) (insert (org-link-make-string (concat "id:" id) description)) (run-hook-with-args 'org-roam-post-node-insert-hook id description))) (org-roam-capture- :node node :info info :templates templates :props (append (when (and beg end) (list :region (cons beg end))) (list :link-description description :finalize 'insert-link)))))) (deactivate-mark)))
org-roam-link-replace-at-point-id I added a
(concat (org-roam-node-id node)). This function is triggered every time
org-roam replaces a
(defun maikol/org-roam-link-replace-at-point-id (&optional link) "Replace \"roam:\" LINK at point with an \"id:\" link." (save-excursion (save-match-data (let* ((link (or link (org-element-context))) (type (org-element-property :type link)) (path (org-element-property :path link)) (desc (and (org-element-property :contents-begin link) (org-element-property :contents-end link) (buffer-substring-no-properties (org-element-property :contents-begin link) (org-element-property :contents-end link)))) node) (goto-char (org-element-property :begin link)) (when (and (org-in-regexp org-link-any-re 1) (string-equal type "roam") (setq node (save-match-data (org-roam-node-from-title-or-alias path)))) (replace-match (org-link-make-string (concat "id:" (org-roam-node-id node)) (concat (org-roam-node-id node) " " (or desc path)))))))))
Finally, I have those to make them the default functions,
(advice-add #'org-roam-node-insert :override #'maikol/org-roam-node-insert-id) (advice-add #'org-roam-link-replace-at-point :override #'maikol/org-roam-link-replace-at-point-id)
This one is probably obvious to anyone who has used org mode beyond a beginner level, but I’ll still highlight a lil’ something called
Takes a link you have in your clipboard, then inserts it as an org link with the description being the URL’s title.
Very useful if you find materials for your project and want to put them into your document quickly. Eliminates the step of having to describe your link.
oh my lord I have been doing this manually for so long
I recently added something similar to that to my config for files.
(defun +org-insert-file-link () "Insert a file link. At the prompt, enter the filename." (interactive) (insert (format "[[%s]]" (org-link-complete-file)))) (map! :after org :map org-mode-map :localleader "l f" #'+org-insert-file-link)
This is very useful, thanks