Compare commits

..

87 Commits

Author SHA1 Message Date
2ff616fbd8 release 2.3.0 2025-05-24 23:06:32 -07:00
046822b512 Bump DB version to avoid error 2025-03-24 14:40:44 -07:00
cce9591c1c keep OLP data in node properties
Not all links to a node come from another node.  Persisting OLP data
allows us to build backlinks with information about these non-node
headings.

Revert: db4170a459.
2025-03-23 17:20:13 -07:00
db4170a459 (perf): Deprecate link :outline properties
As it happens, turning sexps into strings is one of the
computationally expensive steps in EmacSQL.

With an enormous number of links in the database, that's a lot
of (:outline nil) to stringify into "(:outline nil)".

Its only use was in org-roam-node-insert-section,
where the information is very cheap to reconstruct.
It's already in one of the other arguments!

This has passed unnoticed because org-roam-db-sync has other
performance tarpits, but it will probably be noticed eventually after
those get fixed.
2025-03-12 18:34:24 -07:00
0037daaf3e docs: update caching docs
Now that emacsql handles choosing an appropriate backend/connector, we
do not need to provide these instructions.  If there are issues, emacsql
has good error messages that tell the user what they need to do to get
things working.

In general:
  - If the user is on Emacs >= 29, emacsql will use the built-in sqlite
    functionality that comes with Emacs.
  - If the user is on Emacs < 29, emacsql will use a module-based
    connector that requires the user to have certain libraries available
    on their machine.  emacsql will tell the user what is needed if they
    do not have it already.

Ref: #2486
Close: #2502
Close: #2415
2025-02-18 09:22:30 -08:00
888b5d1a67 Set org-roam-directory to a non-existent path to ensure robust test
* In some rare case, the first expect of org-roam-file-p may return t
when running in some environment (e.g. during autopkgtest in Debian).
* Setting org-roam-directory to a non-existent path ensure that the
first check is always nil as expected.
2025-02-18 08:58:24 -08:00
ed272eaf56 Address compiler warnings
Depend on Org 9.6 for `org-fold-show-context'.
2025-02-18 08:56:35 -08:00
551ff3b17e Use org-fold-show-context instead of obsolete function alias
To avoid having to create a wrapper function and silence the byte-
compiler for both when using a pre-rename and post-rename Org, keep
it simple and just depend on Org 9.6.
2025-02-18 08:56:35 -08:00
719594dfc7 org-roam-db: Don't unnecessarily enable foreign keys support
Starting with EmacSQL v4.1.0, `emacsql-sqlite-open' takes care of that.
2025-02-18 08:56:35 -08:00
b4b8d8c0ee (fix): fix error message 2025-02-18 08:56:35 -08:00
0d51698839 Rely on emacsql-sqlite-open to pick the best available back-end
That function was added two years ago and the first release that
provided it was v4.0.0.  It automatically picks the best available
back-end, `emacsql-sqlite-builtin' or `emacsql-sqlite-module'.
In v4.0.0 it could also fall back to the legacy `emacsql-sqlite'.
The inferior third-party back-ends are no longer supported.

Emacsql v4.1.0, which will be releases in early December, removes
the legacy `emacsql-sqlite' back-end (which used a custom binary).
2025-02-18 08:56:35 -08:00
7dc76b708b fix(db): Org-roam does not store Org-ID w/ search option
add `:search-option` property to the `link` table when present.

Fix: #2495
Close: #2496
2025-02-17 13:51:29 -08:00
f3db974bcc fix #2425
(kill-whole-line) kills folded text if called from column 1
Make sure to unfold text before calling it --
Prevents data loss if user has decided to extract subtree on a folded org headline.
2025-02-17 13:36:45 -08:00
bb08be4740 refactor!: do not include time zone in org iso8601
org mode timestamps do not support time zones, so returning the
machine's local time zone is misleading.

Also, org-format-time-string is an obsolete alias of format-time-string.

Ref: cc2490a706
2025-02-17 12:48:43 -08:00
2490afe110 refactor: remove emacsql-sqlite backend option
This option is no longer supported in emacsql 4.0 and was throwing
linter errors in CI.

Ref: 7a79c2be3d
2025-02-17 12:48:43 -08:00
40b6c10d8a nit: formatting update
My editor reformatted some of the identation.  Also corrected a
docstring for org-roam-refile.
2025-02-17 12:48:43 -08:00
425d53d56d Use regexp match to replace hard-coded path equal test (#2497)
Hard-coded paths cause the tests to fail when building under different
environments, e.g. under Debian sbuild it fails with the following
errors:

,----
| ========================================
| org-roam-id-find finds the correct file node
| FAILED: Expected `(car location)' to be `equal' to `"/home/runner/work/org-roam/org-roam/tests/roam-files/foo.org"', but instead it was `"/build/reproducible-path/org-roam-2.2.2+git20250105.cad3518/tests/roam-files/foo.org"' which does not match because: (arrays-of-different-length 84 60 "/build/reproducible-path/org-roam-2.2.2+git20250105.cad3518/tests/roam-files/foo.org" "/home/runner/work/org-roam/org-roam/tests/roam-files/foo.org" first-mismatch-at 1).
|
| ========================================
| org-roam-id-find finds the correct heading node
| FAILED: Expected `(car location)' to be `equal' to `"/home/runner/work/org-roam/org-roam/tests/roam-files/family.org"', but instead it was `"/build/reproducible-path/org-roam-2.2.2+git20250105.cad3518/tests/roam-files/family.org"' which does not match because: (arrays-of-different-length 87 63 "/build/reproducible-path/org-roam-2.2.2+git20250105.cad3518/tests/roam-files/family.org" "/home/runner/work/org-roam/org-roam/tests/roam-files/family.org" first-mismatch-at 1).
|
| Ran 41 specs, 2 failed, in 980.31ms.
| buttercup-run failed: ""
`----
2025-01-11 10:55:35 -05:00
64e302c126 Depend on emacsql 4.0.0 (#2466)
See https://github.com/magit/emacsql/issues/113.  Emacsql 4.0.0 has
been released and should now be used in the package-requires header.
2025-01-10 21:52:11 -05:00
cad3518788 (fix): advise org-id-find rather than overwriting id link (#2432)
There have been recent changes in org-mode to improve `org-id-open' to
be able to apply search strings in id: links.  But, org-roam overrides
the `:follow` parameter for id: links to its own `org-roam-id-open'
function and therefore misses this.

The only change that `org-roam-id-open' makes is to try calling
`org-roam-id-find' before falling back on `org-id-find'.  This commit
uses advice to do this directly, thereby integrating better with
`org-id-open'.

There was some discussion on the org-mode list about adding a custom
variable to avoid using advice, but this accomplishes the result
without requiring changes in org:

https://list.orgmode.org/87jzlxjiuf.fsf@localhost/
2025-01-04 20:43:23 -08:00
2a630476b3 Take node as argument to #'org-roam-refile (#2388) 2024-10-07 19:04:46 +02:00
9fd7c87b5b Update org-roam.org (#2475)
Fix formatting for 2 code objects.
2024-09-17 19:40:37 +02:00
0b9fcbc97b (test): add org-roam-db-get-{scheduled|deadline}-time (#2465) 2024-07-16 22:35:22 +02:00
e415610b05 (test): add org-roam-db--file-hash (#2464) 2024-07-16 21:57:42 +02:00
3e186a8552 (fix): remove dead-code about org-roam-shield feature (#2462)
As described in https://github.com/org-roam/org-roam/issues/2348,
the `org-roam-shield-region` function is not called anymore.

The reverse function and associated face can also be removed.

Fix: #2348
2024-07-15 19:50:52 +02:00
0b2218706d (test): add org-roam-buffer-p (#2461) 2024-07-15 19:20:18 +02:00
84334b7e16 (test): add org-roam-file-p (#2460) 2024-07-15 18:37:15 +02:00
3c52d581ae (test): add org-roam-demote-entire-buffer (#2459) 2024-07-14 15:52:49 +02:00
fdd834d9bf (docs): explain org-roam-file-exclude-regexp (#2458) 2024-07-14 10:15:41 +02:00
8e6938a39d (docs): add missing versions dates and obsolete notice (#2456) 2024-07-08 20:50:41 +02:00
a753ec097d (test): add org-roam-alias-{add|remove} (#2455) 2024-07-08 19:29:24 +02:00
43a5362ada (test): add org-roam-node-from-{id|title-or-alias} (#2454) 2024-07-08 18:59:53 +02:00
a432539121 (test): add org-roam--get-titles (#2453) 2024-07-07 17:18:20 +02:00
1ce760ccc7 (test): add org-roam--buffer-promoteable-p (#2452) 2024-07-07 16:54:41 +02:00
76df9d1f3c (test): add org-roam-id-at-point (#2451) 2024-07-07 15:41:00 +02:00
74d714f789 (test): add org-roam-id-find (#2450) 2024-07-03 23:18:18 +02:00
6644cb27a9 (feat): allow a custom heading for a backlinks section (#2333)
Allow the user to set a custom heading for a backlinks section in the org-roam buffer
2024-07-03 20:56:42 +02:00
94b826d759 (feat): extract rg-command builder function from unlinked-references (#2449)
* (test): add "org-roam--list-files-search-globs"

* (feat): extract rg-command builder function from unlinked-references

Users can now advice this command to tweak the flag pased to ripgrep.
The current one have been expanded to long-form.

It's a follow up to the fix about shell quoting

* (docs): update CHANGELOG
2024-07-03 19:26:03 +02:00
edccf9be84 (fix): org-roam-directory having spaces and Unlinked References not working (#2411)
Co-authored-by: Vikram Mandyam <vicky08@gmail>
2024-07-03 18:38:15 +02:00
aa64cc9596 (chore): fix indent blocking ci lint execution (#2448)
This mix of tabs and spaces was introduced recently in:
2e94f55cc5
2024-07-02 17:56:56 +02:00
e93c77f6a5 (docs): add details about org-roam-protocol with Homebrew (#2441)
Add additional information for setting up org-roam-protocol on Mac OS when using emacs installed from Homebrew (see also https://org-roam.discourse.group/t/problem-with-org-roam-protocol/3473)
2024-07-01 19:50:40 +02:00
2d1c5d78e8 Link Martin Edström's knowledge base (#2394) 2024-07-01 19:46:07 +02:00
f8b40a3109 (docs): fix name of my-org-roam-show-backlink-p (#2447)
Fix: #2392
2024-07-01 18:33:56 +02:00
7fdc7150cc Fix some typos (#2430) 2024-07-01 08:39:57 +02:00
8667e44187 (docs): update org-protocol instructions (#2401) 2024-01-14 11:42:08 -08:00
2e94f55cc5 (node) add optional NOCASE parameter to org-roam-node-from-title-or-alias (#2403)
* (node) add NOCASE parameter to org-roam-node-from-title-or-alias

* fixed docstring of org-roam-node-from-title-or-alias.
2024-01-14 11:41:46 -08:00
5c06471c3a (node): org-roam-node-at-point: don't error in non-org buffers (#2329)
`=' assumes that both objects being compared are numbers. In some
buffers `outline-level' can return nil, so `=' returns an error. `eq'
does not assume this, but does return t when comparing two numbers.
2023-03-07 09:21:01 -08:00
b5436f3410 depend on snapshot of emacsql (#2327) 2023-03-05 09:20:26 -08:00
f7dc81e494 Fix org-fold-core-style in org-roam-buffer (#2325) 2023-03-05 09:20:07 -08:00
e73807efe1 Add customisable function for prompting when adding refs (#2317)
* (node): new custom `org-roam-ref-prompt-function'

Function for prompting when adding a ref.

* (node): use `org-roam-ref-prompt' in `org-roam-ref-add'

Prompt properly for ref.
2023-02-23 14:45:37 +08:00
1981dc3617 utils: descendant-of-p: Defend against nils (#2319)
This has an effect on find-file-hook for totally unrelated files,
through the callchain of `org-roam-db-autosync--setup-file-h ->
org-roam-file-p -> org-roam-descendant-of-p'.

From an org file, inside a project-el project, (find-file
"some/other/file") will intermittently reproduce this error:

   org-roam-descendant-of-p: Wrong type argument: arrayp, nil

If this fix seems inappropriate -- it could amount to surppressing a
valid error in routine calls -- then I would advise throwing an
explicit signal here, or finding a safer way to get the `path` inside
`org-roam-file-p'; the current means:

    (or file (buffer-file-name (buffer-base-buffer)))

.. can result in nil, which then bleeds errors into use elsewhere.

for posterity, here is the full calling context I'm referring to, from
`org-roam-file-p'.

  (let* ((path (or file (buffer-file-name (buffer-base-buffer))))
         (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))
         (org-roam-dir-p (org-roam-descendant-of-p path
         org-roam-directory))
         ...
2023-02-23 14:43:47 +08:00
7d2f511251 (minor): fix lints on main (#2320) 2023-02-23 14:42:35 +08:00
74422df546 add discoverability support for age encrypted org files (#2302) 2022-12-31 13:22:30 -08:00
938c602faa (core): add org-roam-node-category (#2300) 2022-12-26 18:19:51 -08:00
45a6863e07 (completions): don't complete org-roam nodes in source blocks (#2292)
* don't complete org-roam nodes in source blocks

This fixes the following situation where
`org-roam-completion-everywhere = t` and you are working with org-babel
blocks in one of your org-roam nodes.

```
```

Before my nodes would be suggested, but after this change only valid
babel headers are suggested as desired.

Previously completions from org-roam nodes would be suggested

* fix lints

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2022-12-25 10:39:30 -08:00
cdad2ee7f6 (db): default to sqlite-builtin when available (#2299) 2022-12-25 10:25:55 -08:00
256fe73e7a (docs): update documentation on database-connectors (#2298)
Update docs to reflect sqlite-bulitin and sqlite-module
2022-12-24 10:50:01 -08:00
f9228ce319 (feat): add support for filtering backlinks. (#2247)
* Add support for filtering backlinks.

See #1043.

* Add documentation for backlinks filter
2022-12-04 19:55:47 -08:00
Eli
25c476791e (fix): update org-roam-unlinked-references-section check (#2254)
`org-roam-unlinked-references-section` would get nil org-roam-node-title
when create a headline node, which caused the issue #1625. This commit
add a check to make `org-roam-unlinked-references-section` work
correctly.
2022-12-03 09:50:01 -08:00
78ee5c6814 (fix):fill outline of link in properties (#2230) 2022-12-03 09:49:23 -08:00
apc
3add6748ae Minor typo in the commented text of the definition of org-roam-refile (#2263) 2022-12-02 00:17:10 -08:00
e418037991 (docs):orgmode.org/elpa has been shut down (#2258)
See https://list.orgmode.org/87blb3epey.fsf@gnu.org/ for details.
Removed it from the documentation in the manual to (try and) assist newcomers.
2022-12-02 00:16:42 -08:00
05f67901c6 (feat):support multi-line org titles (#2264)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2022-12-02 00:16:11 -08:00
c2e852e102 (feat)org-roam-tag-add: use tags separator as crm-separator (#2282)
Allows use of : in minibuffer to separate multiple selected tags.
2022-12-01 23:57:41 -08:00
4e6f934690 (fix)refs:support spaces in links (#2285)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2022-12-01 23:55:04 -08:00
d95d25615e (Docs): Fixed typos in the docs (#2256)
* Fix typo

* Fix typo

* Fix typo
2022-09-08 09:25:56 -07:00
7f453f3fff (fix)promote: promote all metadata to file level (#2246)
Without specifying `t`, it is only pushing the PROPERTIES drawer up  to
the file level, missing any other "planning information, clocking lines and
any kind of drawer." We want to promote all of this to the file level.
2022-08-03 21:37:36 -07:00
e435581215 (fix): remove use of deprecated org-font-lock-ensure (#2238) 2022-07-23 13:58:47 -07:00
nth
917a325dd9 (fix): links not displayed properly in org-roam-buffer (#2236)
Closes #2228.
2022-07-23 08:47:08 -07:00
c386761914 (fix): autoload org-roam-list-files (#2226) 2022-06-20 22:27:01 -07:00
171a8db32f (db)fix: file modification detection failing in some edge cases (#2221)
One example of an edge case:

- If a file has LF line endings,
- and is situated in a repository where .editorconfig asks for
  CRLF,
  (Such repositories exist, for example
  <https://github.com/obsidianmd/obsidian-docs/>.)
- and editorconfig-mode is enabled,

org-roam-db--file-hash would then return different results depending
on whether the file path is passed to it or not.

While this is a contrived edge case, there may be other cases like
this where the data from insert-file-contents-literally and the data
from find-file-noselect makes secure-hash return different values.

This commit removes the branch in org-roam-db--file-hash to compute
the hash based on buffer content, instead making it always require a
file path.

(This commit also allows org-roam-db-insert-file to take an optional
HASH argument, allowing it to avoid recalculating the hash.)

Since now we always compute the hash with the file on disk, the
special case for encrypted files is no longer needed.

This should have no impact on whether db is synchronized. The only
case when db--file-hash uses the "calculate in current buffer" path is
in db-insert-file; the only use of db-insert-file is in
db-update-file, which already calls db--file-hash with the file path,
and does not rely on the value from the current buffer.
2022-06-13 16:01:56 -07:00
bbac208fda (feat): org-roam-property-* code duplication removed (#2217) (#2218)
Co-authored-by: Chris Langhans <chris@langhans-coding.de>
2022-06-10 17:08:25 -07:00
fcefc1b1b4 (db)fix: FOREIGN KEY error in narrowed buffer (#2215)
When trying to save from a narrowed buffer, only the Roam nodes visible
in the narrowed buffer are written to the database.

This commit ensures that org-roam behaves the same whether the current
buffer is narrowed or not.
2022-06-08 09:21:13 -07:00
0cd9b9e6d3 (fix)completion: ensure unique ref candidates (#2208)
Add invisible id to candidate strings to ensure each candidate is
unique, and completing-read doesn't get confused about which one to open.

Fix #2207
2022-06-05 13:53:29 -07:00
83a0b3d464 (db)fix: org-roam-db-connector group (#2209) 2022-05-28 12:37:47 -07:00
ed7d4f0a2e (feat): support custom minibuffer matching function in org-roam-node-find (#2177) 2022-05-27 20:21:44 -07:00
32557afdbf (chore)ci: /s/master/main (#2204) 2022-05-25 14:19:11 -07:00
f144941dfb (fix)capture: respect blank lines in capture templates (#2203) 2022-05-25 11:57:17 -07:00
01843a6486 (chore): reapply #2178 (#2197) 2022-05-16 09:40:37 -07:00
1f51ec91d5 (node): fix org-roam-node-at-point check (#2195)
org-roam-node-at-point returned the wrong value if point-min is a
level-1 heading node. We make sure that everytime we go up one
heading, the outline-level changes (reduces by 1) to prevent this error.
2022-05-15 16:51:38 -07:00
2657f0b444 Fix org-roam-extract-subtree (#2191)
* Fix undefined incf.

Calling org-roam-extract-subtree failes with "Symbol’s function definition is void: incf"

org-roam.el includes cl-lib. org-roam--h1-count uses a bare incf call, which is undefined. Fix this by using cl-incf.

* Save buffer before promoting it.

After fixing incf in 8ec2e59e67, org-roam-extract-subtree still fails. 

The error is now: org-roam-db--file-hash: Opening input file: No such file or directory,...

The buffer with the newly created content is still unsaved at this time, so save it before calling (org-roam-promote-entire-buffer)

Caveat is we now save the buffer two times, before and after promoting it.
2022-05-12 09:34:53 -07:00
455f139d3e Revert "(fix)db: update atime on file access (#2174)"
This reverts commit b2d9543fa2.
2022-05-11 22:19:05 -07:00
b2d9543fa2 (fix)db: update atime on file access (#2174)
Previously we only updated the database on file save, but we need to
update the file's atime on file access, so we hook into `find-file-hook`
to do so. We only update the file atime if the file exists in the file table.
2022-05-11 15:39:49 -07:00
c0871c42be (fix) org-roam-file-p handle opening a buffer with no path (#2185)
reapply #2169
2022-05-07 17:19:48 -07:00
007e76725c (chore) fix version numbers (#2182) 2022-05-03 18:06:55 -07:00
5483e65d5a (fix)org-roam-file-p: don't exclude org-roam-directory (#2178)
* (fix)org-roam-file-p: don't exclude org-roam-directory

Don't exlude the org-roam-directory even if it matches
org-roam-file-exclude-regexp.

Should fix [#2165].

* Refactor PR #2178

Refactor PR #2178 to avoid recalculating (file-relative-name path
org-roam-directory) multiple timess.
2022-05-02 09:12:28 -07:00
b63ff2a7bb (chore): remove extraneous changelog line (#2172) 2022-04-24 18:44:58 -07:00
e8b4822a85 (perf)node-read: filter before map to candidate (#2168) 2022-04-24 17:12:22 -07:00
34 changed files with 1169 additions and 851 deletions

View File

@ -4,7 +4,7 @@ name: "Docs"
on: on:
push: push:
branches: branches:
- master - main
jobs: jobs:
build: build:

View File

@ -28,7 +28,7 @@ on:
pull_request: pull_request:
push: push:
branches: branches:
- master - main
jobs: jobs:
build: build:
@ -36,7 +36,11 @@ jobs:
strategy: strategy:
matrix: matrix:
emacs_version: emacs_version:
- 27.1 # REVIEW: we do not yet have the bootstrapping in place to test
# versions of emacs without built-in sqlite (pre 29.1)
# - 27.2
# - 28.2
- 29.4
- snapshot - snapshot
steps: steps:
- uses: purcell/setup-emacs@master - uses: purcell/setup-emacs@master

View File

@ -1,5 +1,87 @@
# Changelog # Changelog
## 2.2.2
## 2.3.0 (2025-05-24)
* (perf)node-read: filter before map to candidate by @russmatney in https://github.com/org-roam/org-roam/pull/2168
* (chore): remove extraneous changelog line by @jethrokuan in https://github.com/org-roam/org-roam/pull/2172
* (fix)org-roam-file-p: don't exclude org-roam-directory by @toregilhk in https://github.com/org-roam/org-roam/pull/2178
* (chore) fix version numbers by @jethrokuan in https://github.com/org-roam/org-roam/pull/2182
* (fix) org-roam-file-p handle opening a buffer with no path by @jethrokuan in https://github.com/org-roam/org-roam/pull/2185
* (fix)db: update atime on file access by @jethrokuan in https://github.com/org-roam/org-roam/pull/2174
* Fix org-roam-extract-subtree by @ralfdoering in https://github.com/org-roam/org-roam/pull/2191
* (node): fix org-roam-node-at-point check by @jethrokuan in https://github.com/org-roam/org-roam/pull/2195
* (chore): reapply #2178 by @jethrokuan in https://github.com/org-roam/org-roam/pull/2197
* Solved issue #2192 (Respect blank lines in capture templates) by @alopezrivera in https://github.com/org-roam/org-roam/pull/2203
* (chore)ci: /s/master/main by @jethrokuan in https://github.com/org-roam/org-roam/pull/2204
* support custom minibuffer matching function by @cuttlefisch in https://github.com/org-roam/org-roam/pull/2177
* (db)fix: org-roam-db-connector group by @jethrokuan in https://github.com/org-roam/org-roam/pull/2209
* ensure unique candidates in `org-roam-ref-find` by @bdarcus in https://github.com/org-roam/org-roam/pull/2208
* (db)fix: FOREIGN KEY error in narrowed buffer by @psii in https://github.com/org-roam/org-roam/pull/2215
* (feat): org-roam-property-* code duplication removed (#2217) by @clanghans in https://github.com/org-roam/org-roam/pull/2218
* (db)fix: file modification detection failing in some edge cases by @kisaragi-hiu in https://github.com/org-roam/org-roam/pull/2221
* (fix): autoload org-roam-list-files by @jethrokuan in https://github.com/org-roam/org-roam/pull/2226
* (fix): links not displayed properly in org-roam-buffer by @ntharim in https://github.com/org-roam/org-roam/pull/2236
* (fix): remove use of deprecated org-font-lock-ensure by @jethrokuan in https://github.com/org-roam/org-roam/pull/2238
* was missing the FULL parameter to `org-end-of-meta-data` - fixes #2242 by @jmay in https://github.com/org-roam/org-roam/pull/2246
* (Docs): Fixed typos in the docs by @hnvy in https://github.com/org-roam/org-roam/pull/2256
* Fix space chars in roam refs by @hwiorn in https://github.com/org-roam/org-roam/pull/2285
* org-roam-tag-add: use tags separator as crm-separator by @Hugo-Heagren in https://github.com/org-roam/org-roam/pull/2282
* Support multi-line org titles by @FelixBrendel in https://github.com/org-roam/org-roam/pull/2264
* (Docs): orgmode.org/elpa has been shut down by @aviad in https://github.com/org-roam/org-roam/pull/2258
* Minor typo in the commented text of the definition of `org-roam-refile` by @apc in https://github.com/org-roam/org-roam/pull/2263
* fix outline of link in properties by @bhuztez in https://github.com/org-roam/org-roam/pull/2230
* (fix): update `org-roam-unlinked-references-section` check by @Elilif in https://github.com/org-roam/org-roam/pull/2254
* Add support for filtering backlinks. by @swflint in https://github.com/org-roam/org-roam/pull/2247
* (docs): update documentation on database-connectors by @jethrokuan in https://github.com/org-roam/org-roam/pull/2298
* (db): default to sqlite-builtin when possible by @jethrokuan in https://github.com/org-roam/org-roam/pull/2299
* don't complete org-roam nodes in source blocks by @ParetoOptimalDev in https://github.com/org-roam/org-roam/pull/2292
* (core): add org-roam-node-category by @jethrokuan in https://github.com/org-roam/org-roam/pull/2300
* add discoverability support for age encrypted org files by @anticomputer in https://github.com/org-roam/org-roam/pull/2302
* (minor): fix lints on main by @jethrokuan in https://github.com/org-roam/org-roam/pull/2320
* utils: descendant-of-p: Defend against nils by @qzdl in https://github.com/org-roam/org-roam/pull/2319
* Add customisable function for prompting when adding refs by @Hugo-Heagren in https://github.com/org-roam/org-roam/pull/2317
* Fix org-fold-core-style in org-roam-buffer by @hwiorn in https://github.com/org-roam/org-roam/pull/2325
* depend on snapshot of emacsql by @jethrokuan in https://github.com/org-roam/org-roam/pull/2327
* (node): org-roam-node-at-point: don't error in non-org buffers by @Hugo-Heagren in https://github.com/org-roam/org-roam/pull/2329
* (node) add optional NOCASE parameter to org-roam-node-from-title-or-alias by @nuthub in https://github.com/org-roam/org-roam/pull/2403
* (docs): update org-protocol instructions by @benthamite in https://github.com/org-roam/org-roam/pull/2401
* Fix some typos by @feltcat in https://github.com/org-roam/org-roam/pull/2430
* (docs): fix name of my-org-roam-show-backlink-p by @Delapouite in https://github.com/org-roam/org-roam/pull/2447
* Link Martin Edström's knowledge base by @meedstrom in https://github.com/org-roam/org-roam/pull/2394
* Update org-roam.org by @marcosbodio in https://github.com/org-roam/org-roam/pull/2441
* (chore): fix indent blocking ci lint execution by @Delapouite in https://github.com/org-roam/org-roam/pull/2448
* Fix Issue #2410 - Unlinked References doesnt work if the org-roam-directory has a space in it. by @vikram-mandyam in https://github.com/org-roam/org-roam/pull/2411
* (test): add "org-roam--list-files-search-globs" by @Delapouite in https://github.com/org-roam/org-roam/pull/2449
* Backlink heading by @toregilhk in https://github.com/org-roam/org-roam/pull/2333
* (test): add org-roam-id-find by @Delapouite in https://github.com/org-roam/org-roam/pull/2450
* (test): add org-roam-id-at-point by @Delapouite in https://github.com/org-roam/org-roam/pull/2451
* (test): add org-roam--buffer-promoteable-p by @Delapouite in https://github.com/org-roam/org-roam/pull/2452
* (test): add org-roam--get-titles by @Delapouite in https://github.com/org-roam/org-roam/pull/2453
* (test): add org-roam-node-from-{id|title-or-alias} by @Delapouite in https://github.com/org-roam/org-roam/pull/2454
* (test): add org-roam-alias-{add|remove} by @Delapouite in https://github.com/org-roam/org-roam/pull/2455
* (docs): add missing versions dates and obsolete notice by @Delapouite in https://github.com/org-roam/org-roam/pull/2456
* (docs): explain org-roam-file-exclude-regexp by @adamoudad in https://github.com/org-roam/org-roam/pull/2458
* (test): add org-roam-demote-entire-buffer by @Delapouite in https://github.com/org-roam/org-roam/pull/2459
* (test): add org-roam-file-p by @Delapouite in https://github.com/org-roam/org-roam/pull/2460
* (test): add org-roam-buffer-p by @Delapouite in https://github.com/org-roam/org-roam/pull/2461
* (fix): remove dead-code about org-roam-shield feature by @Delapouite in https://github.com/org-roam/org-roam/pull/2462
* (test): add org-roam-db--file-hash by @Delapouite in https://github.com/org-roam/org-roam/pull/2464
* (test): add org-roam-db-get-{scheduled|deadline}-time by @Delapouite in https://github.com/org-roam/org-roam/pull/2465
* Doc formatting: 2 fixes by @kevinrineer in https://github.com/org-roam/org-roam/pull/2475
* Take org-roam-node as argument to #'org-roam-refile by @pestctrl in https://github.com/org-roam/org-roam/pull/2388
* Compatibility with latest org-id version: advise org-id-find rather than overwriting id link by @ricklupton in https://github.com/org-roam/org-roam/pull/2432
* Depend on emacsql 4.0.0 by @bcc32 in https://github.com/org-roam/org-roam/pull/2466
* Use regexp match to replace hard-coded path equal test by @manphiz in https://github.com/org-roam/org-roam/pull/2497
* Align sqlite integration with emacsql 4.0 by @dustinfarris in https://github.com/org-roam/org-roam/pull/2503
* fix #2425 Prevent data loss when user has called org-roam-extract-subtree on folded org headline by @akashpal-21 in https://github.com/org-roam/org-roam/pull/2444
* Rely on emacsql-sqlite-open to pick the best available back-end by @tarsius in https://github.com/org-roam/org-roam/pull/2486
* Set org-roam-directory to a non-existent path to ensure robust test by @manphiz in https://github.com/org-roam/org-roam/pull/2499
* (perf): Deprecate link :outline properties by @meedstrom in https://github.com/org-roam/org-roam/pull/2509
* Bump DB version to avoid error by @meedstrom in https://github.com/org-roam/org-roam/pull/2514
## 2.2.2 (2022-04-25)
### Breaking ### Breaking
### Added ### Added
- [#2138](https://github.com/org-roam/org-roam/pull/2138) export: add new module - [#2138](https://github.com/org-roam/org-roam/pull/2138) export: add new module
@ -18,7 +100,8 @@
### Changed ### Changed
- [#2160](https://github.com/org-roam/org-roam/pull/2160) core: ignore files in `org-attach-id-dir` by default - [#2160](https://github.com/org-roam/org-roam/pull/2160) core: ignore files in `org-attach-id-dir` by default
## 2.2.1 ## 2.2.1 (2022-03-15)
### Breaking ### Breaking
- [#2054](https://github.com/org-roam/org-roam/pull/2054) node: simplify default `org-roam-node-display-template`. - [#2054](https://github.com/org-roam/org-roam/pull/2054) node: simplify default `org-roam-node-display-template`.
This was done so completions work fine by default on all completion systems. To restore the tabular vertical completion interface, set this in your configuration: This was done so completions work fine by default on all completion systems. To restore the tabular vertical completion interface, set this in your configuration:
@ -52,7 +135,8 @@
- [#2109](https://github.com/org-roam/org-roam/pull/2109) capture: `org-roam-node-insert` places cursor after inserted link where appropriate - [#2109](https://github.com/org-roam/org-roam/pull/2109) capture: `org-roam-node-insert` places cursor after inserted link where appropriate
- [#2123](https://github.com/org-roam/org-roam/pull/2123), [#2124](https://github.com/org-roam/org-roam/pull/2124) buffer: `org-roam-mode-section-functions` renamed to `org-roam-mode-sections`, supports passing args into the section-rendering function - [#2123](https://github.com/org-roam/org-roam/pull/2123), [#2124](https://github.com/org-roam/org-roam/pull/2124) buffer: `org-roam-mode-section-functions` renamed to `org-roam-mode-sections`, supports passing args into the section-rendering function
## 2.2.0 ## 2.2.0 (2022-01-14)
### Added ### Added
- [#1806](https://github.com/org-roam/org-roam/pull/1806), [#2017](https://github.com/org-roam/org-roam/pull/2017) db: support caching and usage of Org 9.5's in-built citations - [#1806](https://github.com/org-roam/org-roam/pull/1806), [#2017](https://github.com/org-roam/org-roam/pull/2017) db: support caching and usage of Org 9.5's in-built citations
- [#1963](https://github.com/org-roam/org-roam/pull/1963) db: cache file title into files table - [#1963](https://github.com/org-roam/org-roam/pull/1963) db: cache file title into files table
@ -83,7 +167,8 @@
- [#2016](https://github.com/org-roam/org-roam/pull/2016) db: fix node caching being affected by agenda variables - [#2016](https://github.com/org-roam/org-roam/pull/2016) db: fix node caching being affected by agenda variables
- [#2033](https://github.com/org-roam/org-roam/pull/2023) db: respect local variables during db parsing - [#2033](https://github.com/org-roam/org-roam/pull/2023) db: respect local variables during db parsing
## 2.1.0 ## 2.1.0 (2021-08-20)
### Added ### Added
- [#1693](https://github.com/org-roam/org-roam/pull/1693) added `filter-fn` and `templates` parameter to `org-roam-capture`, `org-roam-node-find`, and `org-roam-node-insert` - [#1693](https://github.com/org-roam/org-roam/pull/1693) added `filter-fn` and `templates` parameter to `org-roam-capture`, `org-roam-node-find`, and `org-roam-node-insert`
- [#1709](https://github.com/org-roam/org-roam/pull/1709) added ability to specify default value in org-roam capture templates - [#1709](https://github.com/org-roam/org-roam/pull/1709) added ability to specify default value in org-roam capture templates
@ -113,7 +198,10 @@
- [#1713](https://github.com/org-roam/org-roam/pull/1713) capture: check for file-existence before template insertion - [#1713](https://github.com/org-roam/org-roam/pull/1713) capture: check for file-existence before template insertion
- [#1725](https://github.com/org-roam/org-roam/pull/1725) db: always compute hash of encrypted file to prevent re-processing of encrypted files - [#1725](https://github.com/org-roam/org-roam/pull/1725) db: always compute hash of encrypted file to prevent re-processing of encrypted files
## 2.0.0 ## 2.0.0 (2021-07-17)
A few symbols have been marked as obsolete. Have a look at the content of [org-roam-compat.el](https://github.com/org-roam/org-roam/blob/f819720c510185af713522c592833ec9f2934251/org-roam-compat.el#L159)
### Added ### Added
- [#1396](https://github.com/org-roam/org-roam/pull/1396) add option to choose between prepending, appending, and omitting `roam_tags` in file completion - [#1396](https://github.com/org-roam/org-roam/pull/1396) add option to choose between prepending, appending, and omitting `roam_tags` in file completion
- [#1270](https://github.com/org-roam/org-roam/pull/1270) capture: create OLP if it does not exist. Removes need for OLP setup in `:head`. - [#1270](https://github.com/org-roam/org-roam/pull/1270) capture: create OLP if it does not exist. Removes need for OLP setup in `:head`.
@ -140,7 +228,7 @@
- [#1409](https://github.com/org-roam/org-roam/issues/1398) prevent inclusion of non-org-roam files in `org-roam-dailies--list-files` - [#1409](https://github.com/org-roam/org-roam/issues/1398) prevent inclusion of non-org-roam files in `org-roam-dailies--list-files`
- [#1542](https://github.com/org-roam/org-roam/issues/1542) fix files not excluded when `org-roam-list-files-commands` is nil - [#1542](https://github.com/org-roam/org-roam/issues/1542) fix files not excluded when `org-roam-list-files-commands` is nil
## 1.2.3 (13-11-2020) ## 1.2.3 (2020-11-13)
Primarily a stabilization and bug-fix release. Primarily a stabilization and bug-fix release.
@ -171,7 +259,7 @@ Org-roam-dailies has also been revamped to include new features, see [this video
- [#1233](https://github.com/org-roam/org-roam/issues/1233) fixes bug where descriptive file links become plain links during update for relative paths - [#1233](https://github.com/org-roam/org-roam/issues/1233) fixes bug where descriptive file links become plain links during update for relative paths
- [#1252](https://github.com/org-roam/org-roam/issues/1252) respect original link type during automatic replacement - [#1252](https://github.com/org-roam/org-roam/issues/1252) respect original link type during automatic replacement
## 1.2.2 (06-10-2020) ## 1.2.2 (2020-10-06)
In this release we support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`. Completion for these fuzzy links is supported via `completion-at-point`. In this release we support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`. Completion for these fuzzy links is supported via `completion-at-point`.
@ -209,7 +297,7 @@ This change requires you to set `org-roam-directory` to the resolved path of a f
- [#1057](https://github.com/org-roam/org-roam/pull/1057) Improve performance of database builds by preventing generation of LaTeX and image previews. - [#1057](https://github.com/org-roam/org-roam/pull/1057) Improve performance of database builds by preventing generation of LaTeX and image previews.
- [#1103](https://github.com/org-roam/org-roam/pull/1103) Fix long build-times for Windows on files with URL links - [#1103](https://github.com/org-roam/org-roam/pull/1103) Fix long build-times for Windows on files with URL links
## 1.2.1 (27-07-2020) ## 1.2.1 (2020-07-27)
This release consisted of a big deal of refactoring and bug fixes. Notably, we fixed several catastrophic failures on db builds with bad setups (#854), and modularized tag and title extractions. This release consisted of a big deal of refactoring and bug fixes. Notably, we fixed several catastrophic failures on db builds with bad setups (#854), and modularized tag and title extractions.
@ -242,7 +330,7 @@ We also added some new features that had been a long time coming:
- [#894](https://github.com/org-roam/org-roam/pull/894) Perform link fixes on all Org-roam files - [#894](https://github.com/org-roam/org-roam/pull/894) Perform link fixes on all Org-roam files
- [#952](https://github.com/org-roam/org-roam/pull/952) Cache `${foo}` template variables so they do not need to be re-entered twice - [#952](https://github.com/org-roam/org-roam/pull/952) Cache `${foo}` template variables so they do not need to be re-entered twice
## 1.2.0 (12-06-2020) ## 1.2.0 (2020-06-12)
In this release, we improved the linking process by achieving feature parity between links to files and links to headlines. Before, we used the `file:foo::*bar` format to link to the headline `bar` in file `foo`, but this was prone to breakage upon renaming the file or modifying the headline. This is not the case anymore. Now, we use `org-id` to create IDs for those headlines, which are then stored in our database to compute the relationships and jump around. Note that this will work even if youre not using `org-id` in your global configuration for Org-mode. In this release, we improved the linking process by achieving feature parity between links to files and links to headlines. Before, we used the `file:foo::*bar` format to link to the headline `bar` in file `foo`, but this was prone to breakage upon renaming the file or modifying the headline. This is not the case anymore. Now, we use `org-id` to create IDs for those headlines, which are then stored in our database to compute the relationships and jump around. Note that this will work even if youre not using `org-id` in your global configuration for Org-mode.
@ -270,7 +358,7 @@ We also add `org-roam-unlinked-references`, which naively finds text that could
- [#759](https://github.com/org-roam/org-roam/pull/759), [#760](https://github.com/org-roam/org-roam/pull/760) Tags are only added to the tags table if there are actually tags present - [#759](https://github.com/org-roam/org-roam/pull/759), [#760](https://github.com/org-roam/org-roam/pull/760) Tags are only added to the tags table if there are actually tags present
- [#700](https://github.com/org-roam/org-roam/pull/700), [#733](https://github.com/org-roam/org-roam/pull/733) Allow symlinks within the `org-roam` directory - [#700](https://github.com/org-roam/org-roam/pull/700), [#733](https://github.com/org-roam/org-roam/pull/733) Allow symlinks within the `org-roam` directory
## 1.1.1 (18-05-2020) ## 1.1.1 (2020-05-18)
In this release, we added two new features: In this release, we added two new features:
@ -310,7 +398,7 @@ As usual, this release comes with a multitude of bug-fixes and refactorings.
- [#606](https://github.com/org-roam/org-roam/pull/606) Added `org-roam-dev.el` for developer coding standards - [#606](https://github.com/org-roam/org-roam/pull/606) Added `org-roam-dev.el` for developer coding standards
- [#622](https://github.com/org-roam/org-roam/pull/622) Online documentation now points to the Org-based documentation - [#622](https://github.com/org-roam/org-roam/pull/622) Online documentation now points to the Org-based documentation
## 1.1.0 (21-04-2020) ## 1.1.0 (2020-04-21)
To the average user, this release is mainly a bugfix release with additional options to customize. However, the changes made to the source is significant. Most notably, in this release: To the average user, this release is mainly a bugfix release with additional options to customize. However, the changes made to the source is significant. Most notably, in this release:
@ -348,7 +436,7 @@ In the coming months, you can expect work on bigger projects (e.g. revamping the
- [#363](https://github.com/org-roam/org-roam/pull/363), [#473](https://github.com/org-roam/org-roam/pull/473) Modularize org-roam features. - [#363](https://github.com/org-roam/org-roam/pull/363), [#473](https://github.com/org-roam/org-roam/pull/473) Modularize org-roam features.
- [#497](https://github.com/org-roam/org-roam/pull/497) Simplify `org-roam--list-files` implementation - [#497](https://github.com/org-roam/org-roam/pull/497) Simplify `org-roam--list-files` implementation
## 1.0.0 (23-03-2020) ## 1.0.0 (2020-03-23)
Org-roam is now on MELPA! We have squashed most of the bugs, and Org-roam has Org-roam is now on MELPA! We have squashed most of the bugs, and Org-roam has
been stable for the most part. been stable for the most part.
@ -367,7 +455,7 @@ been stable for the most part.
- [#293](https://github.com/org-roam/org-roam/pull/293) Fix capture templates not working as expected for `org-roam-find-file` - [#293](https://github.com/org-roam/org-roam/pull/293) Fix capture templates not working as expected for `org-roam-find-file`
- [#275](https://github.com/org-roam/org-roam/pull/275) Fix database rebuild when `org-roam-directory` is set locally - [#275](https://github.com/org-roam/org-roam/pull/275) Fix database rebuild when `org-roam-directory` is set locally
## 1.0.0-rc1 (06-03-2020) ## 1.0.0-rc1 (2020-03-06)
This is a pre-release before the push to MELPA. It contains large This is a pre-release before the push to MELPA. It contains large
internal changes, with little user-facing changes. Most notably, the internal changes, with little user-facing changes. Most notably, the

View File

@ -153,9 +153,8 @@ dependencies. These include:
- dash - dash
- f - f
- s - s
- org (9.4 is the minimal required version!) - org (9.6 is the minimum required version!)
- emacsql - emacsql
- emacsql-sqlite
- magit-section - magit-section
- filenotify-recursive - filenotify-recursive
@ -230,6 +229,7 @@ it has not already been addressed on [GitHub][issues] or on
([Source](https://github.com/jethrokuan/braindump/tree/master/org)) ([Source](https://github.com/jethrokuan/braindump/tree/master/org))
- [Alexey Shmalko](https://www.alexeyshmalko.com/) - [Alexey Shmalko](https://www.alexeyshmalko.com/)
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html) - [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
- [Martin Edström](https://edstrom.dev/)
## Contributing ## Contributing

View File

@ -1,23 +1,23 @@
#+title: Org-roam User Manual #+title: Org-roam User Manual
#+author: Jethro Kuan #+author: Jethro Kuan
#+email: jethrokuan95@gmail.com #+email: jethrokuan95@gmail.com
#+date: 2020-2022 #+date: 2020-2025
#+language: en #+language: en
#+texinfo_deffn: t #+texinfo_deffn: t
#+texinfo_dir_category: Emacs #+texinfo_dir_category: Emacs
#+texinfo_dir_title: Org-roam: (org-roam). #+texinfo_dir_title: Org-roam: (org-roam).
#+texinfo_dir_desc: Roam Research for Emacs. #+texinfo_dir_desc: Roam Research for Emacs.
#+subtitle: for version 2.2.1 #+subtitle: for version 2.3.0
#+options: H:4 num:3 toc:nil creator:t ':t #+options: H:4 num:3 toc:nil creator:t ':t
#+property: header-args :eval never #+property: header-args :eval never
#+texinfo: @noindent #+texinfo: @noindent
This manual is for Org-roam version 2.2.1. This manual is for Org-roam version 2.3.0.
#+BEGIN_QUOTE #+BEGIN_QUOTE
Copyright (C) 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> Copyright (C) 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
You can redistribute this document and/or modify it under the terms of the GNU You can redistribute this document and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either General Public License as published by the Free Software Foundation, either
@ -178,18 +178,7 @@ archives to =package-archives=:
#+END_SRC #+END_SRC
Org-roam also depends on a recent version of Org, which can be obtained in Org's Org-roam also depends on a recent version of Org, which can be obtained in Org's
package repository (see info:org#Installation). To use Org's ELPA archive: package repository (see info:org#Installation).
#+BEGIN_SRC emacs-lisp
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
#+END_SRC
Once you have added your preferred archive, you need to update the
local package list using:
#+BEGIN_EXAMPLE
M-x package-refresh-contents RET
#+END_EXAMPLE
Once you have done that, you can install Org-roam and its dependencies Once you have done that, you can install Org-roam and its dependencies
using: using:
@ -235,7 +224,6 @@ dependencies that it requires. These include:
- s - s
- org - org
- emacsql - emacsql
- emacsql-sqlite
- magit-section - 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
@ -279,40 +267,6 @@ 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
** 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.
~emacsql-sqlite~ requires a C compiler (e.g. ~gcc~ or ~clang~) to be present in
your computer. How to install a C compiler depends on the OS that you use.
**** C Compiler for Windows
One of the easiest ways to install a C compiler in Windows is to use [[https://www.msys2.org/][MSYS2]] as at the time of this writing:
1. Download and use the installer in the official MSYS2 website
2. Run MSYS2 and in its terminal, type the following and answer "Y" to
proceed -- this will install ~gcc~ in your PC:
#+BEGIN_SRC bash
pacman -S gcc
#+END_SRC
4. On Windows, add ~C:\msys64\usr\bin~ (command =where gcc= in MSYS2 terminal
can tell you the correct path) to ~PATH~ in your environmental variables
5. Launch Emacs and call ~M-x org-roam-db-autosync-mode~ (launch Emacs after
defining the path, so that Emacs can recognize it)
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
@ -421,7 +375,7 @@ Org-roam provides (see [[*Completion][Completion]]).
** Customizing Node Completions ** Customizing Node Completions
Node selection is achieved via the ~completing-read~ interface, typically Node selection is achieved via the ~completing-read~ interface, typically
through `org-roam-node-read`. The presentation of these nodes are governed by through ~org-roam-node-read~. The presentation of these nodes are governed by
~org-roam-node-display-template~. ~org-roam-node-display-template~.
- Variable: org-roam-node-display-template - Variable: org-roam-node-display-template
@ -468,49 +422,8 @@ can set ~org-roam-node-display-template~ as such:
* Customizing Node Caching * Customizing Node Caching
** How to cache ** How to cache
Org-roam uses a SQLite database to perform caching. This integration is
Org-roam uses a sqlite database to perform caching, but there are multiple Emacs managed by the [[https://github.com/magit/emacsql][emacsql]] library. It should "just work".
libraries that can be used. The default used by Org-roam is ~emacs-sqlite~.
Below the pros and cons of each package is used:
[[https://github.com/skeeto/emacsql][**emacs-sqlite**]]
The default option used by Org-roam. This library is the most mature and
well-supported and is imported by default in Org-roam.
One downside of using ~emacs-sqlite~ is that using it requires compilation and
can cause issues in some environments (especially Windows). If you have issues
producing the customized binary required by ~emacs-sqlite~, consider using
~emacs-sqlite3~.
[[https://github.com/cireu/emacsql-sqlite3][**emacs-sqlite3**]]
~emacs-sqlite3~ uses the official sqlite3 binary that can be obtained from your
system's package manager. This is useful if you have issues producing the
~sqlite3~ binary required by the other packages. However, it is not recommended
because it has some compatibility issues with Emacs, but should work for most
regular cases. See [[https://nullprogram.com/blog/2014/02/06/][Chris Wellon's blog post]] for more information.
To use ~emacsql-sqlite3~, ensure that the package is installed, and set:
#+begin_src emacs-lisp
(setq org-roam-database-connector 'sqlite3)
#+end_src
[[https://github.com/emacscollective/emacsql-libsqlite3/][**emacsql-libsqlite3**]]
~emacs-libsqlite3~ is a relatively young package which uses an Emacs module that
exposes parts of the SQLite C API to Emacs Lisp, instead of using subprocess as
~emacsql-sqlite~ does. It is expected to be a more performant drop-in
replacement for ~emacs-sqlite~.
At the moment it is experimental and does not work well with the SQL query load
required by Org-roam, but you may still try it by ensuring the package is
installed and setting:
#+begin_src emacs-lisp
(setq org-roam-database-connector 'libsqlite3)
#+end_src
** What to cache ** What to cache
@ -532,7 +445,7 @@ property to a non-nil value. For example:
One can also set ~org-roam-db-node-include-function~. For example, to exclude One can also set ~org-roam-db-node-include-function~. For example, to exclude
all headlines with the ~ATTACH~ tag from the Org-roam database, one can set: all headlines with the ~ATTACH~ tag from the Org-roam database, one can set:
#+begin_src org #+begin_src emacs-lisp
(setq org-roam-db-node-include-function (setq org-roam-db-node-include-function
(lambda () (lambda ()
(not (member "ATTACH" (org-get-tags))))) (not (member "ATTACH" (org-get-tags)))))
@ -633,7 +546,7 @@ There are currently 3 provided widget types:
- 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-sections~.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(setq org-roam-mode-sections (setq org-roam-mode-sections
@ -655,6 +568,19 @@ rendering reference links), set ~org-roam-mode-sections~ as follows:
org-roam-reflinks-section)) org-roam-reflinks-section))
#+end_src #+end_src
The backlinks section ~org-roam-backlinks-section~ also supports a
predicate to filter backlinks, ~:show-backlink-p~. This can be used
as follows:
#+begin_src emacs-lisp
(defun my-org-roam-show-backlink-p (backlink)
(not (member "daily" (org-roam-node-tags (org-roam-backlink-source-node backlink)))))
(setq org-roam-mode-sections
'((org-roam-backlinks-section :unique t :show-backlink-p my-org-roam-show-backlink-p)
org-roam-reflinks-section))
#+end_src
** Configuring the Org-roam buffer display ** Configuring the Org-roam buffer display
Org-roam does not control how the pop-up buffer is displayed: this is left to Org-roam does not control how the pop-up buffer is displayed: this is left to
@ -865,7 +791,7 @@ Similarly, the completion candidates are the titles and aliases for all Org-roam
nodes, and upon choosing a candidate a ~roam:Title~ link will be inserted nodes, and upon choosing a candidate a ~roam:Title~ link will be inserted
linking to the node of choice. linking to the node of choice.
This is disable by default. To enable it, set ~org-roam-completion-everywhere~ This is disabled by default. To enable it, set ~org-roam-completion-everywhere~
to ~t~: to ~t~:
#+begin_src emacs-lisp #+begin_src emacs-lisp
@ -1053,7 +979,7 @@ For Mac OS, we need to create our own application.
on open location this_URL on open location this_URL
set EC to "/usr/local/bin/emacsclient --no-wait " set EC to "/usr/local/bin/emacsclient --no-wait "
set filePath to quoted form of this_URL set filePath to quoted form of this_URL
do shell script EC & filePath do shell script EC & filePath & " &> /dev/null &"
tell application "Emacs" to activate tell application "Emacs" to activate
end open location end open location
#+end_src #+end_src
@ -1098,6 +1024,21 @@ defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandle
Then restart your computer. Then restart your computer.
If you're using the [[https://formulae.brew.sh/formula/emacs][Emacs Homebrew formula]], you may need one of the following additional configurations:
a) Add option `-c` to `emacsclient` in the script, and start emacs from command line with `emacs --daemon`
#+begin_src emacs-lisp
on open location this_URL
set EC to "/usr/local/bin/emacsclient -c --no-wait "
set filePath to quoted form of this_URL
do shell script EC & filePath & " &> /dev/null &"
tell application "Emacs" to activate
end open location
#+end_src
b) Add `(server-start)` in .emacs (in this case you do not need option `-c` for `emacsclient` in the script, and you do not need to start emacs with `emacs --daemon`
***** Testing org-protocol ***** Testing org-protocol
To test that you have the handler setup and registered properly from the command To test that you have the handler setup and registered properly from the command
@ -1300,7 +1241,7 @@ There are variants of those commands for ~-yesterday~ and ~-tomorrow~:
- Function: ~org-roam-dailies-capture-yesterday~ n &optional goto - Function: ~org-roam-dailies-capture-yesterday~ n &optional goto
Create an entry in the daily note for yesteday. Create an entry in the daily note for yesterday.
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.
@ -1649,21 +1590,6 @@ to the publishing directory. Example code follows:
(kill-buffer (file-name-nondirectory svg)) (kill-buffer (file-name-nondirectory svg))
(setq my-publish-time 0))))) (setq my-publish-time 0)))))
#+end_src #+end_src
** I'm seeing this "Selecting deleted buffer" error. What do I do?
The "selecting deleted buffer" error usually occurs when you don't have a
working ~emacsql-sqlite~ executable. Org-roam relies on this executable to
function properly, and doesn't catch this error. This issue is most commonly
seen on Windows setups. You can browse through the various GitHub issues posted
about this [[https://github.com/org-roam/org-roam/issues?q=is%3Aissue+selecting+deleted][here]].
To fix this, you can try the following:
1. If on Windows, try replacing your system binary with [[https://github.com/nobiot/emacsql-sqlite.exe][this one]] that has been proven
to work
2. Use the ~emacsql-sqlite3~ option rather than compiling your own emacsql
binary (see [[*How to cache][How to cache]]).
* Developer's Guide to Org-roam * Developer's Guide to Org-roam
** Org-roam's Design Principle ** Org-roam's Design Principle
@ -1702,7 +1628,7 @@ queries on their Org files.
** Building Extensions and Advanced Customization of Org-roam ** Building Extensions and Advanced Customization of Org-roam
Because Org-roam's core functionality is small, it is possible and sometimes Because Org-roam's core functionality is small, it is possible and sometimes
desirable to build extensions on top of it. These extensions may one or more of desirable to build extensions on top of it. These extensions may use one or more of
the following functionalities: the following functionalities:
- Access to Org-roam's database - Access to Org-roam's database
@ -1809,7 +1735,7 @@ When GOTO is non-nil, go the note without creating an entry."
:END: :END:
#+BEGIN_QUOTE #+BEGIN_QUOTE
Copyright (C) 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> Copyright (C) 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
You can redistribute this document and/or modify it under the terms You can redistribute this document and/or modify it under the terms
of the GNU General Public License as published by the Free Software of the GNU General Public License as published by the Free Software

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
;;; org-roam-dailies.el --- Daily-notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-dailies.el --- Daily-notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
;;; ;;;
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Copyright © 2020 Leo Vivier <leo.vivier+dev@gmail.com> ;; Copyright © 2020 Leo Vivier <leo.vivier+dev@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Leo Vivier <leo.vivier+dev@gmail.com> ;; Leo Vivier <leo.vivier+dev@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org-roam "2.1")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-export.el --- Org-roam org-export tweaks -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-export.el --- Org-roam org-export tweaks -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1")) ;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-graph.el --- Basic graphing functionality for Org-roam -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-graph.el --- Basic graphing functionality for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1")) ;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-overlay.el --- Link overlay for [id:] links to Org-roam nodes -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-overlay.el --- Link overlay for [id:] links to Org-roam nodes -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1")) ;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,11 +1,11 @@
;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1")) ;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-capture.el --- Capture functionality -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-capture.el --- Capture functionality -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -707,8 +707,6 @@ the current value of `point'."
(defun org-roam-capture--finalize () (defun org-roam-capture--finalize ()
"Finalize the `org-roam-capture' process." "Finalize the `org-roam-capture' process."
(when-let ((region (org-roam-capture--get :region)))
(org-roam-unshield-region (car region) (cdr region)))
(if org-note-abort (if org-note-abort
(when-let ((new-file (org-roam-capture--get :new-file)) (when-let ((new-file (org-roam-capture--get :new-file))
(_ (yes-or-no-p "Delete file for aborted capture?"))) (_ (yes-or-no-p "Delete file for aborted capture?")))
@ -740,7 +738,6 @@ This function is to be called in the Org-capture finalization process."
(buf (marker-buffer mkr))) (buf (marker-buffer mkr)))
(with-current-buffer buf (with-current-buffer buf
(when-let ((region (org-roam-capture--get :region))) (when-let ((region (org-roam-capture--get :region)))
(org-roam-unshield-region (car region) (cdr region))
(delete-region (car region) (cdr region)) (delete-region (car region) (cdr region))
(set-marker (car region) nil) (set-marker (car region) nil)
(set-marker (cdr region) nil)) (set-marker (cdr region) nil))
@ -788,7 +785,7 @@ When ENSURE-NEWLINE, always ensure there's a newline behind."
;; template does not start with any whitespace, and only ends with a single newline ;; template does not start with any whitespace, and only ends with a single newline
;; ;;
;; Instead, we restore the whitespace in the original template. ;; Instead, we restore the whitespace in the original template.
(setq template (replace-regexp-in-string "\n$" "" (org-capture-fill-template template))) (setq template (replace-regexp-in-string "[\n]*\\'" "" (org-capture-fill-template template)))
(when (and ensure-newline (when (and ensure-newline
(string-equal template-whitespace-content "")) (string-equal template-whitespace-content ""))
(setq template-whitespace-content "\n")) (setq template-whitespace-content "\n"))

View File

@ -1,11 +1,11 @@
;;; org-roam-compat.el --- Backward compatibility code -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-compat.el --- Backward compatibility code -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1")) ;; Package-Requires: ((emacs "26.1"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-db.el --- Org-roam database API -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-db.el --- Org-roam database API -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -31,41 +31,11 @@
;; ;;
;;; Code: ;;; Code:
(require 'org-roam) (require 'org-roam)
(require 'url-parse)
(require 'ol)
(defvar org-outline-path-cache) (defvar org-outline-path-cache)
;;; Options ;;; Options
(defcustom org-roam-database-connector 'sqlite
"The database connector used by Org-roam.
This must be set before `org-roam' is loaded. To use an alternative
connector you must install the respective package explicitly.
The default is `sqlite', which uses the `emacsql-sqlite' library
that is being maintained in the same repository as `emacsql'
itself.
If you are using Emacs 29, then the recommended connector is
`sqlite-builtin', which uses the new builtin support for SQLite.
You need to install the `emacsql-sqlite-builtin' package to use
this connector.
If you are using an older Emacs release, then the recommended
connector is `sqlite-module', which uses the module provided by
the `sqlite3' package. This is very similar to the previous
connector and the built-in support in Emacs 29 derives from this
module. You need to install the `emacsql-sqlite-module' package
to use this connector.
For the time being `libsqlite3' is still supported. Do not use
this, it is an older version of the `sqlite-module' connector
from before the connector and the package were renamed.
For the time being `sqlite3' is also supported. Do not use this.
This uses the third-party `emacsql-sqlite3' package, which uses
the official `sqlite3' cli tool, which is not intended
to be used like this. See https://nullprogram.com/blog/2014/02/06/."
:package-version '(forge . "0.3.0")
:group 'forge
:type '(choice (const sqlite)
(const sqlite-builtin)
(const sqlite-module)
(const :tag "libsqlite3 (OBSOLETE)" libsqlite3)
(const :tag "sqlite3 (BROKEN)" sqlite3)))
(defcustom org-roam-db-location (locate-user-emacs-file "org-roam.db") (defcustom org-roam-db-location (locate-user-emacs-file "org-roam.db")
"The path to file where the Org-roam database is stored. "The path to file where the Org-roam database is stored.
@ -119,8 +89,9 @@ is desirable to parse and cache these links (e.g. hiding links in
a property drawer)." a property drawer)."
:package-version '(org-roam . "2.2.0") :package-version '(org-roam . "2.2.0")
:group 'org-roam :group 'org-roam
:type '(set (const :tag "keywords" keyword) :type '(set
(const :tag "property drawers" node-property))) (const :tag "keywords" keyword)
(const :tag "property drawers" node-property)))
(defcustom org-roam-db-extra-links-exclude-keys '((node-property . ("ROAM_REFS")) (defcustom org-roam-db-extra-links-exclude-keys '((node-property . ("ROAM_REFS"))
(keyword . ("transclude"))) (keyword . ("transclude")))
@ -137,7 +108,7 @@ ROAM_REFS."
:type '(alist)) :type '(alist))
;;; Variables ;;; Variables
(defconst org-roam-db-version 18) (defconst org-roam-db-version 20)
(defvar org-roam-db--connection (make-hash-table :test #'equal) (defvar org-roam-db--connection (make-hash-table :test #'equal)
"Database connection to Org-roam database.") "Database connection to Org-roam database.")
@ -148,36 +119,6 @@ ROAM_REFS."
(gethash (expand-file-name (file-name-as-directory org-roam-directory)) (gethash (expand-file-name (file-name-as-directory org-roam-directory))
org-roam-db--connection)) org-roam-db--connection))
(declare-function emacsql-sqlite "ext:emacsql-sqlite")
(declare-function emacsql-sqlite3 "ext:emacsql-sqlite3")
(declare-function emacsql-libsqlite3 "ext:emacsql-libsqlite3")
(declare-function emacsql-sqlite-builtin "ext:emacsql-sqlite-builtin")
(declare-function emacsql-sqlite-module "ext:emacsql-sqlite-module")
(defun org-roam-db--conn-fn ()
"Return the function for creating the database connection."
(cl-case org-roam-database-connector
(sqlite
(progn
(require 'emacsql-sqlite)
#'emacsql-sqlite))
(sqlite-builtin
(progn
(require 'emacsql-sqlite-builtin)
#'emacsql-sqlite-builtin))
(sqlite-module
(progn
(require 'emacsql-sqlite-module)
#'emacsql-sqlite-module))
(libsqlite3
(progn
(require 'emacsql-libsqlite3)
#'emacsql-libsqlite3))
(sqlite3
(progn
(require 'emacsql-sqlite3)
#'emacsql-sqlite3))))
(defun org-roam-db () (defun org-roam-db ()
"Entrypoint to the Org-roam sqlite database. "Entrypoint to the Org-roam sqlite database.
Initializes and stores the database, and the database connection. Initializes and stores the database, and the database connection.
@ -186,11 +127,7 @@ Performs a database upgrade when required."
(emacsql-live-p (org-roam-db--get-connection))) (emacsql-live-p (org-roam-db--get-connection)))
(let ((init-db (not (file-exists-p org-roam-db-location)))) (let ((init-db (not (file-exists-p org-roam-db-location))))
(make-directory (file-name-directory org-roam-db-location) t) (make-directory (file-name-directory org-roam-db-location) t)
(let ((conn (funcall (org-roam-db--conn-fn) org-roam-db-location))) (let ((conn (emacsql-sqlite-open org-roam-db-location)))
(emacsql conn [:pragma (= foreign_keys ON)])
(when-let* ((process (emacsql-process conn))
(_ (processp process)))
(set-process-query-on-exit-flag process nil))
(puthash (expand-file-name (file-name-as-directory org-roam-directory)) (puthash (expand-file-name (file-name-as-directory org-roam-directory))
conn conn
org-roam-db--connection) org-roam-db--connection)
@ -202,7 +139,7 @@ Performs a database upgrade when required."
((> version org-roam-db-version) ((> version org-roam-db-version)
(emacsql-close conn) (emacsql-close conn)
(user-error (user-error
"The Org-roam database was created with a newer Org-roam version. " "The Org-roam database was created with a newer Org-roam version. %s"
"You need to update the Org-roam package")) "You need to update the Org-roam package"))
((< version org-roam-db-version) ((< version org-roam-db-version)
(emacsql-close conn) (emacsql-close conn)
@ -344,20 +281,21 @@ If FILE is nil, clear the current buffer."
If there is no title, return the file name relative to If there is no title, return the file name relative to
`org-roam-directory'." `org-roam-directory'."
(org-link-display-format (org-link-display-format
(or (cadr (assoc "TITLE" (org-collect-keywords '("title")))) (or (string-join (cdr (assoc "TITLE" (org-collect-keywords '("title")))) " ")
(file-name-sans-extension (file-relative-name (file-name-sans-extension (file-relative-name
(buffer-file-name (buffer-base-buffer)) (buffer-file-name (buffer-base-buffer))
org-roam-directory))))) org-roam-directory)))))
(defun org-roam-db-insert-file () (defun org-roam-db-insert-file (&optional hash)
"Update the files table for the current buffer. "Update the files table for the current buffer.
If UPDATE-P is non-nil, first remove the file in the database." If UPDATE-P is non-nil, first remove the file in the database.
If HASH is non-nil, use that as the file's hash without recalculating it."
(let* ((file (buffer-file-name)) (let* ((file (buffer-file-name))
(file-title (org-roam-db--file-title)) (file-title (org-roam-db--file-title))
(attr (file-attributes file)) (attr (file-attributes file))
(atime (file-attribute-access-time attr)) (atime (file-attribute-access-time attr))
(mtime (file-attribute-modification-time attr)) (mtime (file-attribute-modification-time attr))
(hash (org-roam-db--file-hash))) (hash (or hash (org-roam-db--file-hash file))))
(org-roam-db-query (org-roam-db-query
[:insert :into files [:insert :into files
:values $v1] :values $v1]
@ -366,12 +304,12 @@ If UPDATE-P is non-nil, first remove the file in the database."
(defun org-roam-db-get-scheduled-time () (defun org-roam-db-get-scheduled-time ()
"Return the scheduled time at point in ISO8601 format." "Return the scheduled time at point in ISO8601 format."
(when-let ((time (org-get-scheduled-time (point)))) (when-let ((time (org-get-scheduled-time (point))))
(org-format-time-string "%FT%T%z" time))) (format-time-string "%FT%T" time)))
(defun org-roam-db-get-deadline-time () (defun org-roam-db-get-deadline-time ()
"Return the deadline time at point in ISO8601 format." "Return the deadline time at point in ISO8601 format."
(when-let ((time (org-get-deadline-time (point)))) (when-let ((time (org-get-deadline-time (point))))
(org-format-time-string "%FT%T%z" time))) (format-time-string "%FT%T" time)))
(defun org-roam-db-node-p () (defun org-roam-db-node-p ()
"Return t if headline at point is an Org-roam node, else return nil." "Return t if headline at point is an Org-roam node, else return nil."
@ -381,12 +319,13 @@ If UPDATE-P is non-nil, first remove the file in the database."
(defun org-roam-db-map-nodes (fns) (defun org-roam-db-map-nodes (fns)
"Run FNS over all nodes in the current buffer." "Run FNS over all nodes in the current buffer."
(org-map-region (org-with-wide-buffer
(lambda () (org-map-region
(when (org-roam-db-node-p) (lambda ()
(dolist (fn fns) (when (org-roam-db-node-p)
(funcall fn)))) (dolist (fn fns)
(point-min) (point-max))) (funcall fn))))
(point-min) (point-max))))
(defun org-roam-db-map-links (fns) (defun org-roam-db-map-links (fns)
"Run FNS over all links in the current buffer." "Run FNS over all links in the current buffer."
@ -395,9 +334,10 @@ If UPDATE-P is non-nil, first remove the file in the database."
;; `re-search-forward' let the cursor one character after the link, we need to go backward one char to ;; `re-search-forward' let the cursor one character after the link, we need to go backward one char to
;; make the point be on the link. ;; make the point be on the link.
(backward-char) (backward-char)
(let* ((element (org-element-context)) (let* ((begin (match-beginning 0))
(element (org-element-context))
(type (org-element-type element)) (type (org-element-type element))
link bounds) link)
(cond (cond
;; Links correctly recognized by Org Mode ;; Links correctly recognized by Org Mode
((eq type 'link) ((eq type 'link)
@ -408,14 +348,9 @@ If UPDATE-P is non-nil, first remove the file in the database."
((and (member type org-roam-db-extra-links-elements) ((and (member type org-roam-db-extra-links-elements)
(not (member-ignore-case (org-element-property :key element) (not (member-ignore-case (org-element-property :key element)
(cdr (assoc type org-roam-db-extra-links-exclude-keys)))) (cdr (assoc type org-roam-db-extra-links-exclude-keys))))
(setq bounds (org-in-regexp org-link-any-re)) (setq link (save-excursion
(setq link (buffer-substring-no-properties (goto-char begin)
(car bounds) (save-match-data (org-element-link-parser)))))))
(cdr bounds))))
(with-temp-buffer
(delay-mode-hooks (org-mode))
(insert link)
(setq link (org-element-context)))))
(when link (when link
(dolist (fn fns) (dolist (fn fns)
(funcall fn link))))))) (funcall fn link)))))))
@ -539,9 +474,14 @@ INFO is the org-element parsed buffer."
(;; https://google.com, cite:citeKey (;; https://google.com, cite:citeKey
;; Note: we use string-match here because it matches any link: e.g. [[cite:abc][abc]] ;; Note: we use string-match here because it matches any link: e.g. [[cite:abc][abc]]
;; But this form of matching is loose, and can accept invalid links e.g. [[cite:abc] ;; But this form of matching is loose, and can accept invalid links e.g. [[cite:abc]
(string-match org-link-plain-re ref) (string-match org-link-any-re (org-link-encode ref '(#x20)))
(let ((link-type (match-string 1 ref)) (setq ref (org-link-encode ref '(#x20)))
(path (match-string 2 ref))) (let ((ref-url (url-generic-parse-url (or (match-string 2 ref) (match-string 0 ref))))
(link-type ()) ;; clear url-type for backward compatible.
(path ()))
(setq link-type (url-type ref-url))
(setf (url-type ref-url) nil)
(setq path (org-link-decode (url-recreate-url ref-url)))
(if (and (boundp 'org-ref-cite-types) (if (and (boundp 'org-ref-cite-types)
(or (assoc link-type org-ref-cite-types) (or (assoc link-type org-ref-cite-types)
(member link-type org-ref-cite-types))) (member link-type org-ref-cite-types)))
@ -560,12 +500,18 @@ INFO is the org-element parsed buffer."
"Insert link data for LINK at current point into the Org-roam cache." "Insert link data for LINK at current point into the Org-roam cache."
(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))
(path (org-element-property :path link)) (path (org-element-property :path link))
(source (org-roam-id-at-point)) (option (and (string-match "::\\(.*\\)\\'" path)
(properties (list :outline (ignore-errors (match-string 1 path)))
;; This can error if link is not under any headline (path (if (not option) path
(org-get-outline-path 'with-self 'use-cache))))) (substring path 0 (match-beginning 0))))
(source (org-roam-id-at-point))
(properties (list :outline (ignore-errors
;; This can error if link is not under any headline
(org-get-outline-path 'with-self 'use-cache))))
(properties (if option (plist-put properties :search-option option)
properties)))
;; For Org-ref links, we need to split the path into the cite keys ;; For Org-ref links, we need to split the path into the cite keys
(when (and source path) (when (and source path)
(if (and (boundp 'org-ref-cite-types) (if (and (boundp 'org-ref-cite-types)
@ -605,19 +551,12 @@ INFO is the org-element parsed buffer."
(puthash (car row) (cadr row) ht)) (puthash (car row) (cadr row) ht))
ht)) ht))
(defun org-roam-db--file-hash (&optional file-path) (defun org-roam-db--file-hash (file-path)
"Compute the hash of FILE-PATH, a file or current buffer." "Compute the hash of FILE-PATH."
;; If it is a GPG encrypted file, we always want to compute the hash (with-temp-buffer
;; for the GPG encrypted file (undecrypted) (set-buffer-multibyte nil)
(when (and (not file-path) (equal "gpg" (file-name-extension (buffer-file-name)))) (insert-file-contents-literally file-path)
(setq file-path (buffer-file-name))) (secure-hash 'sha1 (current-buffer))))
(if file-path
(with-temp-buffer
(set-buffer-multibyte nil)
(insert-file-contents-literally file-path)
(secure-hash 'sha1 (current-buffer)))
(org-with-wide-buffer
(secure-hash 'sha1 (current-buffer)))))
;;;; Synchronization ;;;; Synchronization
(defun org-roam-db-update-file (&optional file-path no-require) (defun org-roam-db-update-file (&optional file-path no-require)
@ -642,9 +581,10 @@ in `org-roam-db-sync'."
(emacsql-with-transaction (org-roam-db) (emacsql-with-transaction (org-roam-db)
(org-with-wide-buffer (org-with-wide-buffer
(org-set-regexps-and-options 'tags-only) (org-set-regexps-and-options 'tags-only)
(org-refresh-category-properties) ;; Org doesn't use this anymore, so we probably should stop too.
;; (org-refresh-category-properties)
(org-roam-db-clear-file) (org-roam-db-clear-file)
(org-roam-db-insert-file) (org-roam-db-insert-file content-hash)
(org-roam-db-insert-file-node) (org-roam-db-insert-file-node)
(setq org-outline-path-cache nil) (setq org-outline-path-cache nil)
(org-roam-db-map-nodes (org-roam-db-map-nodes

View File

@ -1,12 +1,12 @@
;;; org-roam-id.el --- ID-related utilities for Org-roam -*- lexical-binding: t; -*- ;;; org-roam-id.el --- ID-related utilities for Org-roam -*- lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -55,40 +55,17 @@ With optional argument MARKERP, return the position as a new marker."
(let ((node (org-roam-populate (org-roam-node-create :id id)))) (let ((node (org-roam-populate (org-roam-node-create :id id))))
(when-let ((file (org-roam-node-file node))) (when-let ((file (org-roam-node-file node)))
(if markerp (if markerp
(unwind-protect (let ((buffer (or (find-buffer-visiting file)
(let ((buffer (or (find-buffer-visiting file) (find-file-noselect file))))
(find-file-noselect file)))) (with-current-buffer buffer
(with-current-buffer buffer (move-marker (make-marker) (org-roam-node-point node) buffer)))
(move-marker (make-marker) (org-roam-node-point node) buffer))))
(cons (org-roam-node-file node) (cons (org-roam-node-file node)
(org-roam-node-point node)))))) (org-roam-node-point node))))))
(defun org-roam-id-open (id _) (defalias 'org-roam-id-open 'org-id-open
"Go to the entry with id ID. "Obsolete alias - use `org-id-open' directly.")
Like `org-id-open', but additionally uses the Org-roam database."
(org-mark-ring-push)
(let ((m (or (org-roam-id-find id 'marker)
(org-id-find id 'marker)))
cmd)
(unless m
(error "Cannot find entry with ID \"%s\"" id))
;; Use a buffer-switching command in analogy to finding files
(setq cmd
(or
(cdr
(assq
(cdr (assq 'file org-link-frame-setup))
'((find-file . switch-to-buffer)
(find-file-other-window . switch-to-buffer-other-window)
(find-file-other-frame . switch-to-buffer-other-frame))))
'switch-to-buffer-other-window))
(if (not (equal (current-buffer) (marker-buffer m)))
(funcall cmd (marker-buffer m)))
(goto-char m)
(move-marker m nil)
(org-show-context)))
(org-link-set-parameters "id" :follow #'org-roam-id-open) (advice-add 'org-id-find :before-until #'org-roam-id-find)
;;;###autoload ;;;###autoload
(defun org-roam-update-org-id-locations (&rest directories) (defun org-roam-update-org-id-locations (&rest directories)

View File

@ -1,12 +1,12 @@
;;; org-roam-log.el --- Integrations with Org-log -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-log.el --- Integrations with Org-log -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2022-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2022-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-migrate.el --- Migration utilities from v1 to v2 -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam-migrate.el --- Migration utilities from v1 to v2 -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.

View File

@ -1,12 +1,12 @@
;;; org-roam-mode.el --- Major mode for special Org-roam buffers -*- lexical-binding: t -*- ;;; org-roam-mode.el --- Major mode for special Org-roam buffers -*- lexical-binding: t -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -42,8 +42,8 @@
(defcustom org-roam-mode-sections (list #'org-roam-backlinks-section (defcustom org-roam-mode-sections (list #'org-roam-backlinks-section
#'org-roam-reflinks-section) #'org-roam-reflinks-section)
"A list of sections for the `org-roam-mode' based buffers. "A list of sections for the `org-roam-mode' based buffers.
Each section is a function that is passed the an `org-roam-node' Each section is a function that is passed the `org-roam-node'
for which the section will be constructed for as the first for which the section will be constructed as the first
argument. Normally this node is `org-roam-buffer-current-node'. argument. Normally this node is `org-roam-buffer-current-node'.
The function may also accept other optional arguments. Each item The function may also accept other optional arguments. Each item
in the list is either: in the list is either:
@ -319,7 +319,7 @@ To toggle its display use `org-roam-buffer-toggle' command.")
(define-inline org-roam-buffer--visibility () (define-inline org-roam-buffer--visibility ()
"Return the current visibility state of the persistent `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
(cond (cond
@ -339,7 +339,7 @@ Has no effect when there's no `org-roam-node-at-point'."
(add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t))))) (add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t)))))
(defun org-roam-buffer--persistent-cleanup-h () (defun org-roam-buffer--persistent-cleanup-h ()
"Clean-up global state thats dedicated for the persistent `org-roam-buffer'." "Clean-up global state that's dedicated for the persistent `org-roam-buffer'."
(setq-default org-roam-buffer-current-node nil (setq-default org-roam-buffer-current-node nil
org-roam-buffer-current-directory nil)) org-roam-buffer-current-directory nil))
@ -441,7 +441,7 @@ In interactive calls OTHER-WINDOW is set with
(with-current-buffer buf (with-current-buffer buf
(widen) (widen)
(goto-char point)) (goto-char point))
(when (org-invisible-p) (org-show-context)) (when (org-invisible-p) (org-fold-show-context))
buf)) buf))
(defun org-roam-preview-default-function () (defun org-roam-preview-default-function ()
@ -514,19 +514,28 @@ Sorts by title."
(string< (org-roam-node-title (org-roam-backlink-source-node a)) (string< (org-roam-node-title (org-roam-backlink-source-node a))
(org-roam-node-title (org-roam-backlink-source-node b)))) (org-roam-node-title (org-roam-backlink-source-node b))))
(cl-defun org-roam-backlinks-section (node &key (unique nil)) (cl-defun org-roam-backlinks-section (node &key (unique nil) (show-backlink-p nil)
(section-heading "Backlinks:"))
"The backlinks section for NODE. "The backlinks section for NODE.
When UNIQUE is nil, show all positions where references are found. When UNIQUE is nil, show all positions where references are found.
When UNIQUE is t, limit to unique sources." When UNIQUE is t, limit to unique sources.
When SHOW-BACKLINK-P is not null, only show backlinks for which
this predicate is not nil.
SECTION-HEADING is the string used as a heading for the backlink section."
(when-let ((backlinks (seq-sort #'org-roam-backlinks-sort (org-roam-backlinks-get node :unique unique)))) (when-let ((backlinks (seq-sort #'org-roam-backlinks-sort (org-roam-backlinks-get node :unique unique))))
(magit-insert-section (org-roam-backlinks) (magit-insert-section (org-roam-backlinks)
(magit-insert-heading "Backlinks:") (magit-insert-heading section-heading)
(dolist (backlink backlinks) (dolist (backlink backlinks)
(org-roam-node-insert-section (when (or (null show-backlink-p)
:source-node (org-roam-backlink-source-node backlink) (and (not (null show-backlink-p))
:point (org-roam-backlink-point backlink) (funcall show-backlink-p backlink)))
:properties (org-roam-backlink-properties backlink))) (org-roam-node-insert-section
:source-node (org-roam-backlink-source-node backlink)
:point (org-roam-backlink-point backlink)
:properties (org-roam-backlink-properties backlink))))
(insert ?\n)))) (insert ?\n))))
;;;; Reflinks ;;;; Reflinks
@ -621,7 +630,7 @@ instead."
(forward-line (1- row))) (forward-line (1- row)))
(when col (when col
(forward-char (1- col)))) (forward-char (1- col))))
(when (org-invisible-p) (org-show-context)) (when (org-invisible-p) (org-fold-show-context))
buf)) buf))
;;;; Unlinked references ;;;; Unlinked references
@ -649,23 +658,28 @@ This is the ROW within FILE."
(end-of-line) (end-of-line)
(point))))) (point)))))
(defun org-roam-unlinked-references--rg-command (titles)
"Return the ripgrep command searching for TITLES."
(concat "rg --follow --only-matching --vimgrep --pcre2 --ignore-case "
(mapconcat (lambda (glob) (concat "--glob " glob))
(org-roam--list-files-search-globs org-roam-file-extensions)
" ")
(format " '\\[([^[]]++|(?R))*\\]%s' "
(mapconcat (lambda (title)
(format "|(\\b%s\\b)" (shell-quote-argument title)))
titles ""))
(shell-quote-argument org-roam-directory)))
(defun org-roam-unlinked-references-section (node) (defun org-roam-unlinked-references-section (node)
"The unlinked references section for NODE. "The unlinked references section for NODE.
References from FILE are excluded." References from FILE are excluded."
(when (and (executable-find "rg") (when (and (executable-find "rg")
(org-roam-node-title node)
(not (string-match "PCRE2 is not available" (not (string-match "PCRE2 is not available"
(shell-command-to-string "rg --pcre2-version")))) (shell-command-to-string "rg --pcre2-version"))))
(let* ((titles (cons (org-roam-node-title node) (let* ((titles (cons (org-roam-node-title node)
(org-roam-node-aliases node))) (org-roam-node-aliases node)))
(rg-command (concat "rg -L -o --vimgrep -P -i " (rg-command (org-roam-unlinked-references--rg-command titles))
(mapconcat (lambda (glob) (concat "-g " glob))
(org-roam--list-files-search-globs org-roam-file-extensions)
" ")
(format " '\\[([^[]]++|(?R))*\\]%s' "
(mapconcat (lambda (title)
(format "|(\\b%s\\b)" (shell-quote-argument title)))
titles ""))
org-roam-directory))
(results (split-string (shell-command-to-string rg-command) "\n")) (results (split-string (shell-command-to-string rg-command) "\n"))
f row col match) f row col match)
(magit-insert-section (unlinked-references) (magit-insert-section (unlinked-references)

View File

@ -1,12 +1,12 @@
;;; org-roam-node.el --- Interfacing and interacting with nodes -*- lexical-binding: t; -*- ;;; org-roam-node.el --- Interfacing and interacting with nodes -*- lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -32,6 +32,7 @@
;; interactively. ;; interactively.
;; ;;
;;; Code: ;;; Code:
(require 'crm)
(require 'org-roam) (require 'org-roam)
;;; Options ;;; Options
@ -112,6 +113,12 @@ It takes a single argument REF, which is a propertized string."
:group 'org-roam :group 'org-roam
:type '(function)) :type '(function))
(defcustom org-roam-ref-prompt-function nil
"Function to prompt for ref strings in `org-roam-ref-add'.
Should take no arguments, prompt the user, and return a string."
:group 'org-roam
:type 'function)
;;;; Completion-at-point ;;;; Completion-at-point
(defcustom org-roam-completion-everywhere nil (defcustom org-roam-completion-everywhere nil
"When non-nil, provide link completion matching outside of Org links." "When non-nil, provide link completion matching outside of Org links."
@ -210,6 +217,10 @@ This path is relative to `org-roam-directory'."
(_ (_
(org-roam-node-title node)))) (org-roam-node-title node))))
(cl-defmethod org-roam-node-category ((node org-roam-node))
"Return the category for NODE."
(cdr (assoc-string "CATEGORY" (org-roam-node-properties node))))
;;; Nodes ;;; Nodes
;;;; Getters ;;;; Getters
(defun org-roam-node-at-point (&optional assert) (defun org-roam-node-at-point (&optional assert)
@ -224,9 +235,12 @@ populated."
(magit-section-up) (magit-section-up)
(org-roam-node-at-point))) (org-roam-node-at-point)))
(t (org-with-wide-buffer (t (org-with-wide-buffer
(org-back-to-heading-or-point-min t) (while (not (or (org-roam-db-node-p)
(while (and (not (org-roam-db-node-p)) (bobp)
(not (bobp))) (eq (funcall outline-level)
(save-excursion
(org-roam-up-heading-or-point-min)
(funcall outline-level)))))
(org-roam-up-heading-or-point-min)) (org-roam-up-heading-or-point-min))
(when-let ((id (org-id-get))) (when-let ((id (org-id-get)))
(org-roam-populate (org-roam-populate
@ -243,17 +257,21 @@ Return nil if a node with ID does not exist."
id)) 0) id)) 0)
(org-roam-populate (org-roam-node-create :id id)))) (org-roam-populate (org-roam-node-create :id id))))
(defun org-roam-node-from-title-or-alias (s) (defun org-roam-node-from-title-or-alias (s &optional nocase)
"Return an `org-roam-node' for the node with title or alias S. "Return an `org-roam-node' for the node with title or alias S.
Return nil if the node does not exist. Return nil if the node does not exist.
Throw an error if multiple choices exist." Throw an error if multiple choices exist.
If NOCASE is non-nil, the query is case insensitive. It is case sensitive otherwise."
(let ((matches (seq-uniq (let ((matches (seq-uniq
(append (append
(org-roam-db-query [:select [id] :from nodes (org-roam-db-query (vconcat [:select [id] :from nodes
:where (= title $s1)] :where (= title $s1)]
(if nocase [ :collate NOCASE ]))
s) s)
(org-roam-db-query [:select [node-id] :from aliases (org-roam-db-query (vconcat [:select [node-id] :from aliases
:where (= alias $s1)] :where (= alias $s1)]
(if nocase [ :collate NOCASE ]))
s))))) s)))))
(cond (cond
((seq-empty-p matches) ((seq-empty-p matches)
@ -292,7 +310,8 @@ Return nil if there's no node with such REF."
Uses the ID, and fetches remaining details from the database. Uses the ID, and fetches remaining details from the database.
This can be quite costly: avoid, unless dealing with very few This can be quite costly: avoid, unless dealing with very few
nodes." nodes."
(when-let ((node-info (car (org-roam-db-query [:select [file level pos todo priority (when-let ((node-info (car (org-roam-db-query [:select [
file level pos todo priority
scheduled deadline title properties olp] scheduled deadline title properties olp]
:from nodes :from nodes
:where (= id $s1) :where (= id $s1)
@ -400,8 +419,9 @@ FROM
GROUP BY id, tags ) GROUP BY id, tags )
GROUP BY id"))) GROUP BY id")))
(cl-loop for row in rows (cl-loop for row in rows
append (pcase-let* ((`(,id ,file ,file-title ,level ,todo ,pos ,priority ,scheduled ,deadline append (pcase-let* ((`(
,title ,properties ,olp ,atime ,mtime ,tags ,aliases ,refs) ,id ,file ,file-title ,level ,todo ,pos ,priority ,scheduled ,deadline
,title ,properties ,olp ,atime ,mtime ,tags ,aliases ,refs)
row) row)
(all-titles (cons title aliases))) (all-titles (cons title aliases)))
(mapcar (lambda (temp-title) (mapcar (lambda (temp-title)
@ -427,12 +447,11 @@ GROUP BY id")))
;;;; Finders ;;;; Finders
(defun org-roam-node-marker (node) (defun org-roam-node-marker (node)
"Get the marker for NODE." "Get the marker for NODE."
(unwind-protect (let* ((file (org-roam-node-file node))
(let* ((file (org-roam-node-file node)) (buffer (or (find-buffer-visiting file)
(buffer (or (find-buffer-visiting file) (find-file-noselect file))))
(find-file-noselect file)))) (with-current-buffer buffer
(with-current-buffer buffer (move-marker (make-marker) (org-roam-node-point node) buffer))))
(move-marker (make-marker) (org-roam-node-point node) buffer)))))
(defun org-roam-node-open (node &optional cmd force) (defun org-roam-node-open (node &optional cmd force)
"Go to the node NODE. "Go to the node NODE.
@ -459,7 +478,7 @@ NODE, unless FORCE is non-nil."
(org-roam-id-at-point)))) (org-roam-id-at-point))))
(goto-char m)) (goto-char m))
(move-marker m nil)) (move-marker m nil))
(org-show-context)) (org-fold-show-context))
(defun org-roam-node-visit (node &optional other-window force) (defun org-roam-node-visit (node &optional other-window force)
"From the current buffer, visit NODE. Return the visited buffer. "From the current buffer, visit NODE. Return the visited buffer.
@ -477,7 +496,7 @@ interactive calls FORCE always set to t."
force)) force))
;;;###autoload ;;;###autoload
(cl-defun org-roam-node-find (&optional other-window initial-input filter-fn &key templates) (cl-defun org-roam-node-find (&optional other-window initial-input filter-fn pred &key templates)
"Find and open an Org-roam node by its title or alias. "Find and open an Org-roam node by its title or alias.
INITIAL-INPUT is the initial input for the prompt. INITIAL-INPUT is the initial input for 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',
@ -486,7 +505,7 @@ If OTHER-WINDOW, visit the NODE in another window.
The TEMPLATES, if provided, override the list of capture templates (see The TEMPLATES, if provided, override the list of capture templates (see
`org-roam-capture-'.)" `org-roam-capture-'.)"
(interactive current-prefix-arg) (interactive current-prefix-arg)
(let ((node (org-roam-node-read initial-input filter-fn))) (let ((node (org-roam-node-read initial-input filter-fn pred)))
(if (org-roam-node-file node) (if (org-roam-node-file node)
(org-roam-node-visit node other-window) (org-roam-node-visit node other-window)
(org-roam-capture- (org-roam-capture-
@ -548,13 +567,13 @@ for an example sort function.
The displayed title is formatted according to `org-roam-node-display-template'." The displayed title is formatted according to `org-roam-node-display-template'."
(let* ((template (org-roam-node--process-display-format org-roam-node-display-template)) (let* ((template (org-roam-node--process-display-format org-roam-node-display-template))
(nodes (org-roam-node-list)) (nodes (org-roam-node-list))
(nodes (mapcar (lambda (node)
(org-roam-node-read--to-candidate node template)) nodes))
(nodes (if filter-fn (nodes (if filter-fn
(cl-remove-if-not (cl-remove-if-not
(lambda (n) (funcall filter-fn (cdr n))) (lambda (n) (funcall filter-fn n))
nodes) nodes)
nodes)) nodes))
(nodes (mapcar (lambda (node)
(org-roam-node-read--to-candidate node template)) nodes))
(sort-fn (or sort-fn (sort-fn (or sort-fn
(when org-roam-node-default-sort (when org-roam-node-default-sort
(intern (concat "org-roam-node-read-sort-by-" (intern (concat "org-roam-node-read-sort-by-"
@ -766,7 +785,8 @@ We use this as a substitute for `org-link-bracket-re', because
"Complete \"roam:\" link at point to an existing Org-roam node." "Complete \"roam:\" link at point to an existing Org-roam node."
(let (roam-p start end) (let (roam-p start end)
(when (org-in-regexp org-roam-bracket-completion-re 1) (when (org-in-regexp org-roam-bracket-completion-re 1)
(setq roam-p (not (string-blank-p (match-string 1))) (setq roam-p (not (or (org-in-src-block-p)
(string-blank-p (match-string 1))))
start (match-beginning 2) start (match-beginning 2)
end (match-end 2)) end (match-end 2))
(list start end (list start end
@ -788,6 +808,7 @@ outside of the bracket syntax for links (i.e. \"[[roam:|]]\"),
hence \"everywhere\"." hence \"everywhere\"."
(when (and org-roam-completion-everywhere (when (and org-roam-completion-everywhere
(thing-at-point 'word) (thing-at-point 'word)
(not (org-in-src-block-p))
(not (save-match-data (org-in-regexp org-link-any-re)))) (not (save-match-data (org-in-regexp org-link-any-re))))
(let ((bounds (bounds-of-thing-at-point 'word))) (let ((bounds (bounds-of-thing-at-point 'word)))
(list (car bounds) (cdr bounds) (list (car bounds) (cdr bounds)
@ -837,7 +858,7 @@ Any top level properties drawers are incorporated into the new heading."
(org-with-wide-buffer (org-with-wide-buffer
(org-map-region (lambda () (org-map-region (lambda ()
(if (= (org-current-level) 1) (if (= (org-current-level) 1)
(incf h1-count))) (cl-incf h1-count)))
(point-min) (point-max)) (point-min) (point-max))
h1-count))) h1-count)))
@ -859,22 +880,24 @@ node."
(org-with-point-at 1 (org-with-point-at 1
(let ((title (nth 4 (org-heading-components))) (let ((title (nth 4 (org-heading-components)))
(tags (org-get-tags))) (tags (org-get-tags)))
(org-fold-show-all)
(kill-whole-line) (kill-whole-line)
(org-roam-end-of-meta-data) (org-roam-end-of-meta-data t)
(insert "#+title: " title "\n") (insert "#+title: " title "\n")
(when tags (org-roam-tag-add tags)) (when tags (org-roam-tag-add tags))
(org-map-region #'org-promote (point-min) (point-max)) (org-map-region #'org-promote (point-min) (point-max))
(org-roam-db-update-file)))) (org-roam-db-update-file))))
;;;###autoload ;;;###autoload
(defun org-roam-refile () (defun org-roam-refile (node)
"Refile node at point to an Org-roam node. "Refile node at point to an org-roam NODE.
If region is active, then use it instead of the node at point." If region is active, then use it instead of the node at point."
(interactive) (interactive
(list (org-roam-node-read nil nil nil 'require-match)))
(let* ((regionp (org-region-active-p)) (let* ((regionp (org-region-active-p))
(region-start (and regionp (region-beginning))) (region-start (and regionp (region-beginning)))
(region-end (and regionp (region-end))) (region-end (and regionp (region-end)))
(node (org-roam-node-read nil nil nil 'require-match))
(file (org-roam-node-file node)) (file (org-roam-node-file node))
(nbuf (or (find-buffer-visiting file) (nbuf (or (find-buffer-visiting file)
(find-file-noselect file))) (find-file-noselect file)))
@ -918,7 +941,7 @@ If region is active, then use it instead of the node at point."
(if (buffer-file-name) (if (buffer-file-name)
(delete-file (buffer-file-name))) (delete-file (buffer-file-name)))
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
;; In this was done during capture, abort the capture process. ;; If this was done during capture, abort the capture process.
(when (and org-capture-mode (when (and org-capture-mode
(buffer-base-buffer (current-buffer))) (buffer-base-buffer (current-buffer)))
(org-capture-kill)) (org-capture-kill))
@ -962,6 +985,7 @@ If region is active, then use it instead of the node at point."
(with-current-buffer (find-file-noselect file-path) (with-current-buffer (find-file-noselect file-path)
(org-paste-subtree) (org-paste-subtree)
(while (> (org-current-level) 1) (org-promote-subtree)) (while (> (org-current-level) 1) (org-promote-subtree))
(save-buffer)
(org-roam-promote-entire-buffer) (org-roam-promote-entire-buffer)
(save-buffer))))) (save-buffer)))))
@ -1001,8 +1025,10 @@ The car is the ref, and the cdr is the corresponding node for the ref."
:file file :file file
:point pos :point pos
:title title))) :title title)))
(cons (propertize ref 'node node 'type type) (cons
node))))) (concat (propertize ref 'node node 'type type)
(propertize id 'invisible t))
node)))))
(defun org-roam-ref-read--annotation (ref) (defun org-roam-ref-read--annotation (ref)
"Return the annotation for REF, which assumed to be a propertized string." "Return the annotation for REF, which assumed to be a propertized string."
@ -1025,11 +1051,15 @@ and when nil is returned the node will be filtered out."
;;;; Editing ;;;; Editing
(defun org-roam-ref-add (ref) (defun org-roam-ref-add (ref)
"Add REF to the node at point." "Add REF to the node at point."
(interactive "sRef: ") (interactive `(,(if org-roam-ref-prompt-function
(funcall org-roam-ref-prompt-function)
(read-string "Ref: "))))
(let ((node (org-roam-node-at-point 'assert))) (let ((node (org-roam-node-at-point 'assert)))
(save-excursion (save-excursion
(goto-char (org-roam-node-point node)) (goto-char (org-roam-node-point node))
(org-roam-property-add "ROAM_REFS" ref)))) (org-roam-property-add "ROAM_REFS" (if (member " " (string-to-list ref))
(concat "\"" ref "\"")
ref)))))
(defun org-roam-ref-remove (&optional ref) (defun org-roam-ref-remove (&optional ref)
"Remove a REF from the node at point." "Remove a REF from the node at point."
@ -1057,7 +1087,8 @@ and when nil is returned the node will be filtered out."
(defun org-roam-tag-add (tags) (defun org-roam-tag-add (tags)
"Add TAGS to the node at point." "Add TAGS to the node at point."
(interactive (interactive
(list (completing-read-multiple "Tag: " (org-roam-tag-completions)))) (list (let ((crm-separator "[ ]*:[ ]*"))
(completing-read-multiple "Tag: " (org-roam-tag-completions)))))
(let ((node (org-roam-node-at-point 'assert))) (let ((node (org-roam-node-at-point 'assert)))
(save-excursion (save-excursion
(goto-char (org-roam-node-point node)) (goto-char (org-roam-node-point node))

View File

@ -1,12 +1,12 @@
;;; org-roam-utils.el --- Utilities for Org-roam -*- lexical-binding: t; -*- ;;; org-roam-utils.el --- Utilities for Org-roam -*- lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -72,11 +72,10 @@ Like `string-equal', but case-insensitive."
(defun org-roam-whitespace-content (s) (defun org-roam-whitespace-content (s)
"Return the whitespace content at the end of S." "Return the whitespace content at the end of S."
(with-temp-buffer (with-temp-buffer
(let ((c 0)) (insert s)
(insert s) (skip-chars-backward " \t\n")
(skip-chars-backward " \t\n") (buffer-substring-no-properties
(buffer-substring-no-properties (point) (point-max))))
(point) (point-max)))))
(defun org-roam-strip-comments (s) (defun org-roam-strip-comments (s)
"Strip Org comments from string S." "Strip Org comments from string S."
@ -85,7 +84,8 @@ Like `string-equal', but case-insensitive."
(goto-char (point-min)) (goto-char (point-min))
(while (not (eobp)) (while (not (eobp))
(if (org-at-comment-p) (if (org-at-comment-p)
(delete-region (point-at-bol) (progn (forward-line) (point))) (delete-region (line-beginning-position)
(progn (forward-line) (point)))
(forward-line))) (forward-line)))
(buffer-string))) (buffer-string)))
@ -120,7 +120,7 @@ SPEC is a list, as per `dolist'."
;;; File utilities ;;; File utilities
(defun org-roam-descendant-of-p (a b) (defun org-roam-descendant-of-p (a b)
"Return t if A is descendant of B." "Return t if A is descendant of B."
(unless (equal (file-truename a) (file-truename b)) (unless (and a b (equal (file-truename a) (file-truename b)))
(string-prefix-p (replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name b) t t) (string-prefix-p (replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name b) t t)
(replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name a) t t)))) (replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name a) t t))))
@ -229,36 +229,10 @@ Like `org-fontify-like-in-org-mode', but supports `org-ref'."
(insert s) (insert s)
(let ((org-ref-buffer-hacked t)) (let ((org-ref-buffer-hacked t))
(org-mode) (org-mode)
(org-font-lock-ensure) (setq-local org-fold-core-style 'overlays)
(font-lock-ensure)
(buffer-string)))) (buffer-string))))
;;;; Shielding regions
(defface org-roam-shielded
'((t :inherit (warning)))
"Face for regions that are shielded (marked as read-only).
This face is used on the region target by org-roam-insertion
during an `org-roam-capture'."
:group 'org-roam-faces)
(defun org-roam-shield-region (beg end)
"Shield region against modifications.
BEG and END are markers for the beginning and end regions.
REGION must be a cons-cell containing the marker to the region
beginning and maximum values."
(add-text-properties beg end
'(font-lock-face org-roam-shielded
read-only t)
(marker-buffer beg)))
(defun org-roam-unshield-region (beg end)
"Unshield the shielded REGION.
BEG and END are markers for the beginning and end regions."
(let ((inhibit-read-only t))
(remove-text-properties beg end
'(font-lock-face org-roam-shielded
read-only t)
(marker-buffer beg))))
;;; Org-mode utilities ;;; Org-mode utilities
;;;; Motions ;;;; Motions
(defun org-roam-up-heading-or-point-min () (defun org-roam-up-heading-or-point-min ()
@ -364,26 +338,14 @@ If the property is already set, it's value is replaced."
(defun org-roam-add-property (val prop) (defun org-roam-add-property (val prop)
"Add VAL value to PROP property for the node at point. "Add VAL value to PROP property for the node at point.
Both, VAL and PROP are strings." Both, VAL and PROP are strings."
(let* ((p (org-entry-get (point) prop)) (org-roam-property-add prop val))
(lst (when p (split-string-and-unquote p)))
(lst (if (memq val lst) lst (cons val lst)))
(lst (seq-uniq lst)))
(org-set-property prop (combine-and-quote-strings lst))
val))
(defun org-roam-remove-property (prop &optional val) (defun org-roam-remove-property (prop &optional val)
"Remove VAL value from PROP property for the node at point. "Remove VAL value from PROP property for the node at point.
Both VAL and PROP are strings. Both VAL and PROP are strings.
If VAL 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)) (org-roam-property-remove prop val))
(lst (when p (split-string-and-unquote p)))
(prop-to-remove (or val (completing-read "Remove: " lst)))
(lst (delete prop-to-remove lst)))
(if lst
(org-set-property prop (combine-and-quote-strings lst))
(org-delete-property prop))
prop-to-remove))
(defun org-roam-property-add (prop val) (defun org-roam-property-add (prop val)
"Add VAL value to PROP property for the node at point. "Add VAL value to PROP property for the node at point.
@ -487,8 +449,10 @@ See <https://github.com/raxod502/straight.el/issues/520>."
(quit "N/A")))) (quit "N/A"))))
(insert (format "- Org: %s\n" (org-version nil 'full))) (insert (format "- Org: %s\n" (org-version nil 'full)))
(insert (format "- Org-roam: %s" (org-roam-version))) (insert (format "- Org-roam: %s" (org-roam-version)))
(insert (format "- sqlite-connector: %s" org-roam-database-connector)))) (insert (format "- sqlite-connector: %s"
(if-let ((conn (org-roam-db--get-connection)))
(eieio-object-class conn)
"not connected")))))
(provide 'org-roam-utils) (provide 'org-roam-utils)
;;; org-roam-utils.el ends here ;;; org-roam-utils.el ends here

View File

@ -1,12 +1,12 @@
;;; org-roam.el --- A database abstraction layer for Org-mode -*- coding: utf-8; lexical-binding: t; -*- ;;; org-roam.el --- A database abstraction layer for Org-mode -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> ;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com> ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam ;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience ;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1 ;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@ -80,6 +80,9 @@
(require 'magit-section) (require 'magit-section)
(require 'emacsql) (require 'emacsql)
;; REVIEW: is this require needed?
;; emacsql-sqlite provides a common interface to an emacsql SQLite backend (e.g. emacs-sqlite-builtin)
;; not to be confused with a backend itself named emacsql-sqlite that existed in emacsql < 4.0.
(require 'emacsql-sqlite) (require 'emacsql-sqlite)
(require 'org) (require 'org)
@ -138,7 +141,7 @@ responsibility to ensure that."
:group 'org-roam) :group 'org-roam)
(defcustom org-roam-file-exclude-regexp (list org-attach-id-dir) (defcustom org-roam-file-exclude-regexp (list org-attach-id-dir)
"Files matching this regular expression are excluded from the Org-roam." "Files matching this regular expression or list of regular expressions are excluded from the Org-roam."
:type '(choice :type '(choice
(repeat (repeat
(string :tag "Regular expression matching files to ignore")) (string :tag "Regular expression matching files to ignore"))
@ -152,36 +155,46 @@ responsibility to ensure that."
'(find fd fdfind rg)) '(find fd fdfind rg))
"Commands that will be used to find Org-roam files. "Commands that will be used to find Org-roam files.
It should be a list of symbols or cons cells representing any of the following It should be a list of symbols or cons cells representing any of
supported file search methods. the following supported file search methods.
The commands will be tried in order until an executable for a command is found. The commands will be tried in order until an executable for a
The Elisp implementation is used if no command in the list is found. command is found. The Elisp implementation is used if no command
in the list is found.
`find' `find'
Use find as the file search method. Use find as the file search method.
Example command: Example command:
find /path/to/dir -type f \( -name \"*.org\" -o -name \"*.org.gpg\" \) find /path/to/dir -type f \
\( -name \"*.org\" -o -name \"*.org.gpg\" -name \"*.org.age\" \)
`fd' `fd'
Use fd as the file search method. Use fd as the file search method.
Example command: fd /path/to/dir/ --type file -e \".org\" -e \".org.gpg\" Example command:
fd /path/to/dir/ --type file -e \".org\" -e \".org.gpg\" -e \".org.age\"
`fdfind' `fdfind'
Same as `fd'. It's an alias that used in some OSes (e.g. Debian, Ubuntu) Same as `fd'. It's an alias that used in some OSes (e.g. Debian, Ubuntu)
`rg' `rg'
Use ripgrep as the file search method.
Example command: rg /path/to/dir/ --files -g \"*.org\" -g \"*.org.gpg\"
By default, `executable-find' will be used to look up the path to the Use ripgrep as the file search method.
executable. If a custom path is required, it can be specified together with the Example command:
method symbol as a cons cell. For example: '(find (rg . \"/path/to/rg\"))." rg /path/to/dir/ --files -g \"*.org\" -g \"*.org.gpg\" -g \"*.org.age\"
:type '(set (const :tag "find" find)
(const :tag "fd" fd) By default, `executable-find' will be used to look up the path to
(const :tag "fdfind" fdfind) the executable. If a custom path is required, it can be specified
(const :tag "rg" rg) together with the method symbol as a cons cell. For example:
(const :tag "elisp" nil))) \\='(find (rg . \"/path/to/rg\"))."
:type '(set
(const :tag "find" find)
(const :tag "fd" fd)
(const :tag "fdfind" fdfind)
(const :tag "rg" rg)
(const :tag "elisp" nil)))
;;; Library ;;; Library
(defun org-roam-file-p (&optional file) (defun org-roam-file-p (&optional file)
@ -192,30 +205,34 @@ FILE is an Org-roam file if:
- It's located somewhere under `org-roam-directory' - It's located somewhere under `org-roam-directory'
- It has a matching file extension (`org-roam-file-extensions') - It has a matching file extension (`org-roam-file-extensions')
- It doesn't match excluded regexp (`org-roam-file-exclude-regexp')" - It doesn't match excluded regexp (`org-roam-file-exclude-regexp')"
(let* ((path (or file (buffer-file-name (buffer-base-buffer)))) (when (or file (buffer-file-name (buffer-base-buffer)))
(ext (when path (org-roam--file-name-extension path))) (let* ((path (or file (buffer-file-name (buffer-base-buffer))))
(ext (if (string= ext "gpg") (relative-path (file-relative-name path org-roam-directory))
(org-roam--file-name-extension (file-name-sans-extension path)) (ext (org-roam--file-name-extension path))
ext)) (ext (if (or (string= ext "gpg")
(org-roam-dir-p (org-roam-descendant-of-p path org-roam-directory)) (string= ext "age"))
(valid-file-ext-p (member ext org-roam-file-extensions)) (org-roam--file-name-extension (file-name-sans-extension path))
(match-exclude-regexp-p ext))
(cond (org-roam-dir-p (org-roam-descendant-of-p path org-roam-directory))
((not org-roam-file-exclude-regexp) nil) (valid-file-ext-p (member ext org-roam-file-extensions))
((stringp org-roam-file-exclude-regexp) (match-exclude-regexp-p
(string-match-p org-roam-file-exclude-regexp path)) (cond
((listp org-roam-file-exclude-regexp) ((not org-roam-file-exclude-regexp) nil)
(let (is-match) ((stringp org-roam-file-exclude-regexp)
(dolist (exclude-re org-roam-file-exclude-regexp) (string-match-p org-roam-file-exclude-regexp relative-path))
(setq is-match (or is-match (string-match-p exclude-re path)))) ((listp org-roam-file-exclude-regexp)
is-match))))) (let (is-match)
(save-match-data (dolist (exclude-re org-roam-file-exclude-regexp)
(and (setq is-match (or is-match (string-match-p exclude-re relative-path))))
path is-match)))))
org-roam-dir-p (save-match-data
valid-file-ext-p (and
(not match-exclude-regexp-p))))) path
org-roam-dir-p
valid-file-ext-p
(not match-exclude-regexp-p))))))
;;;###autoload
(defun org-roam-list-files () (defun org-roam-list-files ()
"Return a list of all Org-roam files under `org-roam-directory'. "Return a list of all Org-roam files under `org-roam-directory'.
See `org-roam-file-p' for how each file is determined to be as See `org-roam-file-p' for how each file is determined to be as
@ -287,7 +304,8 @@ If no files are found, an empty list is returned."
E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")" E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
(cl-loop for e in exts (cl-loop for e in exts
append (list (format "\"*.%s\"" e) append (list (format "\"*.%s\"" e)
(format "\"*.%s.gpg\"" e)))) (format "\"*.%s.gpg\"" e)
(format "\"*.%s.age\"" e))))
(defun org-roam--list-files-find (executable dir) (defun org-roam--list-files-find (executable dir)
"Return all Org-roam files under DIR, using \"find\", provided as EXECUTABLE." "Return all Org-roam files under DIR, using \"find\", provided as EXECUTABLE."
@ -308,8 +326,9 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
(defun org-roam--list-files-rg (executable dir) (defun org-roam--list-files-rg (executable dir)
"Return all Org-roam files under DIR, using \"rg\", provided as EXECUTABLE." "Return all Org-roam files under DIR, using \"rg\", provided as EXECUTABLE."
(let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions)) (let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions))
(command (string-join `(,executable "-L" ,dir "--files" (command (string-join `(
,@(mapcar (lambda (glob) (concat "-g " glob)) globs)) " "))) ,executable "-L" ,dir "--files"
,@(mapcar (lambda (glob) (concat "-g " glob)) globs)) " ")))
(org-roam--shell-command-files command))) (org-roam--shell-command-files command)))
(declare-function org-roam--directory-files-recursively "org-roam-compat") (declare-function org-roam--directory-files-recursively "org-roam-compat")
@ -318,7 +337,7 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
"Return all Org-roam files under DIR, using Elisp based implementation." "Return all Org-roam files under DIR, using Elisp based implementation."
(let ((regex (concat "\\.\\(?:"(mapconcat (let ((regex (concat "\\.\\(?:"(mapconcat
#'regexp-quote org-roam-file-extensions #'regexp-quote org-roam-file-extensions
"\\|" )"\\)\\(?:\\.gpg\\)?\\'")) "\\|" )"\\)\\(?:\\.gpg\\|\\.age\\)?\\'"))
result) result)
(dolist (file (org-roam--directory-files-recursively dir regex nil nil t) result) (dolist (file (org-roam--directory-files-recursively dir regex nil nil t) result)
(when (and (file-readable-p file) (when (and (file-readable-p file)

View File

@ -0,0 +1,8 @@
:PROPERTIES:
:ID: 97bf31cf-dfee-45d8-87a5-2ae0dabc4734
:END:
#+title: Demoteable
* Demoteable h1
** Demoteable child

View File

@ -0,0 +1,19 @@
:PROPERTIES:
:ID: 998b2341-b7fe-434d-848c-5282c0727870
:END:
#+title: Family
* Grand-Parent
:PROPERTIES:
:ID: 77a90980-1994-464e-901f-7e3d3df07fd3
:END:
** Parent
:PROPERTIES:
:ID: 0fa5bb3e-3d8c-4966-8bc9-78d32e505d69
:END:
*** Child
:PROPERTIES:
:ID: 5fb4fdc5-b6d2-4f75-8d54-e60053e467ec
:END:

View File

@ -0,0 +1,3 @@
* Promoteable h1
** Promoteable child

View File

@ -0,0 +1,7 @@
:PROPERTIES:
:ROAM_REFS: "http://site.net/docs/01. introduction - hello world.html"
:ID: 5b9a7400-f59c-4ef9-acbb-045b69af98f1
:END:
#+title: ref with space
* Note
hello

View File

@ -0,0 +1,5 @@
:PROPERTIES:
:ID: 57ff3ce7-5bda-4825-8fca-c09f523e87ba
:ROAM_ALIASES: Batman
:END:
#+title: Bruce Wayne

View File

@ -0,0 +1,16 @@
:PROPERTIES:
:ID: 9a20ca6c-5555-41c9-a039-ac38bf59c7a9
:END:
#+title: With Times
* Scheduled heading
SCHEDULED: <2024-07-16 Tue>
:PROPERTIES:
:ID: a523c198-4cb4-44d2-909c-a0e3258089cd
:END:
* Deadline heading
DEADLINE: <2024-07-17 Tue>
:PROPERTIES:
:ID: 3ab84701-d1c1-463f-b5c6-715e6ff5a0bf
:END:

View File

@ -48,9 +48,16 @@
(org-roam-capture--fill-template "foo\n\t\n") (org-roam-capture--fill-template "foo\n\t\n")
:to-equal "foo\n\t\n")) :to-equal "foo\n\t\n"))
(it "fills template without deleting newlines in its body"
(expect
(org-roam-capture--fill-template "foo\n\n\nbar\n\n")
:to-equal "foo\n\n\nbar\n\n"))
(it "expands templates when it's a function" (it "expands templates when it's a function"
(expect (expect
(org-roam-capture--fill-template (lambda () "foo")) (org-roam-capture--fill-template (lambda () "foo"))
:to-equal "foo"))) :to-equal "foo")))
(provide 'test-org-roam-capture) (provide 'test-org-roam-capture)
;;; test-org-roam-capture.el ends here

120
tests/test-org-roam-db.el Normal file
View File

@ -0,0 +1,120 @@
;;; test-org-roam-db.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'buttercup)
(require 'org-roam)
(defvar root-directory default-directory)
(describe "org-roam-db-get-scheduled-time"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location)
(cd root-directory))
(it "should get scheduled time for current heading node"
(org-roam-id-open "a523c198-4cb4-44d2-909c-a0e3258089cd" nil)
(expect (org-roam-db-get-scheduled-time) :to-equal "2024-07-16T00:00:00")))
(describe "org-roam-db-get-deadline-time"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location)
(cd root-directory))
(it "should get deadline time for current heading node"
(org-roam-id-open "3ab84701-d1c1-463f-b5c6-715e6ff5a0bf" nil)
(expect (org-roam-db-get-deadline-time) :to-equal "2024-07-17T00:00:00")))
(describe "org-roam-db--file-hash"
(it "computes the SHA1 of file"
(expect (org-roam-db--file-hash "tests/roam-files/family.org")
:to-equal
"c4ebf8918c1533df72e4d182cbf1bbd90f776b3b")))
(describe "org-roam-db-sync"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "has the correct number of files"
(expect (caar (org-roam-db-query [:select (funcall count) :from files]))
:to-equal
9))
(it "has the correct number of nodes"
(expect (caar (org-roam-db-query [:select (funcall count) :from nodes]))
:to-equal
12))
(it "has the correct number of links"
(expect (caar (org-roam-db-query [:select (funcall count) :from links]))
:to-equal
1))
(it "respects ROAM_EXCLUDE"
;; The excluded node has ID "53fadc75-f48e-461e-be06-44a1e88b2abe"
(expect (mapcar #'car (org-roam-db-query [:select id :from nodes]))
:to-have-same-items-as
'("884b2341-b7fe-434d-848c-5282c0727861"
"440795d0-70c1-4165-993d-aebd5eef7a24"
"5b9a7400-f59c-4ef9-acbb-045b69af98f1"
"0fa5bb3e-3d8c-4966-8bc9-78d32e505d69"
"5fb4fdc5-b6d2-4f75-8d54-e60053e467ec"
"77a90980-1994-464e-901f-7e3d3df07fd3"
"57ff3ce7-5bda-4825-8fca-c09f523e87ba"
"998b2341-b7fe-434d-848c-5282c0727870"
"a523c198-4cb4-44d2-909c-a0e3258089cd"
"3ab84701-d1c1-463f-b5c6-715e6ff5a0bf"
"9a20ca6c-5555-41c9-a039-ac38bf59c7a9"
"97bf31cf-dfee-45d8-87a5-2ae0dabc4734")))
(it "reads ref in quotes correctly"
(expect (mapcar #'car (org-roam-db-query [:select [ref] :from refs]))
:to-have-same-items-as
'("//site.net/docs/01. introduction - hello world.html"))))
(provide 'test-org-roam-db)
;;; test-org-roam-db.el ends here

79
tests/test-org-roam-id.el Normal file
View File

@ -0,0 +1,79 @@
;;; test-org-roam-id.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'buttercup)
(require 'org-roam)
(defvar root-directory default-directory)
(describe "org-roam-id-at-point"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location)
(cd root-directory))
(it "returns the correct node ids"
(find-file "tests/roam-files/family.org" nil)
(expect (org-roam-id-at-point) :to-equal "998b2341-b7fe-434d-848c-5282c0727870")
(search-forward "Grand")
(expect (org-roam-id-at-point) :to-equal "77a90980-1994-464e-901f-7e3d3df07fd3")
(search-forward "Child")
(expect (org-roam-id-at-point) :to-equal "5fb4fdc5-b6d2-4f75-8d54-e60053e467ec")))
(describe "org-roam-id-find"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "finds nothing for non-existing node"
(expect (org-roam-id-find "non-existing") :to-equal nil))
(it "finds the correct file node"
(let ((location (org-roam-id-find "884b2341-b7fe-434d-848c-5282c0727861")))
(expect (car location) :to-match ".*/tests/roam-files/foo.org")
(expect (cdr location) :to-equal 1)))
(it "finds the correct heading node"
(let ((location (org-roam-id-find "0fa5bb3e-3d8c-4966-8bc9-78d32e505d69")))
(expect (car location) :to-match ".*/tests/roam-files/family.org")
(expect (cdr location) :to-equal 156))))
(provide 'test-org-roam-id)
;;; test-org-roam-id.el ends here

View File

@ -0,0 +1,39 @@
;;; test-org-roam-mode.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'buttercup)
(require 'org-roam)
(describe "org-roam-unlinked-references--rg-command"
(before-each
;; the space in the directory is on purpose
(setq org-roam-directory "/tmp/org roam"))
(it "returns the correct rg command for unlinked references"
(expect (org-roam-unlinked-references--rg-command '("foo" "bar"))
:to-equal
"rg --follow --only-matching --vimgrep --pcre2 --ignore-case --glob \"*.org\" --glob \"*.org.gpg\" --glob \"*.org.age\" '\\[([^[]]++|(?R))*\\]|(\\bfoo\\b)|(\\bbar\\b)' /tmp/org\\ roam")))
(provide 'test-org-roam-mode)
;;; test-org-roam-mode.el ends here

164
tests/test-org-roam-node.el Normal file
View File

@ -0,0 +1,164 @@
;;; test-org-roam-node.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'buttercup)
(require 'org-roam)
(defvar root-directory default-directory)
(describe "org-roam-node-from-id"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "returns nil for unknown id"
(expect (org-roam-node-from-id "non-existing") :to-equal nil))
(it "returns correct node from id"
(let ((node (org-roam-node-from-id "884b2341-b7fe-434d-848c-5282c0727861")))
(expect (org-roam-node-title node) :to-equal "Foo"))))
(describe "org-roam-node-from-title-or-alias"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "returns nil for unknown title"
(expect (org-roam-node-from-title-or-alias "non-existing") :to-equal nil))
(it "returns correct node from title"
(let ((node (org-roam-node-from-title-or-alias "Foo")))
(expect (org-roam-node-title node) :to-equal "Foo")))
(it "returns correct node from alias"
(let ((node (org-roam-node-from-title-or-alias "Batman")))
(expect (org-roam-node-title node) :to-equal "Bruce Wayne")))
(it "returns correct node from alias with nocase"
(let ((node (org-roam-node-from-title-or-alias "batman" t)))
(expect (org-roam-node-title node) :to-equal "Bruce Wayne"))))
(describe "org-roam-demote-entire-buffer"
(after-each
(cd root-directory))
(it "demotes an entire org buffer"
(find-file "tests/roam-files/demoteable.org" nil)
(org-roam-demote-entire-buffer)
(expect (buffer-substring-no-properties (point) (point-max))
:to-equal "* Demoteable\n:PROPERTIES:\n:ID: 97bf31cf-dfee-45d8-87a5-2ae0dabc4734\n:END:\n\n** Demoteable h1\n\n*** Demoteable child\n")))
(describe "org-roam--h1-count"
(after-each
(cd root-directory))
(it "returns the correct number of level-1 headings"
(find-file "tests/roam-files/foo.org" nil)
(expect (org-roam--h1-count) :to-equal 0)
(cd root-directory)
(find-file "tests/roam-files/family.org" nil)
(expect (org-roam--h1-count) :to-equal 1)))
(describe "org-roam--buffer-promoteable-p"
(after-each
(cd root-directory))
(it "should check if buffer is promoteable"
(find-file "tests/roam-files/foo.org" nil)
(expect (org-roam--buffer-promoteable-p) :to-equal nil)
(cd root-directory)
(find-file "tests/roam-files/family.org" nil)
(expect (org-roam--buffer-promoteable-p) :to-equal nil)
(cd root-directory)
(find-file "tests/roam-files/promoteable.org" nil)
(expect (org-roam--buffer-promoteable-p) :to-equal t)))
(describe "org-roam--get-titles"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "returns the list of titles and aliases"
(expect (org-roam--get-titles)
:to-have-same-items-as
`("Bar" "Batman" "Bruce Wayne" "Child" "Deadline heading" "Demoteable" "Family"
"Foo" "Grand-Parent" "Parent" "ref with space" "Scheduled heading" "With Times"))))
(describe "org-roam-alias"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location)
(cd root-directory))
(it "adds an alias to a node"
(cd root-directory)
(find-file "tests/roam-files/foo.org" nil)
(org-roam-alias-add "qux")
(expect (buffer-substring-no-properties (point) (point-max))
:to-equal ":PROPERTIES:\n:ID: 884b2341-b7fe-434d-848c-5282c0727861\n:ROAM_ALIASES: qux\n:END:\n#+title: Foo\n"))
(it "removes an alias from a node"
(cd root-directory)
(find-file "tests/roam-files/with-alias.org" nil)
(org-roam-alias-remove "Batman")
(expect (buffer-substring-no-properties (point) (point-max))
:to-equal ":PROPERTIES:\n:ID: 57ff3ce7-5bda-4825-8fca-c09f523e87ba\n:END:\n#+title: Bruce Wayne\n")))
(provide 'test-org-roam-node)
;;; test-org-roam-node.el ends here

View File

@ -36,4 +36,29 @@
(org-roam-whitespace-content "foo\n\t\n") (org-roam-whitespace-content "foo\n\t\n")
:to-equal "\n\t\n"))) :to-equal "\n\t\n")))
(describe "org-roam-db--file-title"
(it "supports normal titles"
(expect
(with-temp-buffer
(insert "#+title:normal title")
(org-roam-db--file-title))
:to-equal "normal title"))
(it "supports multi-line titles"
(expect
(with-temp-buffer
(insert "#+title: title:\n#+title: separated by newline")
(org-roam-db--file-title))
:to-equal "title: separated by newline"))
(it "supports file-name based titles"
(progn
(setq org-roam-directory temporary-file-directory
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org"))
(with-temp-buffer
(write-file (expand-file-name "test file.org" org-roam-directory))
(org-roam-db--file-title)))
:to-equal "test file"))
(provide 'test-org-roam-utils) (provide 'test-org-roam-utils)
;;; test-org-roam-utils.el ends here

View File

@ -24,6 +24,28 @@
(require 'buttercup) (require 'buttercup)
(require 'org-roam) (require 'org-roam)
(defvar root-directory default-directory)
(describe "org-roam-file-p"
(it "checks if given file respects criteria"
(setq org-roam-directory "/non-existent")
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal nil)
(setq org-roam-directory (expand-file-name "tests/roam-files"))
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal t)
(expect (org-roam-file-p "tests/roam-files/markdown.md") :to-equal nil)
(setq org-roam-file-exclude-regexp (regexp-quote "family.org"))
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal nil)))
(describe "org-roam-buffer-p"
(it "checks if current buffer respects criteria"
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-file-exclude-regexp nil)
(find-file "tests/roam-files/family.org" nil)
(expect (org-roam-buffer-p) :to-equal t)
(cd root-directory)))
(describe "org-roam-list-files" (describe "org-roam-list-files"
(before-each (before-each
(setq org-roam-directory (expand-file-name "tests/roam-files") (setq org-roam-directory (expand-file-name "tests/roam-files")
@ -31,52 +53,29 @@
org-roam-file-extensions '("org") org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)) org-roam-file-exclude-regexp nil))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "gets files correctly" (it "gets files correctly"
(expect (length (org-roam-list-files)) (expect (length (org-roam-list-files)) :to-equal 9))
:to-equal 3))
(it "respects org-roam-file-extensions" (it "respects org-roam-file-extensions"
(setq org-roam-file-extensions '("md")) (setq org-roam-file-extensions '("md"))
(expect (length (org-roam-list-files)) :to-equal 1) (expect (length (org-roam-list-files)) :to-equal 1)
(setq org-roam-file-extensions '("org" "md")) (setq org-roam-file-extensions '("org" "md"))
(expect (length (org-roam-list-files)) :to-equal 4)) (expect (length (org-roam-list-files)) :to-equal 10))
(it "respects org-roam-file-exclude-regexp" (it "respects org-roam-file-exclude-regexp"
(setq org-roam-file-exclude-regexp (regexp-quote "foo.org")) (setq org-roam-file-exclude-regexp (regexp-quote "foo.org"))
(expect (length (org-roam-list-files)) :to-equal 2))) (expect (length (org-roam-list-files)) :to-equal 8)))
(describe "org-roam-db-sync" (describe "org-roam--list-files-search-globs"
(before-all
(setq org-roam-directory (expand-file-name "tests/roam-files")
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
org-roam-file-extensions '("org")
org-roam-file-exclude-regexp nil)
(org-roam-db-sync))
(after-all (it "returns the correct list of globs"
(org-roam-db--close) (expect (org-roam--list-files-search-globs org-roam-file-extensions)
(delete-file org-roam-db-location))
(it "has the correct number of files"
(expect (caar (org-roam-db-query [:select (funcall count) :from files]))
:to-equal
3))
(it "has the correct number of nodes"
(expect (caar (org-roam-db-query [:select (funcall count) :from nodes]))
:to-equal
2))
(it "has the correct number of links"
(expect (caar (org-roam-db-query [:select (funcall count) :from links]))
:to-equal
1))
(it "respects ROAM_EXCLUDE"
;; The excluded node has ID "53fadc75-f48e-461e-be06-44a1e88b2abe"
(expect (mapcar #'car (org-roam-db-query [:select id :from nodes]))
:to-have-same-items-as :to-have-same-items-as
'("884b2341-b7fe-434d-848c-5282c0727861" "440795d0-70c1-4165-993d-aebd5eef7a24")))) '("\"*.org\"" "\"*.org.gpg\"" "\"*.org.age\""))))
(provide 'test-org-roam) (provide 'test-org-roam)