mirror of
https://github.com/org-roam/org-roam
synced 2025-08-01 12:17:21 -05:00
(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:
@ -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~
|
||||||
|
@ -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::
|
||||||
|
@ -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")
|
||||||
|
191
org-roam-mode.el
191
org-roam-mode.el
@ -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
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user