(feat): formalize node dedicated buffers (#1622)

This adds the whole new section in `org-roam-mode.el` for node dedicated
buffers, with a new global command `org-roam-buffer-display-dedicated`,
which supersedes `org-roam-buffer` command.

Along the way this also refactors the code for the persistent buffers to
clean it up, make it more clear in what it does, improve its robustness,
and to make it play nice with the dedicated buffers.
This commit is contained in:
Wetlize
2021-07-23 14:19:30 +03:00
committed by GitHub
parent 8e89bad945
commit d1e3a5d9be
5 changed files with 153 additions and 98 deletions

View File

@ -447,19 +447,15 @@ Org-roam provides (see [[id:70083bfd-d1e3-42b9-bf83-5b05708791c0][Completion]]).
Org-roam provides the Org-roam buffer: an interface to view relationships with Org-roam provides the Org-roam buffer: an interface to view relationships with
other notes (backlinks, reference links, unlinked references etc.). There are other notes (backlinks, reference links, unlinked references etc.). There are
two main functions to use here: two main commands to use here:
- ~org-roam-buffer~: Launch an Org-roam buffer for the current node at point.
- ~org-roam-buffer-toggle~: Launch an Org-roam buffer that tracks the node - ~org-roam-buffer-toggle~: Launch an Org-roam buffer that tracks the node
currently at point. This means that the content of the buffer changes as the currently at point. This means that the content of the buffer changes as the
point is moved, if necessary. point is moved, if necessary.
- ~org-roam-buffer-display-dedicated~: Launch an Org-roam buffer for a specific
Use ~org-roam-buffer-toggle~ when you want wish for the Org-roam buffer to node without visiting its file. Unlike ~org-roam-buffer-toggle~ you can have
buffer, call ~M-x org-roam-buffer~. multiple such buffers and their content won't be automatically replaced with a
new node at point.
- Function: org-roam-buffer
Launch an Org-roam buffer for the current node at point.
To bring up a buffer that tracks the current node at point, call ~M-x To bring up a buffer that tracks the current node at point, call ~M-x
org-roam-buffer-toggle~. org-roam-buffer-toggle~.
@ -468,6 +464,13 @@ org-roam-buffer-toggle~.
Toggle display of the ~org-roam-buffer~. Toggle display of the ~org-roam-buffer~.
To bring up a buffer that's dedicated for a specific node, call ~M-x
org-roam-buffer-display-dedicated~.
- Function: org-roam-buffer-display-dedicated
Launch node dedicated Org-roam buffer without visiting the node itself.
** Navigating the Org-roam Buffer ** Navigating the Org-roam Buffer
The Org-roam buffer uses ~magit-section~, making the typical ~magit-section~ The Org-roam buffer uses ~magit-section~, making the typical ~magit-section~

View File

@ -716,23 +716,21 @@ other notes (backlinks, reference links, unlinked references etc.). There are
two main functions to use here: two main functions to use here:
@itemize @itemize
@item
@code{org-roam-buffer}: Launch an Org-roam buffer for the current node at point.
@item @item
@code{org-roam-buffer-toggle}: Launch an Org-roam buffer that tracks the node @code{org-roam-buffer-toggle}: Launch an Org-roam buffer that tracks the node
currently at point. This means that the content of the buffer changes as the currently at point. This means that the content of the buffer changes as the
point is moved, if necessary. point is moved, if necessary.
@item
@code{org-roam-buffer-display-dedicated}: Launch an Org-roam buffer for a
specific node without visiting its file. Unlike @code{org-roam-buffer-toggle} you
can have multiple such buffers and their content won't be automatically
replaced with a new node at point.
@end itemize @end itemize
Use @code{org-roam-buffer-toggle} when you want wish for the Org-roam buffer to Use @code{org-roam-buffer-toggle} when you want wish for the Org-roam buffer to
buffer, call @code{M-x org-roam-buffer}. buffer, call @code{M-x org-roam-buffer}.
@defun org-roam-buffer
Launch an Org-roam buffer for the current node at point.
@end defun
To bring up a buffer that tracks the current node at point, call @code{M-x To bring up a buffer that tracks the current node at point, call @code{M-x
org-roam-buffer-toggle}. org-roam-buffer-toggle}.
@ -741,6 +739,14 @@ org-roam-buffer-toggle}.
Toggle display of the @code{org-roam-buffer}. Toggle display of the @code{org-roam-buffer}.
@end defun @end defun
To bring up a buffer that's dedicated for a specific node, call @code{M-x
org-roam-buffer-display-dedicated}.
@defun org-roam-buffer-display-dedicated
Launch node dedicated Org-roam buffer without visiting the node itself.
@end defun
@menu @menu
* Navigating the Org-roam Buffer:: * Navigating the Org-roam Buffer::
* Configuring what is displayed in the buffer:: * Configuring what is displayed in the buffer::

View File

@ -98,6 +98,19 @@ recursion."
(nconc result (nreverse files)))) (nconc result (nreverse files))))
;;; Obsolete aliases (remove after next major release) ;;; Obsolete aliases (remove after next major release)
(define-obsolete-variable-alias
'org-roam-current-node
'org-roam-buffer-current-node "org-roam 2.0")
(define-obsolete-variable-alias
'org-roam-current-directory
'org-roam-buffer-current-directory "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-buffer-render
'org-roam-buffer-render-contents "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-buffer
'org-roam-buffer-display-dedicated "org-roam 2.0")
(define-obsolete-function-alias (define-obsolete-function-alias
'org-roam-dailies-find-today 'org-roam-dailies-find-today
'org-roam-dailies-goto-today "org-roam 2.0") 'org-roam-dailies-goto-today "org-roam 2.0")

View File

@ -120,16 +120,26 @@ and `:slant'."
:group 'org-roam-faces) :group 'org-roam-faces)
;;; Variables ;;; Variables
(defvar org-roam-current-node nil (defvar org-roam-buffer-current-node nil
"The current node at point.") "The node for which an `org-roam-mode' based buffer displays its contents.
This set both, locally and globally. Normally the local value is
only set in the `org-roam-mode' based buffers, while the global
value shows the current node in the persistent `org-roam-buffer'.")
(defvar org-roam-current-directory nil (put 'org-roam-buffer-current-node 'permanent-local t)
"The `org-roam-directory' value for the current node.")
(defvar org-roam-buffer-current-directory nil
"The `org-roam-directory' value of `org-roam-buffer-current-node'.
Set both, locally and globally in the same way as `org-roam-buffer-current-node'.")
(put 'org-roam-buffer-current-directory 'permanent-local t)
(defcustom org-roam-mode-section-functions (list #'org-roam-backlinks-section (defcustom org-roam-mode-section-functions (list #'org-roam-backlinks-section
#'org-roam-reflinks-section) #'org-roam-reflinks-section)
"Functions which insert sections of the `org-roam-buffer'. "Functions that insert sections in the `org-roam-mode' based buffers.
Each function is called with one argument, which is the current org-roam node at point." Each function is called with one argument, which is an
`org-roam-node' for which the buffer will be constructed for.
Normally this node is `org-roam-buffer-current-node'."
:group 'org-roam :group 'org-roam
:type 'hook) :type 'hook)
@ -139,7 +149,7 @@ Each function is called with one argument, which is the current org-roam node at
(set-keymap-parent map magit-section-mode-map) (set-keymap-parent map magit-section-mode-map)
(define-key map [C-return] 'org-roam-visit-thing) (define-key map [C-return] 'org-roam-visit-thing)
(define-key map (kbd "C-m") 'org-roam-visit-thing) (define-key map (kbd "C-m") 'org-roam-visit-thing)
(define-key map [remap revert-buffer] 'org-roam-buffer-render) (define-key map [remap revert-buffer] 'org-roam-buffer-refresh)
map) map)
"Parent keymap for all keymaps of modes derived from `org-roam-mode'.") "Parent keymap for all keymaps of modes derived from `org-roam-mode'.")
@ -156,54 +166,85 @@ which visits the thing at point."
(interactive) (interactive)
(user-error "There is no thing at point that could be visited")) (user-error "There is no thing at point that could be visited"))
(defun org-roam-buffer-render () (defun org-roam-buffer-refresh ()
"Render the current node at point." "Refresh the contents of the currently selected Org-roam buffer."
(interactive) (interactive)
(when (derived-mode-p 'org-roam-mode) (cl-assert (derived-mode-p 'org-roam-mode))
(let ((inhibit-read-only t)) (save-excursion (org-roam-buffer-render-contents)))
(erase-buffer)
(setq-local default-directory org-roam-current-directory)
(setq-local org-roam-directory org-roam-current-directory)
(org-roam-set-header-line-format (org-roam-node-title org-roam-current-node))
(magit-insert-section (org-roam)
(magit-insert-heading)
(run-hook-with-args 'org-roam-mode-section-functions org-roam-current-node)))))
(defun org-roam-buffer () (defun org-roam-buffer-render-contents ()
"Launch an Org-roam buffer for the current node at point." "Recompute and render the contents of an Org-roam buffer.
(interactive) Assumes that the current buffer is an `org-roam-mode' based
(if-let ((node (org-roam-node-at-point)) buffer."
(source-org-roam-directory org-roam-directory)) (let ((inhibit-read-only t))
(progn (erase-buffer)
(let ((buffer (get-buffer-create (org-roam-mode)
(concat "org-roam: " (setq-local default-directory org-roam-buffer-current-directory)
(file-relative-name (buffer-file-name) org-roam-directory))))) (setq-local org-roam-directory org-roam-buffer-current-directory)
(with-current-buffer buffer (org-roam-set-header-line-format
(org-roam-mode) (org-roam-node-title org-roam-buffer-current-node))
(setq-local org-roam-current-node node) (magit-insert-section (org-roam)
(setq-local org-roam-current-directory source-org-roam-directory) (magit-insert-heading)
(org-roam-buffer-render)) (run-hook-with-args 'org-roam-mode-section-functions org-roam-buffer-current-node))
(switch-to-buffer-other-window buffer))) (goto-char 0)))
(user-error "No node at point")))
;;; Dedicated buffer
;;;###autoload
(defun org-roam-buffer-display-dedicated (node)
"Launch NODE dedicated Org-roam buffer.
Unlike the persistent `org-roam-buffer', the contents of this
buffer won't be automatically changed and will be held in place.
In interactive calls prompt to select NODE, unless called with
`universal-argument', in which case NODE will be set to
`org-roam-node-at-point'."
(interactive
(list (if current-prefix-arg
(org-roam-node-at-point 'assert)
(org-roam-node-read nil nil nil 'require-match))))
(let ((buffer (get-buffer-create (org-roam-buffer--dedicated-name node))))
(with-current-buffer buffer
(setq-local org-roam-buffer-current-node node)
(setq-local org-roam-buffer-current-directory org-roam-directory)
(org-roam-buffer-render-contents))
(display-buffer buffer)))
(defun org-roam-buffer--dedicated-name (node)
"Construct buffer name for NODE dedicated Org-roam buffer."
(let ((title (org-roam-node-title node))
(filename (file-relative-name (org-roam-node-file node) org-roam-directory)))
(format "*org-roam: %s<%s>*" title filename)))
(defun org-roam-buffer-dedicated-p (&optional buffer)
"Return t if an Org-roam BUFFER is a node dedicated one.
See `org-roam-buffer-display-dedicated' for more details.
If BUFFER is nil, default it to `current-buffer'."
(or buffer (setq buffer (current-buffer)))
(string-match-p (concat "^" (regexp-quote "*org-roam: "))
(buffer-name buffer)))
;;; Persistent buffer ;;; Persistent buffer
(defvar org-roam-buffer "*org-roam*" (defvar org-roam-buffer "*org-roam*"
"The persistent Org-roam buffer name.") "The persistent Org-roam buffer name. Must be surround with \"*\".
The content inside of this buffer will be automatically updated
to the nearest node at point that comes from the current buffer.
To toggle its display use `org-roam-buffer-toggle' command.")
(defun org-roam-buffer--post-command-h () (defun org-roam-buffer-toggle ()
"Reconstructs the Org-roam buffer. "Toggle display of the persistent `org-roam-buffer'."
This needs to be quick or infrequent, because this is run at (interactive)
`post-command-hook'. If REDISPLAY, force an update of (pcase (org-roam-buffer--visibility)
the Org-roam buffer." ('visible
(when (get-buffer-window org-roam-buffer) (progn
(when-let ((node (org-roam-node-at-point))) (delete-window (get-buffer-window org-roam-buffer))
(unless (equal node org-roam-current-node) (remove-hook 'post-command-hook #'org-roam-buffer--redisplay-h)))
(setq org-roam-current-node node) ((or 'exists 'none)
(setq org-roam-current-directory org-roam-directory) (progn
(org-roam-buffer-persistent-redisplay))))) (display-buffer (get-buffer-create org-roam-buffer))
(org-roam-buffer-persistent-redisplay)))))
(define-inline org-roam-buffer--visibility () (define-inline org-roam-buffer--visibility ()
"Return whether the current visibility state of the org-roam buffer. "Return the current visibility state of the persistent `org-roam-buffer'.
Valid states are 'visible, 'exists and 'none." Valid states are 'visible, 'exists and 'none."
(declare (side-effect-free t)) (declare (side-effect-free t))
(inline-quote (inline-quote
@ -212,42 +253,34 @@ Valid states are 'visible, 'exists and 'none."
((get-buffer org-roam-buffer) 'exists) ((get-buffer org-roam-buffer) 'exists)
(t 'none)))) (t 'none))))
(defun org-roam-buffer-toggle () (defun org-roam-buffer--persistent-cleanup-h ()
"Toggle display of the Org-roam buffer." "Clean-up global state thats dedicated for the persistent `org-roam-buffer'."
(interactive) (setq-default org-roam-buffer-current-node nil
(pcase (org-roam-buffer--visibility) org-roam-buffer-current-directory nil))
('visible
(progn
(delete-window (get-buffer-window org-roam-buffer))
(remove-hook 'post-command-hook #'org-roam-buffer--post-command-h)))
((or 'exists 'none)
(progn
(setq org-roam-current-node (org-roam-node-at-point)
org-roam-current-directory org-roam-directory)
(display-buffer (get-buffer-create org-roam-buffer))
(org-roam-buffer-persistent-redisplay)))))
(defun org-roam-buffer-persistent-redisplay () (defun org-roam-buffer-persistent-redisplay ()
"Recompute contents of the persistent Org-roam buffer. "Recompute contents of the persistent `org-roam-buffer'.
Has no effect when `org-roam-current-node' is nil." Has no effect when there's no `org-roam-node-at-point'."
(when org-roam-current-node (when-let ((node (org-roam-node-at-point)))
(with-current-buffer (get-buffer-create org-roam-buffer) (unless (equal node org-roam-buffer-current-node)
(let ((inhibit-read-only t)) (setq org-roam-buffer-current-node node
(erase-buffer) org-roam-buffer-current-directory org-roam-directory)
(org-roam-mode) (with-current-buffer (get-buffer-create org-roam-buffer)
(setq-local default-directory org-roam-current-directory) (org-roam-buffer-render-contents)
(setq-local org-roam-directory org-roam-current-directory) (add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t)))))
(org-roam-set-header-line-format (org-roam-node-title org-roam-current-node))
(magit-insert-section (org-roam)
(magit-insert-heading)
(dolist (fn org-roam-mode-section-functions)
(funcall fn org-roam-current-node)))))))
(defun org-roam-buffer--redisplay () (defun org-roam-buffer--redisplay-h ()
"." "Reconstruct the persistent `org-roam-buffer'.
(add-hook 'post-command-hook #'org-roam-buffer--post-command-h nil t)) This needs to be quick or infrequent, because this designed to
run at `post-command-hook'."
(and (get-buffer-window org-roam-buffer)
(org-roam-buffer-persistent-redisplay)))
(add-hook 'org-roam-find-file-hook #'org-roam-buffer--redisplay) (defun org-roam-buffer--setup-redisplay-h ()
"Setup automatic redisplay of the persistent `org-roam-buffer'."
(add-hook 'post-command-hook #'org-roam-buffer--redisplay-h nil t))
(add-hook 'org-roam-find-file-hook #'org-roam-buffer--setup-redisplay-h)
;;; Sections ;;; Sections
;;;; Backlinks ;;;; Backlinks

View File

@ -870,8 +870,8 @@ window instead."
"Insert section for a link from SOURCE-NODE to some other node. "Insert section for a link from SOURCE-NODE to some other node.
SOURCE-NODE is an `org-roam-node' that links or references some SOURCE-NODE is an `org-roam-node' that links or references some
other node. Normally the other node is `org-roam-current-node' other node. Normally the other node is
that set in `org-roam-buffer'. `org-roam-buffer-current-node'.
POINT is the position in SOURCE-NODE's file where the link is POINT is the position in SOURCE-NODE's file where the link is
located. located.