Compare commits

...

27 Commits

Author SHA1 Message Date
d7e1bd49a5 (feat)capture: create parent directories
Closes #1643
2021-07-25 10:57:10 +08:00
9acd982332 (docs): add org-id-link-to-org-use-id to FAQ (#1670)
Address a common question about Org-roam creating IDs
2021-07-25 10:31:20 +08:00
028c95a011 (fix)migration: upgrade db to v2 before conversion (#1666)
`org-roam-migrate-v1-to-v2` requires the v2 db to already be in place,
so run `org-roam-db-sync` once first.

Fixes #1664
2021-07-24 16:54:46 +08:00
d1e3a5d9be (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.
2021-07-23 19:19:30 +08:00
8e89bad945 (migration)docs: Warn requirement of at least Org 9.4 (#1663)
Closes #1661
2021-07-23 19:17:47 +08:00
9c10a3c04c (feat)preview: improve org-roam link preview (#1655)
1. If it the link is at a headline, it shows the headline's content
instead of just repeating the headline
2. If the link is a bullet item in the plain-list, show the full list instead
2021-07-22 01:46:12 +08:00
1aba91eacd (fix)tags: fix tags migration (#1653)
- prevent botching of existing filetags
- insert new tag list using `org-make-tag-string` (colon-delimited) for resilience

Fixes #1642.
2021-07-21 23:25:04 +08:00
2fe233ffa0 (fix)dailies: prevent non-compliant dailies from breaking calendar (#1652)
ht @mbafford for finding the cause
2021-07-21 23:03:03 +08:00
d9015cb931 (fix): fix org-roam-file-p crashing (#1651)
org-roam-file-p throws `wrong-type-argument stringp nil` on buffers that
do not have a corresponding file. This fix changes org-roam-file-p to
return nil instead of crashing in this scenario.

Addresses #1645
2021-07-21 20:57:59 +08:00
7d5b7e6185 (fix): fix org-ref cite links (#1637) 2021-07-20 16:25:54 +08:00
3ea433c09d (migration): mention org-roam-directory (#1636)
Mention the requirement to set org-roam-directory before running the
migration wizard. Closes #1624.
2021-07-20 15:17:28 +08:00
e5c735c86a (docs): remove apt installation (#1634)
Apt installation is only valid for Org-roam v1. To be re-added when
Debian updates their repos. Closes #1631.
2021-07-20 15:10:01 +08:00
23605546d8 (docs): mention magit-section as dependency in install from source (#1618) 2021-07-19 17:30:52 +08:00
f50e30dd51 Include desc back in replace-match statement (#1615)
Following @jcguu95's suggestion on #1602.
2021-07-19 10:38:19 +08:00
a529b20a81 fix(#1575): fix display of non-ASCII in unlinked references section (#1616)
Non-ASCII characters are displayed incorrectly because
`org-roam-unlinked-references-preview-line` uses
`insert-file-contents-literally` which ignores the encoding.

Use `insert-file-contents` which does the right thing.

fixes #1575
2021-07-19 10:36:21 +08:00
6cbd4ad3e8 org-roam-mode-sections -> org-roam-mode-section-functions (#1612) 2021-07-19 10:35:40 +08:00
e997c017de (docs): adjusted configuration examples for backlinks buffer (#1610)
- Fixed the original example's extra parenthesis, which broke the alist.
 - Added a second example for configuring the buffer as a side window.
2021-07-19 01:31:34 +08:00
63450e9eaf migration: proper fix for file-link replacement (#1609) 2021-07-18 23:23:04 +08:00
da02453ab1 (fix): migration: ensure empty roam_alias is removed (#1608)
* (fix): migration: ensure empty roam_alias is removed

Addresses #1596

* fix lint
2021-07-18 23:08:59 +08:00
bbf1d97eb0 (refactor): move all the backward compatibility related code to org-roam-compat.el (#1595) 2021-07-18 22:50:45 +08:00
7d9fcf5288 (docs) Replace mention of org-roam-db-build-cache with org-roam-db-sync (#1606) 2021-07-18 21:43:34 +08:00
d0be7f3b2a (fix): allow migration for desc with backslash (#1604)
Fixes #1602
2021-07-18 19:51:05 +08:00
363dca1765 (doc): add my braindump example (Sidharth Arya) (#1599) 2021-07-18 19:35:18 +08:00
4c5a041556 (docs): add note on encryption (#1597) 2021-07-18 14:55:32 +08:00
5e42d854c1 (doc): Add section for C Compiler (#1593)
* (doc): Add section for C Compiler

In the Post-Installation Tasks section, I suggest to add a sub-section for the C
compiler requirement for emacsql-sqlite. I have put an explanation for Windows
-- I have tried to make it as succinct as I can without losing some fine points
that I believe important for users to avoid confusion.

I have just removed MSYS2 and the PATH on my Windows machine and repeated the
process as I described it here to confirm that it works.

Since this new part is distinct from the existing paragraphs for SQLite, I also
suggest a sub-section heading for them -- I used "SQLite" as its title.

Please feel feel to change any part as you see fit.

It might be also useful if macOS users added their parts. I believe XCode is the
easiest way to install a C compiler (I believe it would be clang for recent
XCode versions) or perhaps brew. I don't use macOS so I will refrain from adding
this part..

I did not add .texi file to this commit -- last time, I believe you had to
revise the texi file that my machine generated anyway. Let me know if I should
follow up with a texi file.

* remove reference to emacsql-sqlite3

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-07-18 14:39:30 +08:00
681873759d Refactor some docstring and parameters in org-roam.el (#1594)
This mostly goes over docstrings, updating them in places where it was
outdated and adding them to places where they didn't exist or were
existed as placeholders.
2021-07-18 14:22:45 +08:00
2168490d5a bump docs for Org-roam v2 (#1591) 2021-07-17 22:54:31 +08:00
10 changed files with 1667 additions and 1534 deletions

View File

@ -86,6 +86,7 @@ it has not already been addressed on [GitHub][issues] or on
- [Jethro Kuan](https://braindump.jethro.dev/) - [Jethro Kuan](https://braindump.jethro.dev/)
([Source](https://github.com/jethrokuan/braindump/tree/master/org)) ([Source](https://github.com/jethrokuan/braindump/tree/master/org))
- [Alexey Shmalko](https://braindump.rasen.dev/) - [Alexey Shmalko](https://braindump.rasen.dev/)
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
## Contributing ## Contributing

View File

@ -134,7 +134,7 @@ A slip-box requires a method for quickly capturing ideas. These are called
*fleeting notes*: they are simple reminders of information or ideas that will *fleeting notes*: they are simple reminders of information or ideas that will
need to be processed later on, or trashed. This is typically accomplished using need to be processed later on, or trashed. This is typically accomplished using
~org-capture~ (see info:org#Capture), or using Org-roam's daily notes ~org-capture~ (see info:org#Capture), or using Org-roam's daily notes
functionality (see [[*Daily-notes][Daily-notes]]). This provides a central inbox for collecting functionality (see [[id:4eae8552-95e1-4e4a-b7b7-2c53433730ea][Org-roam Dailies]]). This provides a central inbox for collecting
thoughts, to be processed later into permanent notes. thoughts, to be processed later into permanent notes.
*Permanent notes* *Permanent notes*
@ -198,19 +198,6 @@ using:
M-x package-install RET org-roam RET M-x package-install RET org-roam RET
#+END_EXAMPLE #+END_EXAMPLE
Now see [[*Post-Installation Tasks][Post-Installation Tasks]].
** 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 ** Installing from Source
You may install Org-roam directly from the repository on [[https://github.com/org-roam/org-roam][GitHub]] if you like. You may install Org-roam directly from the repository on [[https://github.com/org-roam/org-roam][GitHub]] if you like.
@ -248,7 +235,8 @@ dependencies that it requires. These include:
- s - s
- org - org
- emacsql - emacsql
- emacsql-sqlite3 - emacsql-sqlite
- magit-section
You can install this manually as well, or get the latest version from MELPA. You 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. may wish to use [[https://github.com/jwiegley/use-package][use-package]], [[https://github.com/raxod502/straight.el][straight.el]] to help manage this.
@ -291,23 +279,43 @@ file:
install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir
#+end_src #+end_src
** Post-Installation Tasks ** Installation Troubleshooting
*** C Compiler
Org-roam relies on an Emacs package called ~emacsql~ and ~emacsql-sqlite~ to
work with the ~sqlite~ database. Both of them should be installed automatically
in your Emacs environment as a prerequisite for Org-roam when you install it.
Org-roam requires ~sqlite3~ to be locatable by Emacs (i.e. on ~exec-path~). ~emacsql-sqlite~ requires a C compiler (e.g. ~gcc~ or ~clang~) to be present in
Please ensure that ~sqlite3~ is installed appropriately on your operating your computer. How to install a C compiler depends on the OS that you use.
system. You can verify that this is the case by executing [fn:2]:
#+BEGIN_SRC emacs-lisp - For Windows:
(executable-find "sqlite3")
#+END_SRC
If you have ~sqlite3~ installed, and ~executable-find~ still reports ~nil~, then There are various ways to install one, depending on how you have installed
the path to the executable is not a member of the Emacs variable ~exec-path~. Emacs. If you use Emacs within a Cygwin or MinGW environment, then you should
Rectify this by manually adding the path within your Emacs configuration: install a compiler using their respective package manager.
#+BEGIN_SRC emacs-lisp If you have installed your Emacs from the [[https://www.gnu.org/software/emacs/][GNU Emacs website]], then the easiest way
(add-to-list 'exec-path "path/to/sqlite3") is to use [[https://www.msys2.org/][MSYS2]] as at the time of this writing:
#+END_SRC
1. Use the installer in the official website and install MSYS2
2. Run MSYS2
3. In the command-line tool, type the following and answer "Y" to proceed:
#+BEGIN_SRC bash
pacman -S gcc
#+END_SRC
Note that you do not need to manually set the PATH for MSYS2; the
installer automatically takes care of it for you.
4. Open Emacs and call ~M-x org-roam-setup~
This will automatically start compiling ~emacsql-sqlite~; you should see a
message in minibuffer. It may take a while until compilation completes. Once
complete, you should see a new file ~emacsql-sqlite.exe~ created in a subfolder
named ~sqlite~ under ~emacsql-sqlite~ installation folder. It's typically in
your Emacs configuration folder like this:
~/.config/emacs/elpa/emacsql-sqlite-20190727.1710/sqlite~
* Getting Started * Getting Started
** The Org-roam Node ** The Org-roam Node
@ -376,7 +384,7 @@ Org-roam is available on startup, place this in your Emacs configuration:
(org-roam-setup) (org-roam-setup)
#+end_src #+end_src
To build the cache manually, run ~M-x org-roam-db-build-cache~. Cache builds may To build the cache manually, run ~M-x org-roam-db-sync~. Cache builds may
take a while the first time, but subsequent builds are often instantaneous take a while the first time, but subsequent builds are often instantaneous
because they only reprocess modified files. because they only reprocess modified files.
@ -439,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~.
@ -460,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~
@ -478,14 +489,14 @@ section-specific commands such as ~org-roam-node-visit~.
There are currently 3 provided widget types: There are currently 3 provided widget types:
- Backlinks :: View (preview of) nodes that link to this node - Backlinks :: View (preview of) nodes that link to this node
- Reference Links :: Nodes that reference this node (see [[id:57c1f991-be38-4fab-b27d-60227047f3b7][Refs]]) - Reference Links :: Nodes that reference this node (see [[*Refs][Refs]])
- Unlinked references :: View nodes that contain text that match the nodes - Unlinked references :: View nodes that contain text that match the nodes
title/alias but are not linked 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 #+begin_src emacs-lisp
(setq org-roam-mode-sections (setq org-roam-mode-section-functions
(list #'org-roam-backlinks-section (list #'org-roam-backlinks-section
#'org-roam-reflinks-section #'org-roam-reflinks-section
;; #'org-roam-unlinked-references-section ;; #'org-roam-unlinked-references-section
@ -501,11 +512,11 @@ the user. The author's recommended configuration is as follows:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(add-to-list 'display-buffer-alist (add-to-list 'display-buffer-alist
'(("\\*org-roam\\*" '("\\*org-roam\\*"
(display-buffer-in-direction) (display-buffer-in-direction)
(direction . right) (direction . right)
(window-width . 0.33) (window-width . 0.33)
(window-height . fit-window-to-buffer)))) (window-height . fit-window-to-buffer)))
#+end_src #+end_src
Crucially, the window is a regular window (not a side-window), and this allows Crucially, the window is a regular window (not a side-window), and this allows
@ -515,6 +526,20 @@ for predictable navigation:
Org-roam buffer. Org-roam buffer.
- ~C-u RET~ navigates to thing-at-point in the other window. - ~C-u RET~ navigates to thing-at-point in the other window.
For users that prefer using a side-window for the org-roam buffer, the following
example configuration should provide a good starting point:
#+begin_src emacs-lisp
(add-to-list 'display-buffer-alist
'("\\*org-roam\\*"
(display-buffer-in-side-window)
(side . right)
(slot . 0)
(window-width . 0.33)
(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t)))))
#+end_src
** TODO Styling the Org-roam buffer ** TODO Styling the Org-roam buffer
* Node Properties * Node Properties
** Standard Org properties ** Standard Org properties
@ -587,7 +612,7 @@ With the above example, if another node links to https://www.google.com/, it
will show up as a “reference backlink”. will show up as a “reference backlink”.
These keys also come in useful for when taking website notes, using the These keys also come in useful for when taking website notes, using the
~roam-ref~ protocol (see [[*Roam Protocol][Roam Protocol]]). ~roam-ref~ protocol (see [[*Org-roam Protocol][Roam Protocol]]).
You may assign multiple refs to a single node, for example when you want You may assign multiple refs to a single node, for example when you want
multiple papers in a series to share the same note, or an article has a citation multiple papers in a series to share the same note, or an article has a citation
@ -664,6 +689,10 @@ extension in your Org-roam capture templates. For example:
:unnarrowed t))) :unnarrowed t)))
#+end_src #+end_src
Note that the Org-roam database stores metadata information in plain-text
(headline text, for example), so if this information is private to you then you
should also ensure the database is encrypted.
* Org-roam Protocol * Org-roam Protocol
Org-roam provides extensions for capturing content from external applications Org-roam provides extensions for capturing content from external applications
@ -838,7 +867,7 @@ where ~template~ is the template key for a template in
~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]). These templates ~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]). These templates
should contain a ~#+roam_key: ${ref}~ in it. should contain a ~#+roam_key: ${ref}~ in it.
* The Org-roam Templating System * The Templating System
Org-roam extends the ~org-capture~ system, providing a smoother note-taking Org-roam extends the ~org-capture~ system, providing a smoother note-taking
experience. However, these extensions mean Org-roam capture templates are experience. However, these extensions mean Org-roam capture templates are
@ -902,7 +931,7 @@ strings. ~${foo}~'s substitution is performed as follows:
Org-roam provides basic graphing capabilities to explore interconnections Org-roam provides basic graphing capabilities to explore interconnections
between notes, in ~org-roam-graph~. This is done by performing SQL queries and between notes, in ~org-roam-graph~. This is done by performing SQL queries and
generating images using [[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*Roam Protocol][Roam generating images using [[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*Org-roam Protocol][Roam
Protocol]]. Protocol]].
The entry point to graph creation is ~org-roam-graph~. The entry point to graph creation is ~org-roam-graph~.
@ -971,9 +1000,12 @@ for customizable options.
Example: ~'(("dir" . "back"))~ Example: ~'(("dir" . "back"))~
* Org-roam Dailies * Org-roam Dailies
:PROPERTIES:
:ID: 4eae8552-95e1-4e4a-b7b7-2c53433730ea
:END:
Org-roam provides journaling capabilities akin to Org-roam provides journaling capabilities akin to
[[#org-journal][Org-journal]] with ~org-roam-dailies~. Org-journal with ~org-roam-dailies~.
** Configuration ** Configuration
@ -1011,7 +1043,7 @@ See [[*The Templating System][The Templating System]] for creating new templates
When ~goto~ is non-nil, go to the note without creating an entry. When ~goto~ is non-nil, go to the note without creating an entry.
- Function: ~org-roam-dailies-find-today~ - Function: ~org-roam-dailies-goto-today~
Find the daily note for today, creating it if necessary. Find the daily note for today, creating it if necessary.
@ -1023,7 +1055,7 @@ There are variants of those commands for ~-yesterday~ and ~-tomorrow~:
With numeric argument ~n~, use the daily note ~n~ days in the past. With numeric argument ~n~, use the daily note ~n~ days in the past.
- Function: ~org-roam-dailies-find-yesterday~ - Function: ~org-roam-dailies-goto-yesterday~
With numeric argument N, use the daily-note N days in the future. With numeric argument N, use the daily-note N days in the future.
@ -1038,7 +1070,7 @@ There are also commands which allow you to use Emacss ~calendar~ to find the
With a 'C-u' prefix or when ~goto~ is non-nil, go the note without With a 'C-u' prefix or when ~goto~ is non-nil, go the note without
creating an entry. creating an entry.
- Function: ~org-roam-dailies-find-date~ - Function: ~org-roam-dailies-goto-date~
Find the daily note for a date using the calendar, creating it if necessary. Find the daily note for a date using the calendar, creating it if necessary.
@ -1048,11 +1080,11 @@ There are also commands which allow you to use Emacss ~calendar~ to find the
Find and open ~org-roam-dailies-directory~. Find and open ~org-roam-dailies-directory~.
- Function: ~org-roam-dailies-find-previous-note~ - Function: ~org-roam-dailies-goto-previous-note~
When in an daily-note, find the previous one. When in an daily-note, find the previous one.
- Function: ~org-roam-dailies-find-next-note~ - Function: ~org-roam-dailies-goto-next-note~
When in an daily-note, find the next one. When in an daily-note, find the next one.
* Performance Optimization * Performance Optimization
@ -1128,7 +1160,7 @@ The Deft interface can slow down quickly when the number of files get huge.
[[https://github.com/bastibe/org-journal][Org-journal]] provides journaling capabilities to Org-mode. A lot of its [[https://github.com/bastibe/org-journal][Org-journal]] provides journaling capabilities to Org-mode. A lot of its
functionalities have been incorporated into Org-roam under the name functionalities have been incorporated into Org-roam under the name
[[*Daily-notes][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose [[*Org-roam Dailies][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose
journal entries from the ideas you would write on a scratchpad. journal entries from the ideas you would write on a scratchpad.
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
@ -1234,6 +1266,13 @@ are the solutions:
set ~ivy-use-selectable-prompt~ to ~t~, so that "bar" is now selectable. 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 - Helm :: Org-roam should provide a selectable "[?] bar" candidate at the top of
the candidate list. 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 * Migrating from Org-roam v1

File diff suppressed because it is too large Load Diff

View File

@ -525,6 +525,12 @@ also run Org-capture's template expansion."
(when-let ((ref (plist-get org-roam-capture--info :ref))) (when-let ((ref (plist-get org-roam-capture--info :ref)))
(org-roam-ref-add 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 () (defun org-roam-capture--goto-location ()
"Initialize the buffer, and goto the location of the new capture. "Initialize the buffer, and goto the location of the new capture.
Return the ID of the location." Return the ID of the location."
@ -535,6 +541,7 @@ Return the ID of the location."
(setq path (expand-file-name (setq path (expand-file-name
(string-trim (org-roam-capture--fill-template path t)) (string-trim (org-roam-capture--fill-template path t))
org-roam-directory)) org-roam-directory))
(org-roam-capture--create-parent-directory path)
(unless (file-exists-p path) (unless (file-exists-p path)
(org-roam-capture--put :new-file path)) (org-roam-capture--put :new-file path))
(set-buffer (org-capture-target-buffer path)) (set-buffer (org-capture-target-buffer path))
@ -544,6 +551,7 @@ Return the ID of the location."
(setq path (expand-file-name (setq path (expand-file-name
(string-trim (org-roam-capture--fill-template path t)) (string-trim (org-roam-capture--fill-template path t))
org-roam-directory)) org-roam-directory))
(org-roam-capture--create-parent-directory path)
(set-buffer (org-capture-target-buffer path)) (set-buffer (org-capture-target-buffer path))
(unless (file-exists-p path) (unless (file-exists-p path)
(org-roam-capture--put :new-file path)) (org-roam-capture--put :new-file path))
@ -555,6 +563,7 @@ Return the ID of the location."
(setq path (expand-file-name (setq path (expand-file-name
(string-trim (org-roam-capture--fill-template path t)) (string-trim (org-roam-capture--fill-template path t))
org-roam-directory)) org-roam-directory))
(org-roam-capture--create-parent-directory path)
(set-buffer (org-capture-target-buffer path)) (set-buffer (org-capture-target-buffer path))
(unless (file-exists-p path) (unless (file-exists-p path)
(org-roam-capture--put :new-file path) (org-roam-capture--put :new-file path)
@ -565,6 +574,7 @@ Return the ID of the location."
(setq path (expand-file-name (setq path (expand-file-name
(string-trim (org-roam-capture--fill-template path t)) (string-trim (org-roam-capture--fill-template path t))
org-roam-directory)) org-roam-directory))
(org-roam-capture--create-parent-directory path)
(widen) (widen)
(set-buffer (org-capture-target-buffer path)) (set-buffer (org-capture-target-buffer path))
(unless (file-exists-p path) (unless (file-exists-p path)
@ -577,6 +587,7 @@ Return the ID of the location."
(setq path (expand-file-name (setq path (expand-file-name
(string-trim (org-roam-capture--fill-template path t)) (string-trim (org-roam-capture--fill-template path t))
org-roam-directory)) org-roam-directory))
(org-roam-capture--create-parent-directory path)
(require 'org-datetree) (require 'org-datetree)
(widen) (widen)
(set-buffer (org-capture-target-buffer path)) (set-buffer (org-capture-target-buffer path))

View File

@ -33,7 +33,103 @@
;;; Code: ;;; Code:
;;;; Library Requires ;;;; Library Requires
;;; Backports
;; REVIEW Remove when 26.x support is dropped. This is exact the same as
;; `directory-files-recursively' from Emacs 26, but with FOLLOW-SYMLINKS
;; parameter from Emacs 27.
(defun org-roam--directory-files-recursively (dir regexp
&optional include-directories predicate
follow-symlinks)
"Return list of all files under directory DIR whose names match REGEXP.
This function works recursively. Files are returned in \"depth
first\" order, and files from each directory are sorted in
alphabetical order. Each file name appears in the returned list
in its absolute form.
By default, the returned list excludes directories, but if
optional argument INCLUDE-DIRECTORIES is non-nil, they are
included.
PREDICATE can be either nil (which means that all subdirectories
of DIR are descended into), t (which means that subdirectories that
can't be read are ignored), or a function (which is called with
the name of each subdirectory, and should return non-nil if the
subdirectory is to be descended into).
If FOLLOW-SYMLINKS is non-nil, symbolic links that point to
directories are followed. Note that this can lead to infinite
recursion."
(let* ((result nil)
(files nil)
(dir (directory-file-name dir))
;; When DIR is "/", remote file names like "/method:" could
;; also be offered. We shall suppress them.
(tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir)))))
(dolist (file (sort (file-name-all-completions "" dir)
'string<))
(unless (member file '("./" "../"))
(if (directory-name-p file)
(let* ((leaf (substring file 0 (1- (length file))))
(full-file (concat dir "/" leaf)))
;; Don't follow symlinks to other directories.
(when (and (or (not (file-symlink-p full-file))
(and (file-symlink-p full-file)
follow-symlinks))
;; Allow filtering subdirectories.
(or (eq predicate nil)
(eq predicate t)
(funcall predicate full-file)))
(let ((sub-files
(if (eq predicate t)
(condition-case nil
(org-roam--directory-files-recursively
full-file regexp include-directories
predicate follow-symlinks)
(file-error nil))
(org-roam--directory-files-recursively
full-file regexp include-directories
predicate follow-symlinks))))
(setq result (nconc result sub-files))))
(when (and include-directories
(string-match regexp leaf))
(setq result (nconc result (list full-file)))))
(when (string-match regexp file)
(push (concat dir "/" file) 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
'org-roam-dailies-find-today
'org-roam-dailies-goto-today "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-yesterday
'org-roam-dailies-goto-yesterday "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-tomorrow
'org-roam-dailies-goto-tomorrow "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-next-note
'org-roam-dailies-goto-next-note "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-previous-note
'org-roam-dailies-goto-previous-note "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-date
'org-roam-dailies-goto-date "org-roam 2.0")
;;; Obsolete functions ;;; Obsolete functions
(provide 'org-roam-compat) (provide 'org-roam-compat)

View File

@ -67,6 +67,8 @@ This path is relative to `org-roam-directory'."
:if-new (file+head "%<%Y-%m-%d>.org" :if-new (file+head "%<%Y-%m-%d>.org"
"#+title: %<%Y-%m-%d>\n"))) "#+title: %<%Y-%m-%d>\n")))
"Capture templates for daily-notes in Org-roam. "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." See `org-roam-capture-templates' for the template documentation."
:group 'org-roam :group 'org-roam
:type '(repeat :type '(repeat
@ -213,16 +215,17 @@ future."
(org-roam-dailies-capture-tomorrow (- n) t)) (org-roam-dailies-capture-tomorrow (- n) t))
;;; Calendar ;;; Calendar
(defun org-roam-dailies-calendar--file-to-date (&optional file) (defun org-roam-dailies-calendar--file-to-date (file)
"Convert FILE to date. "Convert FILE to date.
Return (MONTH DAY YEAR)." Return (MONTH DAY YEAR) or nil if not an Org time-string."
(let ((file (or file (condition-case nil
(buffer-base-buffer (buffer-file-name))))) (progn
(cl-destructuring-bind (_ _ _ d m y _ _ _) (cl-destructuring-bind (_ _ _ d m y _ _ _)
(org-parse-time-string (org-parse-time-string
(file-name-sans-extension (file-name-sans-extension
(file-name-nondirectory file))) (file-name-nondirectory file)))
(list m d y)))) (list m d y)))
(t nil)))
(defun org-roam-dailies-calendar--date-to-time (date) (defun org-roam-dailies-calendar--date-to-time (date)
"Convert DATE as returned from then calendar (MONTH DAY YEAR) to a time." "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 () (defun org-roam-dailies-calendar-mark-entries ()
"Mark days in the calendar for which a daily-note is present." "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)) (when (file-exists-p (expand-file-name org-roam-dailies-directory org-roam-directory))
(dolist (date (mapcar #'org-roam-dailies-calendar--file-to-date (dolist (date (remove nil
(org-roam-dailies--list-files))) (mapcar #'org-roam-dailies-calendar--file-to-date
(org-roam-dailies--list-files))))
(when (calendar-date-is-visible-p date) (when (calendar-date-is-visible-p date)
(calendar-mark-visible-date date 'org-roam-dailies-calendar-note))))) (calendar-mark-visible-date date 'org-roam-dailies-calendar-note)))))
@ -327,25 +331,6 @@ negative, find note N days in the future."
(define-key org-roam-dailies-map (kbd "v") #'org-roam-dailies-capture-date) (define-key org-roam-dailies-map (kbd "v") #'org-roam-dailies-capture-date)
(define-key org-roam-dailies-map (kbd ".") #'org-roam-dailies-find-directory) (define-key org-roam-dailies-map (kbd ".") #'org-roam-dailies-find-directory)
(define-obsolete-function-alias
'org-roam-dailies-find-today
'org-roam-dailies-goto-today "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-yesterday
'org-roam-dailies-goto-yesterday "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-tomorrow
'org-roam-dailies-goto-tomorrow "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-next-note
'org-roam-dailies-goto-next-note "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-previous-note
'org-roam-dailies-goto-previous-note "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-date
'org-roam-dailies-goto-date "org-roam 2.0")
(provide 'org-roam-dailies) (provide 'org-roam-dailies)
;;; org-roam-dailies.el ends here ;;; org-roam-dailies.el ends here

View File

@ -422,14 +422,23 @@ If UPDATE-P is non-nil, first remove the file in the database."
(save-excursion (save-excursion
(goto-char (org-element-property :begin link)) (goto-char (org-element-property :begin link))
(let ((type (org-element-property :type 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))) (properties (list :outline (org-get-outline-path)))
(source (org-roam-id-at-point))) (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 (org-roam-db-query
[:insert :into links [:insert :into links
:values $v1] :values $v1]
(vector (point) source dest type properties)))))) (mapcar (lambda (p)
(vector (point) source p type properties))
path))))))
;;;;; Fetching ;;;;; Fetching
(defun org-roam-db--get-current-files () (defun org-roam-db--get-current-files ()

View File

@ -51,7 +51,12 @@ for an overview of the major changes.
Notes taken in v1 are incompatible with v1, but you can upgrade Notes taken in v1 are incompatible with v1, but you can upgrade
them to the v2 format via a simple command. To migrate your 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 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) (message "Backing up files to %s" backup-dir)
(copy-directory org-roam-directory backup-dir)) (copy-directory org-roam-directory backup-dir))
;; Upgrade database to v2
(org-roam-db-sync 'force)
;; Convert v1 to v2 ;; Convert v1 to v2
(dolist (f (org-roam--list-all-files)) (dolist (f (org-roam--list-all-files))
(org-roam-with-file f nil (org-roam-with-file f nil
(org-roam-migrate-v1-to-v2))) (org-roam-migrate-v1-to-v2)))
;; Rebuild cache ;; Rebuild cache
(org-roam-db-sync 'force) (org-roam-db-sync 'force)
@ -115,18 +124,22 @@ This will take a while. Are you sure you want to do this?")
;; Replace roam_alias into properties drawer roam_aliases ;; Replace roam_alias into properties drawer roam_aliases
(when-let* ((aliases (mapcan #'split-string-and-unquote (when-let* ((aliases (mapcan #'split-string-and-unquote
(cdar (org-collect-keywords '("roam_alias")))))) (cdar (org-collect-keywords '("roam_alias"))))))
(let ((case-fold-search t)) (dolist (alias aliases)
(org-with-point-at 1 (org-roam-alias-add alias)))
(dolist (alias aliases) (let ((case-fold-search t))
(org-roam-alias-add alias)) (org-with-point-at 1
(while (re-search-forward "^#\\+roam_alias:" (point-max) t) (while (re-search-forward "^#\\+roam_alias:" (point-max) t)
(beginning-of-line) (beginning-of-line)
(kill-line 1))))) (kill-line 1))))
;; Replace #+roam_tags into #+filetags ;; Replace #+roam_tags into #+filetags
(org-with-point-at 1 (org-with-point-at 1
(let* ((roam-tags (org-roam-migrate-get-prop-list "ROAM_TAGS")) (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 (append roam-tags file-tags))
(tags (seq-map (lambda (tag) (tags (seq-map (lambda (tag)
(replace-regexp-in-string (replace-regexp-in-string
@ -135,7 +148,7 @@ This will take a while. Are you sure you want to do this?")
tag)) tags)) tag)) tags))
(tags (seq-uniq tags))) (tags (seq-uniq tags)))
(when 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)) (let ((case-fold-search t))
(org-with-point-at 1 (org-with-point-at 1
(while (re-search-forward "^#\\+roam_tags:" (point-max) t) (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) :where (= file $s1)
:and (= level 0)] path)))) :and (= level 0)] path))))
(set-match-data mdata) (set-match-data mdata)
(replace-match (org-link-make-string (concat "id:" node-id) desc)))))))) (replace-match (org-link-make-string (concat "id:" node-id)
desc) nil t)))))))
(provide 'org-roam-migrate) (provide 'org-roam-migrate)
;;; org-roam-migrate.el ends here ;;; org-roam-migrate.el ends here

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
@ -410,7 +443,7 @@ If ROW, move to the row, and if COL move to the COL."
"Return the preview line from FILE. "Return the preview line from FILE.
This is the ROW within FILE." This is the ROW within FILE."
(with-temp-buffer (with-temp-buffer
(insert-file-contents-literally file) (insert-file-contents file)
(forward-line (1- row)) (forward-line (1- row))
(buffer-substring-no-properties (buffer-substring-no-properties
(save-excursion (save-excursion

View File

@ -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. "Return t if FILE is part of Org-roam system, nil otherwise.
If FILE is not specified, use the current buffer's file-path." If FILE is not specified, use the current buffer's file-path."
(let* ((path (or file (buffer-file-name (buffer-base-buffer)))) (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") (ext (if (string= ext "gpg")
(org-roam--file-name-extension (file-name-sans-extension path)) (org-roam--file-name-extension (file-name-sans-extension path))
ext))) ext)))
(save-match-data (save-match-data
(and (and
path
(member ext org-roam-file-extensions) (member ext org-roam-file-extensions)
(not (and org-roam-file-exclude-regexp (not (and org-roam-file-exclude-regexp
(string-match-p org-roam-file-exclude-regexp path))) (string-match-p org-roam-file-exclude-regexp path)))
@ -216,67 +217,6 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
(command (s-join " " `(,executable "-L" ,dir "-type f \\(" ,names "\\)")))) (command (s-join " " `(,executable "-L" ,dir "-type f \\(" ,names "\\)"))))
(org-roam--shell-command-files command))) (org-roam--shell-command-files command)))
;; Emacs 26 does not have FOLLOW-SYMLINKS in `directory-files-recursively'
(defun org-roam--directory-files-recursively (dir regexp
&optional include-directories predicate
follow-symlinks)
"Return list of all files under directory DIR whose names match REGEXP.
This function works recursively. Files are returned in \"depth
first\" order, and files from each directory are sorted in
alphabetical order. Each file name appears in the returned list
in its absolute form.
By default, the returned list excludes directories, but if
optional argument INCLUDE-DIRECTORIES is non-nil, they are
included.
PREDICATE can be either nil (which means that all subdirectories
of DIR are descended into), t (which means that subdirectories that
can't be read are ignored), or a function (which is called with
the name of each subdirectory, and should return non-nil if the
subdirectory is to be descended into).
If FOLLOW-SYMLINKS is non-nil, symbolic links that point to
directories are followed. Note that this can lead to infinite
recursion."
(let* ((result nil)
(files nil)
(dir (directory-file-name dir))
;; When DIR is "/", remote file names like "/method:" could
;; also be offered. We shall suppress them.
(tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir)))))
(dolist (file (sort (file-name-all-completions "" dir)
'string<))
(unless (member file '("./" "../"))
(if (directory-name-p file)
(let* ((leaf (substring file 0 (1- (length file))))
(full-file (concat dir "/" leaf)))
;; Don't follow symlinks to other directories.
(when (and (or (not (file-symlink-p full-file))
(and (file-symlink-p full-file)
follow-symlinks))
;; Allow filtering subdirectories.
(or (eq predicate nil)
(eq predicate t)
(funcall predicate full-file)))
(let ((sub-files
(if (eq predicate t)
(condition-case nil
(org-roam--directory-files-recursively
full-file regexp include-directories
predicate follow-symlinks)
(file-error nil))
(org-roam--directory-files-recursively
full-file regexp include-directories
predicate follow-symlinks))))
(setq result (nconc result sub-files))))
(when (and include-directories
(string-match regexp leaf))
(setq result (nconc result (list full-file)))))
(when (string-match regexp file)
(push (concat dir "/" file) files)))))
(nconc result (nreverse files))))
(defun org-roam--list-files-elisp (dir) (defun org-roam--list-files-elisp (dir)
"Return all Org-roam files located recursively within DIR, using elisp." "Return all Org-roam files located recursively within DIR, using elisp."
(let ((regex (concat "\\.\\(?:"(mapconcat (let ((regex (concat "\\.\\(?:"(mapconcat
@ -352,7 +292,9 @@ If BUFFER is not specified, use the current buffer."
;;;###autoload ;;;###autoload
(defun org-roam-setup () (defun org-roam-setup ()
"Setup Org-roam." "Setup Org-roam and initialize its database.
This will install the needed hooks and advices to keep everything
in sync with the connected databases."
(interactive) (interactive)
(add-hook 'find-file-hook #'org-roam--file-setup) (add-hook 'find-file-hook #'org-roam--file-setup)
(add-hook 'kill-emacs-hook #'org-roam-db--close-all) (add-hook 'kill-emacs-hook #'org-roam-db--close-all)
@ -361,7 +303,10 @@ If BUFFER is not specified, use the current buffer."
(org-roam-db-sync)) (org-roam-db-sync))
(defun org-roam-teardown () (defun org-roam-teardown ()
"Teardown Org-roam." "Teardown Org-roam to completely disable it.
This will remove all the hooks and advices installed by
`org-roam-setup' and close all the database connections made by
Org-roam."
(interactive) (interactive)
(remove-hook 'find-file-hook #'org-roam--file-setup) (remove-hook 'find-file-hook #'org-roam--file-setup)
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all) (remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
@ -407,6 +352,7 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
;;;; Nodes ;;;; Nodes
(cl-defstruct (org-roam-node (:constructor org-roam-node-create) (cl-defstruct (org-roam-node (:constructor org-roam-node-create)
(:copier nil)) (:copier nil))
"A heading or top level file with an assigned ID property."
file file-hash file-atime file-mtime file file-hash file-atime file-mtime
id level point todo priority scheduled deadline title properties olp id level point todo priority scheduled deadline title properties olp
tags aliases refs) tags aliases refs)
@ -446,7 +392,7 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
(replace-regexp-in-string (car pair) (cdr pair) title))) (replace-regexp-in-string (car pair) (cdr pair) title)))
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric (let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
("__*" . "_") ;; remove sequential underscores ("__*" . "_") ;; remove sequential underscores
("^_" . "") ;; remove starting underscore ("^_" . "") ;; remove starting underscore
("_$" . ""))) ;; remove ending underscore ("_$" . ""))) ;; remove ending underscore
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs))) (slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
(downcase slug))))) (downcase slug)))))
@ -456,24 +402,26 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
(set-keymap-parent map org-roam-mode-map) (set-keymap-parent map org-roam-mode-map)
(define-key map [remap org-roam-visit-thing] 'org-roam-node-visit) (define-key map [remap org-roam-visit-thing] 'org-roam-node-visit)
map) map)
"Keymap for Org-roam node sections.") "Keymap for `org-roam-node-section's.")
(defclass org-roam-node-section (magit-section) (defclass org-roam-node-section (magit-section)
((keymap :initform 'org-roam-node-map) ((keymap :initform 'org-roam-node-map)
(node :initform nil))) (node :initform nil))
"A `magit-section' used by `org-roam-mode' to contain heading for NODE.")
(defvar org-roam-preview-map (defvar org-roam-preview-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(set-keymap-parent map org-roam-mode-map) (set-keymap-parent map org-roam-mode-map)
(define-key map [remap org-roam-visit-thing] 'org-roam-preview-visit) (define-key map [remap org-roam-visit-thing] 'org-roam-preview-visit)
map) map)
"Keymap for Org-roam preview.") "Keymap for `org-roam-preview-section's.")
(defclass org-roam-preview-section (magit-section) (defclass org-roam-preview-section (magit-section)
((keymap :initform 'org-roam-preview-map) ((keymap :initform 'org-roam-preview-map)
(file :initform nil) (file :initform nil)
(begin :initform nil) (point :initform nil))
(end :initform nil))) "A `magit-section' used by `org-roam-mode' to contain preview content.
The preview content comes from FILE, and the link as at POINT.")
(cl-defmethod org-roam-populate ((node org-roam-node)) (cl-defmethod org-roam-populate ((node org-roam-node))
"Populate NODE from database. "Populate NODE from database.
@ -521,11 +469,27 @@ nodes."
"${title:*} ${tags:10}" "${title:*} ${tags:10}"
"Configures display formatting for Org-roam node. "Configures display formatting for Org-roam node.
Patterns of form \"${field-name:length}\" are interpolated based Patterns of form \"${field-name:length}\" are interpolated based
on the current node. \"field-name\" is replaced with the on the current node.
corresponding value of the field of the current node. \"length\"
specifies how many characters are used to display the value of Each \"field-name\" is replaced with the return value of each
the field. A \"length\" of \"*\" specifies that as many corresponding accessor function for `org-roam-node', e.g.
characters as possible should be used." \"${title}\" will be interpolated by the result of
`org-roam-node-title'. You can also define custom accessors using
`cl-defmethod'. For example, you can define:
(cl-defmethod org-roam-node-my-title ((node org-roam-node))
(concat \"My \" (org-roam-node-title node)))
and then reference it here or in the capture templates as
\"${my-title}\".
\"length\" is an optional specifier and declares how many
characters can be used to display the value of the corresponding
field. If it's not specified, the field will be inserted as is,
i.e. it won't be aligned nor trimmed. If it's an integer, the
field will be aligned accordingly and all the exceeding
characters will be trimmed out. If it's \"*\", the field will use
as many characters as possible and will be aligned accordingly."
:group 'org-roam :group 'org-roam
:type 'string) :type 'string)
@ -565,17 +529,87 @@ Uses `org-roam-node-display-template' to format the entry."
(- width (cdr fmt))) (- width (cdr fmt)))
0 ?\s))))))) 0 ?\s)))))))
(defun org-roam-node-preview (file point) (defun org-roam-get-preview (file point)
"Get preview content for FILE at POINT." "Get preview content for FILE at POINT."
(save-excursion (save-excursion
(org-roam-with-temp-buffer file (org-roam-with-temp-buffer file
(goto-char point) (goto-char point)
(let* ((elem (org-element-at-point)) (let ((elem (org-element-at-point)))
(begin (org-element-property :begin elem)) ;; We want the parent element always
(end (org-element-property :end elem))) (while (org-element-property :parent elem)
(list begin end (setq elem (org-element-property :parent elem)))
(or (string-trim (buffer-substring-no-properties begin end)) (pcase (car elem)
(org-element-property :raw-value 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)))
(or (string-trim (buffer-substring-no-properties begin end))
(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) (defun org-roam-node-at-point (&optional assert)
"Return the node at point. "Return the node at point.
@ -609,7 +643,7 @@ populated."
buf)) buf))
(defun org-roam-node-visit (node &optional other-window) (defun org-roam-node-visit (node &optional other-window)
"From the buffer, visit NODE. "From the current buffer, visit NODE.
Display the buffer in the selected window. With a prefix Display the buffer in the selected window. With a prefix
argument OTHER-WINDOW display the buffer in another window argument OTHER-WINDOW display the buffer in another window
@ -649,7 +683,7 @@ Throw an error if multiple choices exist."
(user-error "Multiple nodes exist with title or alias \"%s\"" s))))) (user-error "Multiple nodes exist with title or alias \"%s\"" s)))))
(defun org-roam-node-list () (defun org-roam-node-list ()
"Return a list of all nodes." "Return all nodes stored in the database as a list of `org-roam-node's."
(let ((rows (org-roam-db-query (let ((rows (org-roam-db-query
"SELECT "SELECT
id, id,
@ -821,8 +855,8 @@ Returns empty string for annotations."
"Visit FILE at POINT. "Visit FILE at POINT.
With prefix argument OTHER-WINDOW, visit the olp in another With prefix argument OTHER-WINDOW, visit the olp in another
window instead." window instead."
(interactive (list (org-roam-file-at-point t) (interactive (list (org-roam-file-at-point 'assert)
(oref (magit-current-section) begin) (oref (magit-current-section) point)
current-prefix-arg)) current-prefix-arg))
(let ((buf (find-file-noselect file))) (let ((buf (find-file-noselect file)))
(with-current-buffer buf (with-current-buffer buf
@ -833,10 +867,25 @@ window instead."
#'pop-to-buffer-same-window) buf))) #'pop-to-buffer-same-window) buf)))
(cl-defun org-roam-node-insert-section (&key source-node point properties) (cl-defun org-roam-node-insert-section (&key source-node point properties)
"Insert section for NODE. "Insert section for a link from SOURCE-NODE to some other node.
SOURCE-NODE is the source node.
POINT is the point in buffer for the link. SOURCE-NODE is an `org-roam-node' that links or references some
PROPERTIES contains properties about the link." 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.
PROPERTIES (a plist) contains additional information about the
link.
This section is made out of the next 2 `magit-section's:
1. `org-roam-node-section' for a heading that describes
SOURCE-NODE.
2. `org-roam-preview-section' for a preview content that comes
from SOURCE-NODE's file for the link (that references the
other node) at POINT."
(magit-insert-section section (org-roam-node-section) (magit-insert-section section (org-roam-node-section)
(let ((outline (if-let ((outline (plist-get properties :outline))) (let ((outline (if-let ((outline (plist-get properties :outline)))
(mapconcat #'org-link-display-format outline " > ") (mapconcat #'org-link-display-format outline " > ")
@ -848,12 +897,11 @@ PROPERTIES contains properties about the link."
(magit-insert-heading) (magit-insert-heading)
(oset section node source-node) (oset section node source-node)
(magit-insert-section section (org-roam-preview-section) (magit-insert-section section (org-roam-preview-section)
(pcase-let ((`(,begin ,end ,s) (org-roam-node-preview (org-roam-node-file source-node) (insert (org-roam-fontify-like-in-org-mode
point))) (org-roam-get-preview (org-roam-node-file source-node) point))
(insert (org-roam-fontify-like-in-org-mode s) "\n") "\n")
(oset section file (org-roam-node-file source-node)) (oset section file (org-roam-node-file source-node))
(oset section begin begin) (oset section point point)
(oset section end end))
(insert ?\n)))) (insert ?\n))))
;;;###autoload ;;;###autoload
@ -873,9 +921,7 @@ If OTHER-WINDOW, visit the NODE in another window."
;;;###autoload ;;;###autoload
(defun org-roam-node-insert (&optional filter-fn) (defun org-roam-node-insert (&optional filter-fn)
"Find an Org-roam file, and insert a relative org link to it at point. "Find an Org-roam node and insert (where the point is) an \"id:\" link to it.
Return selected file if it exists.
If LOWERCASE is non-nil, downcase the link description.
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node', 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." and when nil is returned the node will be filtered out."
(interactive) (interactive)
@ -912,7 +958,7 @@ and when nil is returned the node will be filtered out."
;;;###autoload ;;;###autoload
(defun org-roam-node-random (&optional other-window) (defun org-roam-node-random (&optional other-window)
"Find a random Org-roam node. "Find and open a random Org-roam node.
With prefix argument OTHER-WINDOW, visit the node in another With prefix argument OTHER-WINDOW, visit the node in another
window instead." window instead."
(interactive current-prefix-arg) (interactive current-prefix-arg)
@ -923,22 +969,24 @@ window instead."
other-window))) other-window)))
;;;; Properties ;;;; Properties
(defun org-roam-add-property (s prop) (defun org-roam-add-property (val prop)
"Add S to property PROP." "Add VAL value to PROP property for the node at point.
Both, VAL and PROP are strings."
(let* ((p (org-entry-get (point) prop)) (let* ((p (org-entry-get (point) prop))
(lst (when p (split-string-and-unquote p))) (lst (when p (split-string-and-unquote p)))
(lst (if (memq s lst) lst (cons s lst))) (lst (if (memq val lst) lst (cons val lst)))
(lst (seq-uniq lst))) (lst (seq-uniq lst)))
(org-set-property prop (combine-and-quote-strings lst)) (org-set-property prop (combine-and-quote-strings lst))
s)) val))
(defun org-roam-remove-property (prop &optional s) (defun org-roam-remove-property (prop &optional val)
"Remove S from property PROP. "Remove VAL value from PROP property for the node at point.
Both VAL and PROP are strings.
If S is not specified, user is prompted to select a value." If VAL is not specified, user is prompted to select a value."
(let* ((p (org-entry-get (point) prop)) (let* ((p (org-entry-get (point) prop))
(lst (when p (split-string-and-unquote p))) (lst (when p (split-string-and-unquote p)))
(prop-to-remove (or s (completing-read "Remove: " lst))) (prop-to-remove (or val (completing-read "Remove: " lst)))
(lst (delete prop-to-remove lst))) (lst (delete prop-to-remove lst)))
(if lst (if lst
(org-set-property prop (combine-and-quote-strings lst)) (org-set-property prop (combine-and-quote-strings lst))
@ -1093,9 +1141,7 @@ REF is assumed to be a propertized string."
;;;###autoload ;;;###autoload
(defun org-roam-ref-find (&optional initial-input filter-fn) (defun org-roam-ref-find (&optional initial-input filter-fn)
"Find and open and Org-roam file from REF if it exists. "Find and open an Org-roam node that's dedicated to a specific ref.
REF should be the value of '#+roam_key:' without any
type-information (e.g. 'cite:').
INITIAL-INPUT is the initial input to the prompt. INITIAL-INPUT is the initial input to the prompt.
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node', 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." and when nil is returned the node will be filtered out."
@ -1106,7 +1152,7 @@ and when nil is returned the node will be filtered out."
;;;; roam: link ;;;; roam: link
(defcustom org-roam-link-auto-replace t (defcustom org-roam-link-auto-replace t
"When non-nil, replace Org-roam's roam links with file or id links whenever possible." "If non-nil, replace \"roam:\" links to existing nodes with \"id:\" links."
:group 'org-roam :group 'org-roam
:type 'boolean) :type 'boolean)
@ -1114,7 +1160,7 @@ and when nil is returned the node will be filtered out."
(org-link-set-parameters "roam" :follow #'org-roam-link-follow-link) (org-link-set-parameters "roam" :follow #'org-roam-link-follow-link)
(defun org-roam-link-replace-at-point (&optional link) (defun org-roam-link-replace-at-point (&optional link)
"Replace the roam: LINK at point with an id link." "Replace \"roam:\" LINK at point with an \"id:\" link."
(save-excursion (save-excursion
(save-match-data (save-match-data
(let* ((link (or link (org-element-context))) (let* ((link (or link (org-element-context)))
@ -1143,23 +1189,21 @@ and when nil is returned the node will be filtered out."
(add-hook 'org-roam-find-file-hook #'org-roam--replace-roam-links-on-save-h) (add-hook 'org-roam-find-file-hook #'org-roam--replace-roam-links-on-save-h)
(defun org-roam-link-follow-link (path) (defun org-roam-link-follow-link (title-or-alias)
"Org-roam's roam: link navigation with description PATH. "Navigate \"roam:\" link to find and open the node with TITLE-OR-ALIAS.
This function is called by Org when following links of the type Assumes that the cursor was put where the link is."
`roam'. While the path is passed, assume that the cursor is on (if-let ((node (org-roam-node-from-title-or-alias title-or-alias)))
the link."
(if-let ((node (org-roam-node-from-title-or-alias path)))
(progn (progn
(when org-roam-link-auto-replace (when org-roam-link-auto-replace
(org-roam-link-replace-at-point)) (org-roam-link-replace-at-point))
(org-id-goto (org-roam-node-id node))) (org-id-goto (org-roam-node-id node)))
(org-roam-capture- (org-roam-capture-
:node (org-roam-node-create :title path) :node (org-roam-node-create :title title-or-alias)
:props '(:finalize find-file)))) :props '(:finalize find-file))))
(defun org-roam-open-id-at-point () (defun org-roam-open-id-at-point ()
"Navigates to the ID at point. "Try to navigate \"id:\" link to find and visit node with an assigned ID.
To be added to `org-open-at-point-functions'." Assumes that the cursor was put where the link is."
(let* ((context (org-element-context)) (let* ((context (org-element-context))
(type (org-element-property :type context)) (type (org-element-property :type context))
(id (org-element-property :path context))) (id (org-element-property :path context)))
@ -1173,7 +1217,7 @@ To be added to `org-open-at-point-functions'."
(t nil)))))) (t nil))))))
(defun org-roam-open-id-with-org-roam-db-h () (defun org-roam-open-id-with-org-roam-db-h ()
"." "Try to open \"id:\" links at point by querying them to the database."
(add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point nil t)) (add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point nil t))
(add-hook 'org-roam-find-file-hook #'org-roam-open-id-with-org-roam-db-h) (add-hook 'org-roam-find-file-hook #'org-roam-open-id-with-org-roam-db-h)
@ -1200,7 +1244,8 @@ Any top level properties drawers are incorporated into the new heading."
(org-roam--file-keyword-kill "FILETAGS"))) (org-roam--file-keyword-kill "FILETAGS")))
(defun org-roam-refile () (defun org-roam-refile ()
"Refile to node." "Refile node at point to an Org-roam node.
If region is active, then use it instead of the node at point."
(interactive) (interactive)
(let* ((regionp (org-region-active-p)) (let* ((regionp (org-region-active-p))
(region-start (and regionp (region-beginning))) (region-start (and regionp (region-beginning)))