mirror of
https://github.com/org-roam/org-roam
synced 2025-08-19 13:43:31 -05:00
Compare commits
16 Commits
migration/
...
feat/paren
Author | SHA1 | Date | |
---|---|---|---|
|
d7e1bd49a5 | ||
|
9acd982332 | ||
|
028c95a011 | ||
|
d1e3a5d9be | ||
|
8e89bad945 | ||
|
9c10a3c04c | ||
|
1aba91eacd | ||
|
2fe233ffa0 | ||
|
d9015cb931 | ||
|
7d5b7e6185 | ||
|
3ea433c09d | ||
|
e5c735c86a | ||
|
23605546d8 | ||
|
f50e30dd51 | ||
|
a529b20a81 | ||
|
6cbd4ad3e8 |
@@ -198,17 +198,6 @@ using:
|
||||
M-x package-install RET org-roam RET
|
||||
#+END_EXAMPLE
|
||||
|
||||
** Installing from Apt
|
||||
|
||||
Users of Debian 11 or later or Ubuntu 20.10 or later can simply install Org-roam
|
||||
using Apt:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
apt-get install elpa-org-roam
|
||||
#+END_SRC
|
||||
|
||||
Org-roam will then be autoloaded into Emacs.
|
||||
|
||||
** Installing from Source
|
||||
|
||||
You may install Org-roam directly from the repository on [[https://github.com/org-roam/org-roam][GitHub]] if you like.
|
||||
@@ -247,6 +236,7 @@ dependencies that it requires. These include:
|
||||
- org
|
||||
- emacsql
|
||||
- emacsql-sqlite
|
||||
- magit-section
|
||||
|
||||
You can install this manually as well, or get the latest version from MELPA. You
|
||||
may wish to use [[https://github.com/jwiegley/use-package][use-package]], [[https://github.com/raxod502/straight.el][straight.el]] to help manage this.
|
||||
@@ -457,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
|
||||
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
|
||||
currently at point. This means that the content of the buffer changes as the
|
||||
point is moved, if necessary.
|
||||
|
||||
Use ~org-roam-buffer-toggle~ when you want wish for the Org-roam buffer to
|
||||
buffer, call ~M-x org-roam-buffer~.
|
||||
|
||||
- Function: org-roam-buffer
|
||||
|
||||
Launch an Org-roam buffer for the current node at point.
|
||||
- ~org-roam-buffer-display-dedicated~: Launch an Org-roam buffer for a specific
|
||||
node without visiting its file. Unlike ~org-roam-buffer-toggle~ you can have
|
||||
multiple such buffers and their content won't be automatically replaced with a
|
||||
new node at point.
|
||||
|
||||
To bring up a buffer that tracks the current node at point, call ~M-x
|
||||
org-roam-buffer-toggle~.
|
||||
@@ -478,6 +464,13 @@ org-roam-buffer-toggle~.
|
||||
|
||||
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
|
||||
|
||||
The Org-roam buffer uses ~magit-section~, making the typical ~magit-section~
|
||||
@@ -500,10 +493,10 @@ There are currently 3 provided widget types:
|
||||
- Unlinked references :: View nodes that contain text that match the nodes
|
||||
title/alias but are not linked
|
||||
|
||||
To configure what sections are displayed in the buffer, set ~org-roam-mode-sections~.
|
||||
To configure what sections are displayed in the buffer, set ~org-roam-mode-section-functions~.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq org-roam-mode-sections
|
||||
(setq org-roam-mode-section-functions
|
||||
(list #'org-roam-backlinks-section
|
||||
#'org-roam-reflinks-section
|
||||
;; #'org-roam-unlinked-references-section
|
||||
@@ -1273,6 +1266,13 @@ are the solutions:
|
||||
set ~ivy-use-selectable-prompt~ to ~t~, so that "bar" is now selectable.
|
||||
- Helm :: Org-roam should provide a selectable "[?] bar" candidate at the top of
|
||||
the candidate list.
|
||||
** How can I stop Org-roam from creating IDs everywhere?
|
||||
|
||||
Other than the interactive commands that Org-roam provides, Org-roam does not
|
||||
create IDs everywhere. If you are noticing that IDs are being created even when
|
||||
you don't want them to be (e.g. when tangling an Org file), check the value you
|
||||
have set for ~org-id-link-to-org-use-id~: setting it to ~'create-if-interactive~
|
||||
is a popular option.
|
||||
|
||||
* Migrating from Org-roam v1
|
||||
|
||||
|
@@ -92,7 +92,6 @@ General Public License for more details.
|
||||
Installation
|
||||
|
||||
* Installing from MELPA::
|
||||
* Installing from Apt::
|
||||
* Installing from Source::
|
||||
* Installation Troubleshooting::
|
||||
|
||||
@@ -174,6 +173,7 @@ FAQ
|
||||
* How do I have more than one Org-roam directory?::
|
||||
* How do I migrate from Roam Research?::
|
||||
* How do I create a note whose title already matches one of the candidates?::
|
||||
* How can I stop Org-roam from creating IDs everywhere?::
|
||||
|
||||
Developer's Guide to Org-roam
|
||||
|
||||
@@ -337,7 +337,6 @@ development repository.
|
||||
|
||||
@menu
|
||||
* Installing from MELPA::
|
||||
* Installing from Apt::
|
||||
* Installing from Source::
|
||||
* Installation Troubleshooting::
|
||||
@end menu
|
||||
@@ -393,18 +392,6 @@ using:
|
||||
M-x package-install RET org-roam RET
|
||||
@end example
|
||||
|
||||
@node Installing from Apt
|
||||
@section Installing from Apt
|
||||
|
||||
Users of Debian 11 or later or Ubuntu 20.10 or later can simply install Org-roam
|
||||
using Apt:
|
||||
|
||||
@example
|
||||
apt-get install elpa-org-roam
|
||||
@end example
|
||||
|
||||
Org-roam will then be autoloaded into Emacs.
|
||||
|
||||
@node Installing from Source
|
||||
@section Installing from Source
|
||||
|
||||
@@ -456,6 +443,9 @@ emacsql
|
||||
|
||||
@item
|
||||
emacsql-sqlite
|
||||
|
||||
@item
|
||||
magit-section
|
||||
@end itemize
|
||||
|
||||
You can install this manually as well, or get the latest version from MELPA@. You
|
||||
@@ -651,7 +641,7 @@ Org-roam is available on startup, place this in your Emacs configuration:
|
||||
(org-roam-setup)
|
||||
@end lisp
|
||||
|
||||
To build the cache manually, run @code{M-x org-roam-db-build-cache}. Cache builds may
|
||||
To build the cache manually, run @code{M-x org-roam-db-sync}. Cache builds may
|
||||
take a while the first time, but subsequent builds are often instantaneous
|
||||
because they only reprocess modified files.
|
||||
|
||||
@@ -724,26 +714,21 @@ Org-roam provides (see @ref{Completion}).
|
||||
|
||||
Org-roam provides the Org-roam buffer: an interface to view relationships with
|
||||
other notes (backlinks, reference links, unlinked references etc.). There are
|
||||
two main functions to use here:
|
||||
two main commands to use here:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@code{org-roam-buffer}: Launch an Org-roam buffer for the current node at point.
|
||||
|
||||
@item
|
||||
@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
|
||||
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
|
||||
|
||||
Use @code{org-roam-buffer-toggle} when you want wish for the Org-roam buffer to
|
||||
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
|
||||
org-roam-buffer-toggle}.
|
||||
|
||||
@@ -752,6 +737,14 @@ org-roam-buffer-toggle}.
|
||||
Toggle display of the @code{org-roam-buffer}.
|
||||
@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
|
||||
* Navigating the Org-roam Buffer::
|
||||
* Configuring what is displayed in the buffer::
|
||||
@@ -798,10 +791,10 @@ There are currently 3 provided widget types:
|
||||
title/alias but are not linked
|
||||
@end itemize
|
||||
|
||||
To configure what sections are displayed in the buffer, set @code{org-roam-mode-sections}.
|
||||
To configure what sections are displayed in the buffer, set @code{org-roam-mode-section-functions}.
|
||||
|
||||
@lisp
|
||||
(setq org-roam-mode-sections
|
||||
(setq org-roam-mode-section-functions
|
||||
(list #'org-roam-backlinks-section
|
||||
#'org-roam-reflinks-section
|
||||
;; #'org-roam-unlinked-references-section
|
||||
@@ -1729,6 +1722,7 @@ Org-mode, and sync your cards to Anki via @uref{https://github.com/FooSoft/anki-
|
||||
* How do I have more than one Org-roam directory?::
|
||||
* How do I migrate from Roam Research?::
|
||||
* How do I create a note whose title already matches one of the candidates?::
|
||||
* How can I stop Org-roam from creating IDs everywhere?::
|
||||
@end menu
|
||||
|
||||
@node How do I have more than one Org-roam directory?
|
||||
@@ -1777,6 +1771,15 @@ set @code{ivy-use-selectable-prompt} to @code{t}, so that ``bar'' is now selecta
|
||||
the candidate list.
|
||||
@end itemize
|
||||
|
||||
@node How can I stop Org-roam from creating IDs everywhere?
|
||||
@section How can I stop Org-roam from creating IDs everywhere?
|
||||
|
||||
Other than the interactive commands that Org-roam provides, Org-roam does not
|
||||
create IDs everywhere. If you are noticing that IDs are being created even when
|
||||
you don't want them to be (e.g. when tangling an Org file), check the value you
|
||||
have set for @code{org-id-link-to-org-use-id}: setting it to @code{'create-if-interactive}
|
||||
is a popular option.
|
||||
|
||||
@node Migrating from Org-roam v1
|
||||
@chapter Migrating from Org-roam v1
|
||||
|
||||
|
@@ -525,6 +525,12 @@ also run Org-capture's template expansion."
|
||||
(when-let ((ref (plist-get org-roam-capture--info :ref)))
|
||||
(org-roam-ref-add ref)))
|
||||
|
||||
(defun org-roam-capture--create-parent-directory (path)
|
||||
"Create the parent directory for PATH."
|
||||
(make-directory
|
||||
(file-name-directory path)
|
||||
'parents))
|
||||
|
||||
(defun org-roam-capture--goto-location ()
|
||||
"Initialize the buffer, and goto the location of the new capture.
|
||||
Return the ID of the location."
|
||||
@@ -535,6 +541,7 @@ Return the ID of the location."
|
||||
(setq path (expand-file-name
|
||||
(string-trim (org-roam-capture--fill-template path t))
|
||||
org-roam-directory))
|
||||
(org-roam-capture--create-parent-directory path)
|
||||
(unless (file-exists-p path)
|
||||
(org-roam-capture--put :new-file path))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
@@ -544,6 +551,7 @@ Return the ID of the location."
|
||||
(setq path (expand-file-name
|
||||
(string-trim (org-roam-capture--fill-template path t))
|
||||
org-roam-directory))
|
||||
(org-roam-capture--create-parent-directory path)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(unless (file-exists-p path)
|
||||
(org-roam-capture--put :new-file path))
|
||||
@@ -555,6 +563,7 @@ Return the ID of the location."
|
||||
(setq path (expand-file-name
|
||||
(string-trim (org-roam-capture--fill-template path t))
|
||||
org-roam-directory))
|
||||
(org-roam-capture--create-parent-directory path)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(unless (file-exists-p path)
|
||||
(org-roam-capture--put :new-file path)
|
||||
@@ -565,6 +574,7 @@ Return the ID of the location."
|
||||
(setq path (expand-file-name
|
||||
(string-trim (org-roam-capture--fill-template path t))
|
||||
org-roam-directory))
|
||||
(org-roam-capture--create-parent-directory path)
|
||||
(widen)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(unless (file-exists-p path)
|
||||
@@ -577,6 +587,7 @@ Return the ID of the location."
|
||||
(setq path (expand-file-name
|
||||
(string-trim (org-roam-capture--fill-template path t))
|
||||
org-roam-directory))
|
||||
(org-roam-capture--create-parent-directory path)
|
||||
(require 'org-datetree)
|
||||
(widen)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
|
@@ -98,6 +98,19 @@ recursion."
|
||||
(nconc result (nreverse files))))
|
||||
|
||||
;;; 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
|
||||
'org-roam-dailies-find-today
|
||||
'org-roam-dailies-goto-today "org-roam 2.0")
|
||||
|
@@ -67,6 +67,8 @@ This path is relative to `org-roam-directory'."
|
||||
:if-new (file+head "%<%Y-%m-%d>.org"
|
||||
"#+title: %<%Y-%m-%d>\n")))
|
||||
"Capture templates for daily-notes in Org-roam.
|
||||
Note that for daily files to show up in the calendar, they have to be of format
|
||||
\"org-time-string.org\".
|
||||
See `org-roam-capture-templates' for the template documentation."
|
||||
:group 'org-roam
|
||||
:type '(repeat
|
||||
@@ -213,16 +215,17 @@ future."
|
||||
(org-roam-dailies-capture-tomorrow (- n) t))
|
||||
|
||||
;;; Calendar
|
||||
(defun org-roam-dailies-calendar--file-to-date (&optional file)
|
||||
(defun org-roam-dailies-calendar--file-to-date (file)
|
||||
"Convert FILE to date.
|
||||
Return (MONTH DAY YEAR)."
|
||||
(let ((file (or file
|
||||
(buffer-base-buffer (buffer-file-name)))))
|
||||
Return (MONTH DAY YEAR) or nil if not an Org time-string."
|
||||
(condition-case nil
|
||||
(progn
|
||||
(cl-destructuring-bind (_ _ _ d m y _ _ _)
|
||||
(org-parse-time-string
|
||||
(file-name-sans-extension
|
||||
(file-name-nondirectory file)))
|
||||
(list m d y))))
|
||||
(list m d y)))
|
||||
(t nil)))
|
||||
|
||||
(defun org-roam-dailies-calendar--date-to-time (date)
|
||||
"Convert DATE as returned from then calendar (MONTH DAY YEAR) to a time."
|
||||
@@ -231,8 +234,9 @@ Return (MONTH DAY YEAR)."
|
||||
(defun org-roam-dailies-calendar-mark-entries ()
|
||||
"Mark days in the calendar for which a daily-note is present."
|
||||
(when (file-exists-p (expand-file-name org-roam-dailies-directory org-roam-directory))
|
||||
(dolist (date (mapcar #'org-roam-dailies-calendar--file-to-date
|
||||
(org-roam-dailies--list-files)))
|
||||
(dolist (date (remove nil
|
||||
(mapcar #'org-roam-dailies-calendar--file-to-date
|
||||
(org-roam-dailies--list-files))))
|
||||
(when (calendar-date-is-visible-p date)
|
||||
(calendar-mark-visible-date date 'org-roam-dailies-calendar-note)))))
|
||||
|
||||
|
@@ -422,14 +422,23 @@ If UPDATE-P is non-nil, first remove the file in the database."
|
||||
(save-excursion
|
||||
(goto-char (org-element-property :begin link))
|
||||
(let ((type (org-element-property :type link))
|
||||
(dest (org-element-property :path link))
|
||||
(path (org-element-property :path link))
|
||||
(properties (list :outline (org-get-outline-path)))
|
||||
(source (org-roam-id-at-point)))
|
||||
(when source
|
||||
;; For Org-ref links, we need to split the path into the cite keys
|
||||
(when (and (boundp 'org-ref-cite-types)
|
||||
(fboundp 'org-ref-split-and-strip-string)
|
||||
(member type org-ref-cite-types))
|
||||
(setq path (org-ref-split-and-strip-string path)))
|
||||
(unless (listp path)
|
||||
(setq path (list path)))
|
||||
(when (and source path)
|
||||
(org-roam-db-query
|
||||
[:insert :into links
|
||||
:values $v1]
|
||||
(vector (point) source dest type properties))))))
|
||||
(mapcar (lambda (p)
|
||||
(vector (point) source p type properties))
|
||||
path))))))
|
||||
|
||||
;;;;; Fetching
|
||||
(defun org-roam-db--get-current-files ()
|
||||
|
@@ -51,7 +51,12 @@ for an overview of the major changes.
|
||||
|
||||
Notes taken in v1 are incompatible with v1, but you can upgrade
|
||||
them to the v2 format via a simple command. To migrate your
|
||||
notes, run:
|
||||
notes, first make sure you're on at least Org 9.4 (check with
|
||||
C-h v org-version) and set your org-roam-directory to your notes:
|
||||
|
||||
(setq org-roam-directory \"path/to/org/files\")
|
||||
|
||||
then, run:
|
||||
|
||||
M-x org-roam-migrate-wizard
|
||||
|
||||
@@ -83,10 +88,14 @@ This will take a while. Are you sure you want to do this?")
|
||||
(message "Backing up files to %s" backup-dir)
|
||||
(copy-directory org-roam-directory backup-dir))
|
||||
|
||||
;; Upgrade database to v2
|
||||
(org-roam-db-sync 'force)
|
||||
|
||||
;; Convert v1 to v2
|
||||
(dolist (f (org-roam--list-all-files))
|
||||
(org-roam-with-file f nil
|
||||
(org-roam-migrate-v1-to-v2)))
|
||||
|
||||
;; Rebuild cache
|
||||
(org-roam-db-sync 'force)
|
||||
|
||||
@@ -126,7 +135,11 @@ This will take a while. Are you sure you want to do this?")
|
||||
;; Replace #+roam_tags into #+filetags
|
||||
(org-with-point-at 1
|
||||
(let* ((roam-tags (org-roam-migrate-get-prop-list "ROAM_TAGS"))
|
||||
(file-tags (org-roam-migrate-get-prop-list "FILETAGS"))
|
||||
(file-tags (cl-mapcan (lambda (value)
|
||||
(cl-mapcan
|
||||
(lambda (k) (org-split-string k ":"))
|
||||
(split-string value)))
|
||||
(org-roam-migrate-get-prop-list "FILETAGS")))
|
||||
(tags (append roam-tags file-tags))
|
||||
(tags (seq-map (lambda (tag)
|
||||
(replace-regexp-in-string
|
||||
@@ -135,7 +148,7 @@ This will take a while. Are you sure you want to do this?")
|
||||
tag)) tags))
|
||||
(tags (seq-uniq tags)))
|
||||
(when tags
|
||||
(org-roam-migrate-prop-set "filetags" (string-join tags " "))))
|
||||
(org-roam-migrate-prop-set "filetags" (org-make-tag-string tags))))
|
||||
(let ((case-fold-search t))
|
||||
(org-with-point-at 1
|
||||
(while (re-search-forward "^#\\+roam_tags:" (point-max) t)
|
||||
@@ -186,7 +199,8 @@ If the property is already set, replace its value."
|
||||
:where (= file $s1)
|
||||
:and (= level 0)] path))))
|
||||
(set-match-data mdata)
|
||||
(replace-match (org-link-make-string (concat "id:" node-id)) nil t)))))))
|
||||
(replace-match (org-link-make-string (concat "id:" node-id)
|
||||
desc) nil t)))))))
|
||||
|
||||
(provide 'org-roam-migrate)
|
||||
;;; org-roam-migrate.el ends here
|
||||
|
179
org-roam-mode.el
179
org-roam-mode.el
@@ -120,16 +120,26 @@ and `:slant'."
|
||||
:group 'org-roam-faces)
|
||||
|
||||
;;; Variables
|
||||
(defvar org-roam-current-node nil
|
||||
"The current node at point.")
|
||||
(defvar org-roam-buffer-current-node nil
|
||||
"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
|
||||
"The `org-roam-directory' value for the current node.")
|
||||
(put 'org-roam-buffer-current-node 'permanent-local t)
|
||||
|
||||
(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
|
||||
#'org-roam-reflinks-section)
|
||||
"Functions which insert sections of the `org-roam-buffer'.
|
||||
Each function is called with one argument, which is the current org-roam node at point."
|
||||
"Functions that insert sections in the `org-roam-mode' based buffers.
|
||||
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
|
||||
: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)
|
||||
(define-key map [C-return] '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)
|
||||
"Parent keymap for all keymaps of modes derived from `org-roam-mode'.")
|
||||
|
||||
@@ -156,54 +166,85 @@ which visits the thing at point."
|
||||
(interactive)
|
||||
(user-error "There is no thing at point that could be visited"))
|
||||
|
||||
(defun org-roam-buffer-render ()
|
||||
"Render the current node at point."
|
||||
(defun org-roam-buffer-refresh ()
|
||||
"Refresh the contents of the currently selected Org-roam buffer."
|
||||
(interactive)
|
||||
(when (derived-mode-p 'org-roam-mode)
|
||||
(cl-assert (derived-mode-p 'org-roam-mode))
|
||||
(save-excursion (org-roam-buffer-render-contents)))
|
||||
|
||||
(defun org-roam-buffer-render-contents ()
|
||||
"Recompute and render the contents of an Org-roam buffer.
|
||||
Assumes that the current buffer is an `org-roam-mode' based
|
||||
buffer."
|
||||
(let ((inhibit-read-only t))
|
||||
(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))
|
||||
(org-roam-mode)
|
||||
(setq-local default-directory org-roam-buffer-current-directory)
|
||||
(setq-local org-roam-directory org-roam-buffer-current-directory)
|
||||
(org-roam-set-header-line-format
|
||||
(org-roam-node-title org-roam-buffer-current-node))
|
||||
(magit-insert-section (org-roam)
|
||||
(magit-insert-heading)
|
||||
(run-hook-with-args 'org-roam-mode-section-functions org-roam-current-node)))))
|
||||
(run-hook-with-args 'org-roam-mode-section-functions org-roam-buffer-current-node))
|
||||
(goto-char 0)))
|
||||
|
||||
(defun org-roam-buffer ()
|
||||
"Launch an Org-roam buffer for the current node at point."
|
||||
(interactive)
|
||||
(if-let ((node (org-roam-node-at-point))
|
||||
(source-org-roam-directory org-roam-directory))
|
||||
(progn
|
||||
(let ((buffer (get-buffer-create
|
||||
(concat "org-roam: "
|
||||
(file-relative-name (buffer-file-name) org-roam-directory)))))
|
||||
;;; 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
|
||||
(org-roam-mode)
|
||||
(setq-local org-roam-current-node node)
|
||||
(setq-local org-roam-current-directory source-org-roam-directory)
|
||||
(org-roam-buffer-render))
|
||||
(switch-to-buffer-other-window buffer)))
|
||||
(user-error "No node at point")))
|
||||
(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
|
||||
(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 ()
|
||||
"Reconstructs the Org-roam buffer.
|
||||
This needs to be quick or infrequent, because this is run at
|
||||
`post-command-hook'. If REDISPLAY, force an update of
|
||||
the Org-roam buffer."
|
||||
(when (get-buffer-window org-roam-buffer)
|
||||
(when-let ((node (org-roam-node-at-point)))
|
||||
(unless (equal node org-roam-current-node)
|
||||
(setq org-roam-current-node node)
|
||||
(setq org-roam-current-directory org-roam-directory)
|
||||
(defun org-roam-buffer-toggle ()
|
||||
"Toggle display of the persistent `org-roam-buffer'."
|
||||
(interactive)
|
||||
(pcase (org-roam-buffer--visibility)
|
||||
('visible
|
||||
(progn
|
||||
(delete-window (get-buffer-window org-roam-buffer))
|
||||
(remove-hook 'post-command-hook #'org-roam-buffer--redisplay-h)))
|
||||
((or 'exists 'none)
|
||||
(progn
|
||||
(display-buffer (get-buffer-create org-roam-buffer))
|
||||
(org-roam-buffer-persistent-redisplay)))))
|
||||
|
||||
(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."
|
||||
(declare (side-effect-free t))
|
||||
(inline-quote
|
||||
@@ -212,42 +253,34 @@ Valid states are 'visible, 'exists and 'none."
|
||||
((get-buffer org-roam-buffer) 'exists)
|
||||
(t 'none))))
|
||||
|
||||
(defun org-roam-buffer-toggle ()
|
||||
"Toggle display of the Org-roam buffer."
|
||||
(interactive)
|
||||
(pcase (org-roam-buffer--visibility)
|
||||
('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-cleanup-h ()
|
||||
"Clean-up global state thats dedicated for the persistent `org-roam-buffer'."
|
||||
(setq-default org-roam-buffer-current-node nil
|
||||
org-roam-buffer-current-directory nil))
|
||||
|
||||
(defun org-roam-buffer-persistent-redisplay ()
|
||||
"Recompute contents of the persistent Org-roam buffer.
|
||||
Has no effect when `org-roam-current-node' is nil."
|
||||
(when org-roam-current-node
|
||||
"Recompute contents of the persistent `org-roam-buffer'.
|
||||
Has no effect when there's no `org-roam-node-at-point'."
|
||||
(when-let ((node (org-roam-node-at-point)))
|
||||
(unless (equal node org-roam-buffer-current-node)
|
||||
(setq org-roam-buffer-current-node node
|
||||
org-roam-buffer-current-directory org-roam-directory)
|
||||
(with-current-buffer (get-buffer-create org-roam-buffer)
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(org-roam-mode)
|
||||
(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)
|
||||
(dolist (fn org-roam-mode-section-functions)
|
||||
(funcall fn org-roam-current-node)))))))
|
||||
(org-roam-buffer-render-contents)
|
||||
(add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t)))))
|
||||
|
||||
(defun org-roam-buffer--redisplay ()
|
||||
"."
|
||||
(add-hook 'post-command-hook #'org-roam-buffer--post-command-h nil t))
|
||||
(defun org-roam-buffer--redisplay-h ()
|
||||
"Reconstruct the persistent `org-roam-buffer'.
|
||||
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
|
||||
;;;; Backlinks
|
||||
@@ -410,7 +443,7 @@ If ROW, move to the row, and if COL move to the COL."
|
||||
"Return the preview line from FILE.
|
||||
This is the ROW within FILE."
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally file)
|
||||
(insert-file-contents file)
|
||||
(forward-line (1- row))
|
||||
(buffer-substring-no-properties
|
||||
(save-excursion
|
||||
|
106
org-roam.el
106
org-roam.el
@@ -167,12 +167,13 @@ Like `file-name-extension', but does not strip version number."
|
||||
"Return t if FILE is part of Org-roam system, nil otherwise.
|
||||
If FILE is not specified, use the current buffer's file-path."
|
||||
(let* ((path (or file (buffer-file-name (buffer-base-buffer))))
|
||||
(ext (org-roam--file-name-extension path))
|
||||
(ext (when path (org-roam--file-name-extension path)))
|
||||
(ext (if (string= ext "gpg")
|
||||
(org-roam--file-name-extension (file-name-sans-extension path))
|
||||
ext)))
|
||||
(save-match-data
|
||||
(and
|
||||
path
|
||||
(member ext org-roam-file-extensions)
|
||||
(not (and org-roam-file-exclude-regexp
|
||||
(string-match-p org-roam-file-exclude-regexp path)))
|
||||
@@ -418,11 +419,9 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
|
||||
(defclass org-roam-preview-section (magit-section)
|
||||
((keymap :initform 'org-roam-preview-map)
|
||||
(file :initform nil)
|
||||
(begin :initform nil)
|
||||
(end :initform nil))
|
||||
(point :initform nil))
|
||||
"A `magit-section' used by `org-roam-mode' to contain preview content.
|
||||
The preview content comes from FILE, between the next locations:
|
||||
BEGIN and END.")
|
||||
The preview content comes from FILE, and the link as at POINT.")
|
||||
|
||||
(cl-defmethod org-roam-populate ((node org-roam-node))
|
||||
"Populate NODE from database.
|
||||
@@ -530,17 +529,87 @@ Uses `org-roam-node-display-template' to format the entry."
|
||||
(- width (cdr fmt)))
|
||||
0 ?\s)))))))
|
||||
|
||||
(defun org-roam-node-preview (file point)
|
||||
(defun org-roam-get-preview (file point)
|
||||
"Get preview content for FILE at POINT."
|
||||
(save-excursion
|
||||
(org-roam-with-temp-buffer file
|
||||
(goto-char point)
|
||||
(let* ((elem (org-element-at-point))
|
||||
(begin (org-element-property :begin elem))
|
||||
(let ((elem (org-element-at-point)))
|
||||
;; We want the parent element always
|
||||
(while (org-element-property :parent elem)
|
||||
(setq elem (org-element-property :parent elem)))
|
||||
(pcase (car elem)
|
||||
('headline ; show subtree
|
||||
(org-roam-headline-get-preview-text (point-marker) most-positive-fixnum))
|
||||
(_
|
||||
(let ((begin (org-element-property :begin elem))
|
||||
(end (org-element-property :end elem)))
|
||||
(list begin end
|
||||
(or (string-trim (buffer-substring-no-properties begin end))
|
||||
(org-element-property :raw-value elem)))))))
|
||||
(org-element-property :raw-value elem)))))))))
|
||||
|
||||
(defun org-roam-headline-get-preview-text (marker n-lines &optional indent)
|
||||
"Extract entry text from MARKER, at most N-LINES lines.
|
||||
This will ignore drawers etc, just get the text.
|
||||
If INDENT is given, prefix every line with this string."
|
||||
(let (txt drawer-re kwd-time-re ind)
|
||||
(save-excursion
|
||||
(with-current-buffer (marker-buffer marker)
|
||||
(if (not (derived-mode-p 'org-mode))
|
||||
(setq txt "")
|
||||
(org-with-wide-buffer
|
||||
(goto-char marker)
|
||||
(end-of-line 1)
|
||||
(setq txt (buffer-substring
|
||||
(min (1+ (point)) (point-max))
|
||||
(progn (outline-next-heading) (point))))
|
||||
(with-temp-buffer
|
||||
(insert txt)
|
||||
(goto-char (point-min))
|
||||
(while (org-activate-links (point-max))
|
||||
(goto-char (match-end 0)))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward org-link-bracket-re (point-max) t)
|
||||
(set-text-properties (match-beginning 0) (match-end 0)
|
||||
nil))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward org-drawer-regexp nil t)
|
||||
(delete-region
|
||||
(match-beginning 0)
|
||||
(progn (re-search-forward
|
||||
"^[ \t]*:END:.*\n?" nil 'move)
|
||||
(point))))
|
||||
(goto-char (point-min))
|
||||
(goto-char (point-max))
|
||||
(skip-chars-backward " \t\n")
|
||||
(when (looking-at "[ \t\n]+\\'") (replace-match ""))
|
||||
|
||||
;; find and remove min common indentation
|
||||
(goto-char (point-min))
|
||||
(untabify (point-min) (point-max))
|
||||
(setq ind (current-indentation))
|
||||
(while (not (eobp))
|
||||
(unless (looking-at "[ \t]*$")
|
||||
(setq ind (min ind (current-indentation))))
|
||||
(beginning-of-line 2))
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(unless (looking-at "[ \t]*$")
|
||||
(move-to-column ind)
|
||||
(delete-region (point-at-bol) (point)))
|
||||
(beginning-of-line 2))
|
||||
(goto-char (point-min))
|
||||
(when indent
|
||||
(while (and (not (eobp)) (re-search-forward "^" nil t))
|
||||
(replace-match indent t t)))
|
||||
(goto-char (point-min))
|
||||
(while (looking-at "[ \t]*\n") (replace-match ""))
|
||||
(goto-char (point-max))
|
||||
(when (> (org-current-line)
|
||||
n-lines)
|
||||
(org-goto-line (1+ n-lines))
|
||||
(backward-char 1))
|
||||
(setq txt (buffer-substring (point-min) (point))))))))
|
||||
(list (point-min) (point) txt)))
|
||||
|
||||
(defun org-roam-node-at-point (&optional assert)
|
||||
"Return the node at point.
|
||||
@@ -786,8 +855,8 @@ Returns empty string for annotations."
|
||||
"Visit FILE at POINT.
|
||||
With prefix argument OTHER-WINDOW, visit the olp in another
|
||||
window instead."
|
||||
(interactive (list (org-roam-file-at-point t)
|
||||
(oref (magit-current-section) begin)
|
||||
(interactive (list (org-roam-file-at-point 'assert)
|
||||
(oref (magit-current-section) point)
|
||||
current-prefix-arg))
|
||||
(let ((buf (find-file-noselect file)))
|
||||
(with-current-buffer buf
|
||||
@@ -801,8 +870,8 @@ window instead."
|
||||
"Insert section for a link from SOURCE-NODE to some other node.
|
||||
|
||||
SOURCE-NODE is an `org-roam-node' that links or references some
|
||||
other node. Normally the other node is `org-roam-current-node'
|
||||
that set in `org-roam-buffer'.
|
||||
other node. Normally the other node is
|
||||
`org-roam-buffer-current-node'.
|
||||
|
||||
POINT is the position in SOURCE-NODE's file where the link is
|
||||
located.
|
||||
@@ -828,12 +897,11 @@ This section is made out of the next 2 `magit-section's:
|
||||
(magit-insert-heading)
|
||||
(oset section node source-node)
|
||||
(magit-insert-section section (org-roam-preview-section)
|
||||
(pcase-let ((`(,begin ,end ,s) (org-roam-node-preview (org-roam-node-file source-node)
|
||||
point)))
|
||||
(insert (org-roam-fontify-like-in-org-mode s) "\n")
|
||||
(insert (org-roam-fontify-like-in-org-mode
|
||||
(org-roam-get-preview (org-roam-node-file source-node) point))
|
||||
"\n")
|
||||
(oset section file (org-roam-node-file source-node))
|
||||
(oset section begin begin)
|
||||
(oset section end end))
|
||||
(oset section point point)
|
||||
(insert ?\n))))
|
||||
|
||||
;;;###autoload
|
||||
|
Reference in New Issue
Block a user