Compare commits

...

751 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
69116a4da4 v2.2.2 (#2171) 2022-04-24 17:05:27 -07:00
3014c63d50 (feat)log: init (#2170)
Create initial log module for working with Org logs
2022-04-24 16:57:13 -07:00
a073bcff5c (fix) org-roam-file-p handle opening a buffer with no path (#2169)
* (fix) org-roam-file-p handle opening a buffer with no path

Found this issue when opening a .epub file with nov.el (a package
that renders EPUB file) because nov.el doesn't store the filename
in buffer-file-name, opening it caused errors with org-roam-file-p.

* (minor): org-roam-file-p check if filename is non-nil first
2022-04-23 16:36:09 -07:00
b948cfbe37 (github): remove commit from issue template 2022-04-16 20:34:49 -07:00
3716817618 (utils): add sqlite-connector to diagnostics output (#2162) 2022-04-16 20:32:57 -07:00
608feed855 Update FUNDING.yml 2022-04-16 20:27:34 -07:00
6132155393 (db)fix: fix sqlite-builtin and sqlite-module (#2161) 2022-04-16 20:26:25 -07:00
d8985aa245 (node)refile: fixed org-roam-promote-entire-buffer structure errors (#2091) 2022-04-16 17:09:50 -07:00
61a544cebd (core): ignore org-attach-id-dir by default (#2160) 2022-04-16 14:49:03 -07:00
ddaf7ec10e (db): fix db sync for narrowed buffers (#2159)
* (db): fix db sync for narrowed buffers

* update changelog
2022-04-16 14:25:41 -07:00
8318da895d (db): support emacsql-sqlite-{builtin,module} (#2158)
* (db): support emacsql-sqlite-{builtin,module}

Add support for emacsql-sqlite-builtin and emacs-sqlite-module. Fixes #2146.

* update changelog
2022-04-16 14:16:39 -07:00
9eaf91b801 (fix)capture: Process fn capture templates before whitespace-content (#2157)
* [Fix #2156] Expand fn templates in fill-template before whitespace-content

* Update change log and adding tests related to #2157
2022-04-14 09:50:47 -07:00
3bb45afccb [Fix #2151] org-roam-preview-default-function doesn't copy next node (#2152) 2022-04-09 16:17:53 -07:00
fee008cdfb (docs): fix docs build (#2150)
debian packaging cannot use id links to build docs
2022-04-09 00:54:02 -07:00
36152590ad (feat)export: init (#2138) 2022-03-27 11:11:05 -07:00
a69968fc12 (chore): add changelog entry (#2136) 2022-03-27 10:42:23 -07:00
d71675fb47 (fix) unlinked-references: search symlinked directories (#2130)
Use the ripgrep '-L' option to follow directory symlinks.  This
matches the behavior of `org-roam--list-files-rg'.
2022-03-19 12:02:03 -07:00
3782e88d50 (release): v2.2.1 (#2126) 2022-03-14 23:37:29 -07:00
b4f14eebae (feat)capture: add org-roam-post-node-insert-hook (#2125)
* (feat): add org-roam-post-node-insert-hook

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2022-03-14 23:24:55 -07:00
cce6a05630 (fix)buffer: update defcustom for org-roam-mode-section-functions (#2124) 2022-03-13 09:04:55 -07:00
cc3689f30f (feat)buffer: pass args to org-mode-section-functions (#2123)
* (feat)buffer: pass args to org-mode-section-functions

* update docs
2022-03-12 21:24:11 -08:00
b179a5a1a6 (feat)buffer: add unique option for org-roam-backlinks-section (#2121)
Prior to this commit, when we would render backlinks in the
`org-buffer`, we would render each reference.  This meant that if a
source file referenced the node 5 times, there would be 5 backlink
references in the `org-buffer` (one for each position of the reference).

With this change, we add a parameter that specifies that backlink
sources should be unique.  In the above example, that would mean instead
of 5 backlinks we'd see 1.  And, as a concession, we'd use the lowest
position (e.g. the first reference in the source).

Closes #2119
2022-03-12 13:12:03 -08:00
9172001c11 (chore)readme: update link (#2120) 2022-03-11 21:49:24 -08:00
c51cadfe25 (fix)core: fix broken shell-based file listing methods (#2118)
Change #2025 broke the `org-roam--shell-command-files` filter that
affects all of the `org-roam-list-files-command` methods except
`elisp`.  This causes `org-roam--list-files` to iterate through the
variants executing their commands via `org-roam--shell-command-files`
but to not see any output, until it finally lands upon `elisp` and
gets some results.

The issue is that "#'s-present?" was replaced by

  (or (null s) (string= "" s))

effectively negating the test and converting it to "#'s-blank?".

This addresses that by negating the current test.
2022-03-10 16:07:39 -08:00
f6950a9820 (fix)capture: fill-template preserve whitespace content (#2117)
* (fix)capture: fill-template preserve whitespace content

Preserve the whitespace content given in the capture template, by
caching it and then appending it to the output template. For
Org-capture's purposes, we need to separately ensure that a newline is
present. Adds tests to the various helper functions to illustrate changes.

Addresses #2115
2022-03-10 09:46:53 -08:00
feb9179c9f (docs): add docs for org-protocol (#2116) 2022-03-09 22:11:05 -08:00
f50d6e7376 (fix): caching symlinked files (#2112)
* Revert "(fix): `org-roam-descendant-of-p` bug on Windows (#2089)"

This reverts commit 97a342fd3f.

Reason:

It seems that the `file-in-directory-p` function proposed in #2089 is provided only for
*physical directories*, does not work as we would like with *symlinked directories*.
It dereferences all the symlinks in its path, and previously seemed related paths
cease to be such.

Because of this, such notes are ignored and not indexed, although they
were indexed earlier.
2022-03-03 22:47:24 -08:00
65ea325071 (fix): place cursor after inserted link for new nodes (#2109)
Special care is taken not to move the point if the original point is no
longer the same (i.e. the user moves the cursor after calling the
capture, but before finalizing it). Fixes #2108.
2022-02-27 12:50:45 -08:00
62d311de22 (chore): org-map-entries -> org-map-region (#2107)
org-map-entries is affected by agenda, while org-map-region is not
2022-02-26 18:07:45 -08:00
c8a360afdd (fix)capture: don't update org-id-locations if file is unknown (#2103) 2022-02-24 09:11:20 -08:00
cebe77135a (fix)capture: always ask before deleting capture (#2100) 2022-02-20 16:51:41 -08:00
25d828c32e (chore): fix lints on master (#2099) 2022-02-20 13:14:58 -08:00
fd97c80a26 (chore): pin eldev install to 10.3 (#2098) 2022-02-20 10:40:54 -08:00
97a342fd3f (fix): org-roam-descendant-of-p bug on Windows (#2089)
On Windows, `file-truename` and `directory-file-name` downcase driver
label: "C:/" => "c:/", while `expand-file-name` keep the case
unchanged. If `org-roam-directory` use upper case driver label, `org-roam-descendant-of-p` will alway return `nil`. Fix by only using `file-truename` in the function.
2022-02-20 10:05:12 -08:00
d20480bb8d (fix)node: properly expand extraction file path (#2097)
Previously, the file-path of the new node in `org-roam-extract-subtree'
was incorrect in many circumstances.  Expanding w.r.t. the initial
prompt directory (ie, `org-roam-directory') fixes that
2022-02-19 19:12:53 -08:00
b163c900b8 (fix)capture: correctly update org-id-locations-file after capture (#2086) 2022-02-08 09:12:42 -08:00
0432b00485 (fix)buffer: buffer-toggle: don't destroy window if org-roam-node-toggle reuses window (#2082)
* (fix)buffer: buffer-toggle: don't destroy buffer if reused

Closes #2077

* add changelog
2022-02-06 14:20:24 -08:00
ccfa97ec3a (feat): ensuring that :ref info capture in all cases (#2079)
Let's assume we're evaluating the following region:

```elisp
(org-roam-capture-
     :node (org-roam-node-create :title "Org Roam Homepage")
     :info '(:ref "https://orgroam.com")
     :props '(:immediate-finish nil))
```

Prior to this commit, if you did not require "org-roam-protocol" then
`org-roam-capture-` would ignore the `:info '(:ref
"https://orgroam.com")` parameter.  Once you required
"org-roam-protocol" then the callback hooks that process `:info`'s
`:ref` will fire regardless of whether it comes from org-roam-protocol.

After this commit, you no longer need to require "org-roam-protocol" to
ensure that you capture an `:info`'s `:ref`.

Why is this useful?  When I'm reading through my elfeed RSS feed, I want
to capture an article.  I could use the org-roam-protocol to do this,
but that seems a bit unnecessary given that I'm already in Emacs.

Closes org-roam/org-roam#2078
2022-02-06 11:17:16 -08:00
86e102d990 (fix)dailies: prevent multiple "dailies/" subdir expansions (#2080) (#2080)
When dynamic binding `org-roam-directory` to the "dailies/"
subdirectory also bind `org-roam-dailies-directory` to "./" to prevent
invalid expansions in user-defined hook functions.

Fixes #2070
2022-02-06 11:16:33 -08:00
eed1df90f5 (feat)id: add org-roam-id module (#2072) 2022-01-30 22:54:28 -08:00
905564a7eb (docs)db: document "selecting deleted buffer" error (#2071) 2022-01-30 11:11:09 -08:00
9f7a4a0b02 (feat): allow specifying template keys in remaining org-roam-dailies capture/goto commands (#2065)
This is an extension of PR #2028 [1] by @astery, where the `keys`
argument was added to `org-roam-dailies--capture` `org-roam-dailies-capture-today`.

I extended this argument to also be available in other built-in dailies
functions, as I didn't see any reason why not and it results in my opinion in
more consistent behaviour.

The rationale is the same as in #2028: Allow users to add keybindings (or in my
case hydras) to calls of org-roam-dailies functions with specific template keys,
thus circumventing the selection screen.

So far it seems to work for me. I have only one pet-peeve about
the interface, if the user starts adding keys to all their goto-functions, they
might add

      (org-roam-dailies-goto-date nil "<key>")

Then the key-string will be interpreted as the value for `prefer-future` and
since it's non-nil, there won't be an error.

[1] https://github.com/org-roam/org-roam/pull/2028
2022-01-29 14:07:19 -08:00
aafe4114c2 (fix)node: make filter-fn for org-roam-node-random optional (#2063)
Also, make interactive argument actually apply for other-window
2022-01-25 21:54:06 -08:00
3e2716edf3 (fix)node: added DOUBLE ACUTE ACCENT for unicode normalization (#2060) 2022-01-21 15:50:52 -08:00
445e3594b2 (fix)dailies: remove f require (#2057) 2022-01-20 15:14:24 -08:00
6f5d65abd9 (breaking!)node: simplify default display-template (#2054)
Revert to a simplified `org-roam-node-display-template`, because on
non-vertical completion frameworks it looks and behaves strangely. To
restore the original default behaviour, set
`org-roam-node-display-template` in your Emacs configuration as such:

  (setq org-roam-node-display-template
        (concat "${title:*} "
                (propertize "${tags:10}" 'face 'org-tag)))
2022-01-20 11:19:41 -08:00
817d8036fb (fix)capture: return id in setup-target-location (#2052)
Fixes #2051.
2022-01-19 18:57:07 -08:00
c17310f0de (feat)org-roam-node-random: support filter-fn (#2050) 2022-01-19 14:23:57 -08:00
bf3ebe2121 (feat)capture: create ID before capture process (#2049)
* (feat)capture: create ID before capture process

This allows the ID to be used as part of the capture template. Addresses #2048.

* update changelog
2022-01-19 13:41:20 -08:00
47ad646d51 (docs)completions: document org-roam-node-display-template (#2047) 2022-01-18 15:56:47 -08:00
6263c3a956 (minor)dailies: fixed some wording (#2045) 2022-01-17 18:19:39 -08:00
69742c3d51 (feat)db: add customizability of extra element link parsing (#2042)
Adds two customizable variables: org-roam-db-extra-links-elements and
org-roam-db-extra-links-exclude-keys, which govern which elements are to
be considered for link parsing by Org-roam.

Also added sane defaults to org-roam-db-extra-links-exclude-keys.
2022-01-16 13:30:13 -08:00
5b15159a2c docs: symlink resolution with find-file-visit-truename
<p dir="auto"><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #1869.">Closes</span> <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1004482400" data-permission-text="Title is private" data-url="https://github.com/org-roam/org-roam/issues/1869" data-hovercard-type="issue" data-hovercard-url="/org-roam/org-roam/issues/1869/hovercard" href="https://github.com/org-roam/org-roam/issues/1869">#1869</a></p>
2022-01-15 21:36:28 -08:00
c0c240b975 (chore): Drop f.el and s.el dependency (#2025)
Drops the f.el and implicit s.el dependency.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2022-01-15 21:26:20 -08:00
001de3a874 (fix): fix completions width for Helm users (#2040) 2022-01-15 18:24:52 -08:00
6170cc9928 (release): bump 2021 -> 2022, 2.1.0 -> 2.2.0 2022-01-14 10:53:56 -08:00
cc95540135 (fix): hotfix changelog 2022-01-14 10:51:06 -08:00
24a683d58c (release): 2.2.0 (#2037) 2022-01-14 10:50:21 -08:00
86c9085363 (fix)core: make 'fd and 'fdfind backend work for listing files (#2021) 2022-01-11 15:05:27 -08:00
b67bccd6c2 (feat)dailies: add keys argument to org-roam-dailies-capture-today and org-roam-dailies--capture (#2028) 2022-01-11 14:13:40 -08:00
8b43093d1a (fix)org-roam-with-file: ensure local variables are respected (#2033)
When visiting a file, ensure that local variables are respected.
2022-01-12 03:38:44 +08:00
679ef6ef00 (fix)db: pragma foreign keys to work with sqlite3 (#2018)
* (fix):db: pragma foreign keys to work with sqlite3

This commit is follow-up for PR #2009 should fix issues #1927 & #1910.

Currently, `[:pragma (= foreign_keys ON)]` is present only in function
`org-roam-db--init`. This means the `foreign_keys` is turned on only when the db
file is created for the first time. Subsequent Emacs sessions won't turn it on
as the db file is already present and does not evaluate `org-roam-db--init`.

This PRAGMA needs to be turned on each database connection at runtime according
to sqlite's documentation (https://sqlite.org/foreignkeys.html#fk_enable)

```
Foreign key constraints are disabled by default (for backwards compatibility),
so must be enabled separately for each database connection
```

I have observed that on Windows only the Emacs session that initially creates
the Org-roam db file works correctly with the `sqlite3` option. Subsequent Emacs
sessions have the same "Unique constraint failed" error messages.

I have tested this patch on Windows and Ubuntu; both seem to work in the first
and subsequent Emacs sessions.

I am not 100% sure if the location of the PRAGMA is the best; use it as a
proof-of-cocenpt for the fix. Thank you.

* remove: [:pragma (= foreign_keys ON)] from org-roam-db--init

* fix: defconst org-roam--sqlite-available-p outputs error

When `org-roam-database-connector` is not `sqlite`, it outputs an unnecessary
error when Org-roam starts up as `defconst` evaluates
`(emacsql-sqlite-ensure-binary)`.

```
Org-roam initialization: (error "No EmacSQL SQLite binary available, aborting")
```

For other database connectors, this is not relevant.

* chore: rm org-roam--sqlite-available-p

As per our conversation, org-roam--sqlite-available-p not needed.
2022-01-02 14:03:30 +08:00
ee9a8d423e doc: Add mention of org-cite to bibliography (#2015)
* doc: Add mention of org-cite to bibliography

* regenerate texi

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-12-27 18:07:27 +08:00
d3c7d74329 (feat)db: allow [cite:@foo] links in ROAM_REFS (#2017) 2021-12-27 16:05:17 +08:00
3bf0a0a35d Use locate-user-emacs-file instead of expand-file-name. (#2016)
Then all advices on `locate-user-emacs-file` will work.
2021-12-27 14:37:46 +08:00
d0f17c6477 (docs): correct how to install gcc on Windows (#2013)
* docs: Correct how to install gcc on Windows

PATH needs to be manually set on Windows. Previously, it was explicitly
mentioned that it was unnecessary. More recent experience is that it's necessary.

* regenerate texi

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-12-23 17:22:02 +08:00
c90b2d68df fix(capture): fix whitespacing in org-roam-capture--fill-template (#2010) 2021-12-21 14:23:21 +08:00
91fd1083fe fix(db): fix support for sqlite3 connector (#2009)
Moving the PRAGMA foreign_keys invocation out of the transaction seems
to work now.
2021-12-21 13:42:57 +08:00
7ad5572741 (fix)db: fix node caching (#2006)
Previously node caching used org-map-entries: this only mapped over agenda
entries, hence skipping various nodes. Instead, we should be using
org-map-region, which maps over the entire file.
2021-12-15 16:48:44 +08:00
b6d59e2238 (minor): make the org-roam-node-read prompt configurable (#1993) 2021-12-14 16:05:08 +08:00
2c5f429b24 (chore): remove org-roam-v2-ack (#2005)
It's been long enough since the v2 release, removing the ack requirement
because it creates an annoying warning on native compilation.
2021-12-14 14:19:07 +08:00
7068d63e96 (docs) minor correction to #2002 (#2004)
* (docs): fix examples for .dir-locals.el

Two items:

1. The current example does not work; in order to call a function wihtin
`.dir-locals.el`, you should use `eval`.

  - [StackExchange](https://emacs.stackexchange.com/questions/21955/calling-functions-in-dir-locals-in-emacs)

  - [Working
example buried in an issue](https://github.com/org-roam/org-roam/issues/1527#issuecomment-933674233))

  - `(info "(emacs)Directory Variables")`

2. Add clear instruction to use an absolute path to define `org-roam-directory` in
this context (it's buried in this [issue](https://github.com/org-roam/org-roam/issues/1459#issuecomment-817259656).

* (docs)Fix the `eval` example for subdirectories.

Comment: https://github.com/org-roam/org-roam/pull/2002#issuecomment-991830879

The eval form that uses relative path sets the local variable *relative to the
org file*. This means the eval form woudl need to locate the relevant
`.dir-locals` file by traversing the directory tree upwards from the
file (lightly tested to wrok)

Using absolute path (the first example) should be fine without change (not tested)

* update texi

* (docs) minor correction to #2002

Correcting the example of .dir-locals using an absolute path to avoid confusion.
Lightly tested with a real absolute path in my system; works on my end with a
subdir.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-12-13 17:44:37 +08:00
898295f4a0 (docs): fix examples for .dir-locals.el (#2002)
* (docs): fix examples for .dir-locals.el

Two items:

1. The current example does not work; in order to call a function wihtin
`.dir-locals.el`, you should use `eval`.

  - [StackExchange](https://emacs.stackexchange.com/questions/21955/calling-functions-in-dir-locals-in-emacs)

  - [Working
example buried in an issue](https://github.com/org-roam/org-roam/issues/1527#issuecomment-933674233))

  - `(info "(emacs)Directory Variables")`

2. Add clear instruction to use an absolute path to define `org-roam-directory` in
this context (it's buried in this [issue](https://github.com/org-roam/org-roam/issues/1459#issuecomment-817259656).

* (docs)Fix the `eval` example for subdirectories.

Comment: https://github.com/org-roam/org-roam/pull/2002#issuecomment-991830879

The eval form that uses relative path sets the local variable *relative to the
org file*. This means the eval form woudl need to locate the relevant
`.dir-locals` file by traversing the directory tree upwards from the
file (lightly tested to wrok)

Using absolute path (the first example) should be fine without change (not tested)

* update texi

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-12-13 13:12:38 +08:00
abe63b4360 (fix)node: org-roam-tag-remove respects tag argument (#1998) (#1999) 2021-12-06 13:07:36 +08:00
e992fc27e2 (feat)graph: allow customized graph links and access to the temporary filenames (#1988) 2021-11-30 19:52:40 +08:00
c3889b3b17 (fix)db: insert plain links into db (#1991) 2021-11-28 16:48:54 +08:00
8c3c216191 (hotfix)buffer: hotfix org-roam-buffer-postrender-functions hook 2021-11-26 15:13:54 +08:00
023af3ec32 (feat)buffer: add customization variables for buffer (#1990)
This commit adds 3 custom variables:

1. org-roam-buffer-postrender-functions

This list of functions are run within the Org-roam buffer after the
Org-roam buffer is rendered. For example, one can produce latex previews
for all content within the Org-roam buffer:

(add-hook
'org-roam-buffer-postrender-functions (lambda () (org--latex-preview-region
(point-min) (point-max))))

2. org-roam-preview-function

This is the function used to extract the content to populate the buffer.
It defaults to `org-roam-preview-default-function`, which extracts all
contents within the headline up to the next headline.

3. org-roam-preview-postprocess-functions

This is a list of functions run to post-process the content retrieved
from org-roam-preview-function. It can be used to strip additional
content from the buffer, or perform sentence-unwrapping.
2021-11-26 14:43:26 +08:00
67f10864df (fix)node: fix wrong string-glyph-* aliases (#1985) 2021-11-24 15:13:41 +08:00
c9efbe1dda (fix)db: fix org-roam-db-sync exiting early on unhandled errors (#1983)
When update-file fails, clear the file from the database and show an
error.
2021-11-23 23:47:00 +08:00
ae533fa309 (fix)node: fix org-roam-node-slug compatibility with Emacs 29.1 (#1982)
Emacs commit 3f096eb3405b2fce7c35366eb2dcf025dda55783 introduced
`string-glyph-compose` and `string-glyph-decompose`, autoloading these instead
of the (still existing) `ucs-normalize-NFC-region` and
`ucs-normalize-NFD-region`.

There are three cases:

- Emacs where these transitions have not happened yet (e.g. 27.1):
  `ucs-normalize-NFC-region` and `ucs-normalize-NFD-region` are still
  autoloaded, aliasing the new names to them will keep them usable
  and the code still works.
- Emacs where the new functions are defined (not yet released): the new names
  are autoloaded, no aliases are installed and the code still works.
- A (hypothetical?) Emacs where `string-glyph-compose` and
  `string-glyph-decompose` are renamed.  If `ucs-normalize-NFC-region` and
  `ucs-normalize-NFD-region` do not get their autoloaded status back, the
  aliasing will happen but the functions not autoloaded and the code will
  break in the same way as in #1981
2021-11-23 21:33:47 +08:00
e4188179f6 (fix)utils: fix org-roam-with-file changing the major-mode (#1980)
`org-roam-with-file` should not alter the major-mode if the
mode is already derived from org-mode.
2021-11-23 00:23:03 +08:00
91aae05810 (minor)capture: avoid surprises when STUFF contains the same key twice (#1961)
See also the discussion in #1961.  The summary is that if STUFF contained
the same key twice, `org-roam-capture--put' would favor the last setting in
STUFF while normally `plist-get' and `plist-put' use the first key/value pair
of a plist:

    (let ((org-capture-plist nil)
          (stuff (list :z 26 :z "ignored")))
      (apply 'org-roam-capture--put stuff)
      (list (plist-get stuff :z)
            (org-roam-capture--get :z)))
    ; old implementation => (26 "ignored")
    ; new implementation => Lisp error: wrong-number-of-arguments

In elisp, plists are defined as having no duplicate keys, but there are
no (costly?) runtime checks against this happening by accident.  OTOH,
`org-roam-capture--put' is only ever called with one key/value pair: we can
afford to restrict its interface to accept only one key/value pair and then
there can never be duplicate keys in its input.
2021-11-22 16:01:02 +08:00
a2e46db808 (feat)db: support org-ref v3 (#1977)
Org-ref v3 introduced a new citation syntax, and removed some functions
that org-roam had previously relied upon (e.g. for extracting keys from
multi-citations).

This commit introduces support on two fronts:

1. Add `org-roam-org-ref-path-to-keys` which converts a link path to a
list of keys. This supports both Org-ref v2 and v3.

2. Adds support for parsing multi-citations in refs.
2021-11-20 16:33:12 +08:00
d93423d4e1 fix(org-roam-db-map-links): goto-char added to point-min (#1969)
* fix(org-roam-db-map-links): goto-char added to point-min

* fix(org-roam-db-map-links): unnecessary point move removed

There's no need to move the point to the beginning of the buffer to
get the context of the link at point. See minimal working example
below.

,----
| (with-temp-buffer
|   (org-mode)
|   (insert "[[a]]")
|   (goto-char (point-min))
|   (pp (org-element-context)))
`----

,----
| (link
|  (:type "fuzzy" :path "a" :format bracket :raw-link "a" :application nil :search-option nil :begin 1 :end 6 :contents-begin nil :contents-end nil :post-blank 0 :parent
|         (paragraph
|          (:begin 1 :end 6 :contents-begin 1 :contents-end 6 :post-blank 0 :post-affiliated 1 :parent nil))))
`----

,----
| (with-temp-buffer
|   (org-mode)
|   (insert "[[a]]")
|   (pp (org-element-context)))
`----

,----
| (link
|  (:type "fuzzy" :path "a" :format bracket :raw-link "a" :application nil :search-option nil :begin 1 :end 6 :contents-begin nil :contents-end nil :post-blank 0 :parent
|         (paragraph
|          (:begin 1 :end 6 :contents-begin 1 :contents-end 6 :post-blank 0 :post-affiliated 1 :parent nil))))
`----
2021-11-14 17:13:43 +08:00
1af1639ee0 (feat)db: cache file title into files table (#1963)
adds a column `title` into the `files` table, and the `file-title` property to the node structure.
2021-11-12 23:47:34 +08:00
db573bbc4e (fix)node: fix org-roam-open-id-at-point not working in PROPERTIES drawer (#1964)
Update org-roam-open-id-at-point to use regexp instead of org-element so
the function works wherever the link is.
2021-11-12 15:42:39 +08:00
50cc4d6990 (minor)overlay: fix typos in file (#1960)
Fix typos in comments.
2021-11-11 20:01:23 +08:00
b96efbb444 (minor)chore: fix minor warnings by native compiler (#1959)
* Fix warnings reported by emacs (--with-native-compiler)
* Drive-by fix for org-roam-database-connector's :group
2021-11-11 20:00:07 +08:00
721f167563 (perf)utils: optimize org-roam-plist-map! (#1958)
The old implementation:

- did not handle duplicate keys well (the function would be applied to each value, but only the first value would be updated with the last value's result)
- was quadratic in the length of the input list (for each key, plist-put would search for the first occurrence of the key by going through all previous elements again)
- copied the input sequence even though this was not really needed
- did not provide a result value that could be useful, thus encouraging imperative programming
- did not need to be a macro, and the macro implementation was evaluating fn multiple times and causing warnings in the native compiler because k and v were not bound.
2021-11-11 19:59:36 +08:00
25bc3acce3 (fix)buffer: change preview-content logic (#1955)
Some commit in Org 9.5 changed the AST structure, so we our previous
preview content logic was borked and started showing the full contents
of the file. To be forward compatible we change the content preview
logic, and extract everything within the section.

Fixes #1934.
2021-11-09 22:32:40 +08:00
d8c7f7d4e7 (fix)db: refresh CATEGORY before writing to db (#1953)
Closes #1844.
2021-11-09 15:33:52 +08:00
01c45f9dca (minor)refactor: make prefix checking clearer (#1951) 2021-11-09 15:25:31 +08:00
239929045f (minor)db: filename title sans-extension (#1952)
Use the file name without extension when no TITLE is specified.
2021-11-09 14:15:58 +08:00
d26047e6f7 (minor)db: make check for property drawers case-insensitive (#1949) 2021-11-07 22:29:17 +08:00
36928d655a (fix)completions: fix same-line completions (#1948)
Make final regex group non-greedy, allowing same-line completions. Closes #1790 .
2021-11-06 21:03:36 +08:00
4a2b44252e (fix)db: don't consider links in ROAM_REFS as links (#1947)
Links within ROAM_REFS are no longer added as links into the database.
This prevents self-referencing. Links within other properties are still
valid.
2021-11-06 18:09:50 +08:00
3177b900e7 (perf)db: prefer org-entry-get over org-entry-properties (#1946)
Since we're only looking for a specific property, org-entry-get is much
faster. This should speed up link indexing significantly.
2021-11-06 17:11:38 +08:00
4d71fbdfe1 (fix)db: expand org-roam-directory name as directory (#1945)
Closes #1940
2021-11-06 17:03:54 +08:00
84f58cbc12 (perf)db: require optional libraries only once per function (#1944)
Require optional libraries 'org-ref and 'oc only once per function run:
org-roam-db-update-file and org-roam-db-sync will call these requires at
the top level instead of within the link mapper.
2021-11-06 15:03:04 +08:00
3e47f198c7 (fix)utils: org-roam-set-keyword skip over all drawers (#1931)
Previously org-roam-set-keyword was unable to handle the syntax of the
:LOGBOOK: drawer. We introduce `org-roam-end-of-meta-data` to move point
over all drawers, allowing us to set the keyword in the right place.
2021-11-01 14:39:50 +08:00
c789531e36 (chore)utils: standardize org-roam-property-add/remove fn signatures (#1930) 2021-10-30 16:21:43 +08:00
1b221a1d4a (fix):org-roam-refile: Don't try to refile a node into itself (#1928) 2021-10-29 16:07:25 +08:00
d0fd2c6959 (fix): protocol: set org-capture-link-is-already-stored (#1921)
Closes #1920
2021-10-27 21:28:01 +08:00
2c75b194d8 (fix)ref: fix org-roam-node-from-ref support for org-cite (#1919)
Support Elisp queries of form (org-roam-node-from-ref "@cite_key").
Closes #1918.
2021-10-22 16:15:58 +08:00
c8f8c3e876 (docs): added instructions on troubleshooting org-protocol (#1914)
Co-authored-by: Leo D'Angelo <ldangelo@mac.com>
2021-10-21 15:19:13 +08:00
852042436e (feat)db: support different sqlite3 libraries (#1907) 2021-10-17 19:13:03 +08:00
dafcf0dcf8 (feat)insert: add org-roam-node-formatted (#1909)
Format a node into a string using a templated string (e.g. "${title}")
or using a function.
2021-10-17 16:15:58 +08:00
2b6f8ce615 (perf)db: don't require (probably non-existent) 'oc feature for each org file (#1908)
Instead check if the (autoloaded) function `org-cite-insert' is bound.

This prevents a lot of unnecessary filesystem I/O when generating the
org roam database.
2021-10-16 17:49:26 +08:00
5651f4598c (chore)libraries: s/s-join/string-join/g (#1906)
Remove usages of s-join. s.el is currently pulled in implicitly by f.el.
2021-10-16 16:25:03 +08:00
e9299297f9 (fix)completion: annotation fixes (#1904)
* (fix)Formatter: Ensure that strings are always padded up to the field width

* (feat)Colorize tags by default with org-tag face
2021-10-14 00:24:39 +08:00
617e0021f5 (fix)completions: fix highlighting of formatted/truncated strings (#1895)
* (fix)org-roam-unlinked-references-section: Use truncate-string-ellipsis

The variable can be set to a unicode ellipsis.

* (fix)org-roam-node-read--format-entry: Fix highlighting for truncation

Fix #1801. The truncated part of the string is made invisible. Matching
on the whole string remains possible.

* (fix)org-roam-format-template: Preserve string properties like format

If the variable value carries properties itself, these properties
take precedence. Display templates can be properties with this change.

(setq org-roam-node-display-template
      (concat (propertize "${title:*}" 'face 'font-lock-keyword-face)
              " "
              (propertize "${tags:10}" 'face 'font-lock-constant-face)))
2021-10-13 19:13:45 +08:00
f80515ab5f (feat)completions: separate completion history (#1901)
* (fix) Use read-from-minibuffer instead of completing-read where appropriate

* (feat) Add separate node and ref completion histories

Using separate histories has the advantage that the history only contains node
names and no other strings from other unrelated minibuffer completions.
2021-10-13 12:47:19 +08:00
4af5ff662e Update documentation on migrating from v1 (#1900)
* Update documentation on migrating from v1

* update texi

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-10-12 00:53:32 +08:00
73dfeb60cf (chore): update slack url (#1899) 2021-10-11 17:35:14 +08:00
5b933bd8ec (fix)completions: improve completion-at-point slightly (#1896)
* Allow capfs to run after org-roam-complete-everywhere. This is
  necessary since org-roam-complete-everywhere gets triggered on every
  word, even if no match has been found.
* Simpler hook setup. org-roam-complete-at-point is unnecessary, better
  add the capfs directly.
2021-10-11 13:57:24 +08:00
3a54182bb1 (fix)completion: minor fixes around completing-read (#1893)
* (fix)org-roam-node-default-sort: Add choice nil

* (fix)Ensure that annotation functions are compiled

* (fix)org-roam-node-read: Preserve sorting if sort-fn is non-nil

If the nodes are sorted by org-roam we don't want the completion UI to change
the order. In order to disable org-roam sorting set org-roam-node-default-sort
to nil. Then the sorting of the completion UI is used.

* (fix)org-roam-graph--build: Use ephermeral buffer name

Ephemeral buffers are hidden by default in the completion lists,
which is usually desired for background processes.

* (fix)capfs: Do not use completion-table-dynamic

completion-table-dynamic serves a different purpose. it should only be used if
the candidates are dynamically generated based on the input. This is not the
case for org-roam where we the list of nodes is already available right at the
beginning of the completion. This change should improve performance.
2021-10-10 19:37:57 +08:00
34243a0a90 (feat): allow org-roam-node-display-template to be a closure (#1891) 2021-10-09 21:36:20 +08:00
54d17cc50f (docs): add space so that list item displays correctly (#1880) 2021-10-03 14:02:40 +08:00
54b63db350 (fix)graph: fix default value of org-roam-graph-node-extra-config (#1884) 2021-10-03 13:57:55 +08:00
8f2c51ad21 (refactor)completions: simplify org-roam-node-read--format-entry (#1850)
This commit simplifies the code in org-roam-node-read--format-entry,
saving the entire processing of display properties when no
field-length is specified and thus no truncation needs to happen.
Since in this case, we don't truncate, the bug fixed in #1759 won't
reappear.

This has the beneficial side-effect that existing display properties
in the field-value, e.g., display properties that replace text by
images/icon, are not overridden by us when no field-length is
specified. Note that images anyway don't need truncation of the text
they replace.

This commit also fixes a wrong word in the comment.
2021-10-01 16:03:36 +08:00
3b93c83b23 (fix)db: Require 'oc to get org-cite functionality. (#1849) 2021-10-01 15:45:02 +08:00
a101c548c1 fix(org-roam-node-read): add aliases (#1883) 2021-10-01 15:44:09 +08:00
1b8ece0219 fix(org-roam-node-read): fix regression introduced in #1876 (#1882)
Fix `filter-fn` not working like its supposed to.
2021-10-01 15:09:10 +08:00
0ecbd3a104 fix(org-roam-extract-subtree): Use file-name-as-directory (#1871)
The current implementation doesn't cover the scenario where
org-roam-directory doesn't have a trailing slash. Because of this,
users are enforced to make org-roam-directory end with a trailing
slash.
2021-09-30 19:08:08 +08:00
66e10df943 (fix)dailies: stop asking for time, only date (#1877)
There is no reason `org-roam-dailies-capture-date' should ask for a
time as only a date is necessary.
2021-09-30 18:54:46 +08:00
d2fc4be73b optimize(core) linear->constant time filter-fn (#1876)
in org-roam-node-read, there is no need to check filter-fn for each node, move the branch up, O(n) to O(1)
2021-09-30 18:54:25 +08:00
17d8e84ea5 (docs): fix typo in README (#1842)
instuctions != instructions
2021-09-26 15:36:15 +08:00
777f969b50 (docs): fix typo in docs (#1834) 2021-09-26 15:35:53 +08:00
bc833a9ff4 (fix)capture: ignore file template upon capture goto. (#1858)
Currently, roam allows file template *nominally*, but, if one tries to set
up, it causes trouble.

`goto` functions, like `org-roam-dailies-goto-*`, tries to expand file
template with `org-roam-format-template`, which assumes template is
string. Hence, complains about it.

This commit suppress such malfunctions by do nothing for non-string template.
2021-09-26 15:00:53 +08:00
ec8d250f6c feat(org-roam-db-map-links): Consider links in properties drawers (#1868)
The current implementation uses org-element-map to iterate through all
links in the current buffer. This function doesn't consider links
within properties drawer. This implementation does consider such
links.
2021-09-26 14:44:16 +08:00
1795039ab9 (perf)db: wrap update-file in sql transaction (#1827)
This should lead to some performance gains on buffers with lots of
inserts required (e.g. when the buffer has a lot of links).
2021-09-01 19:43:19 +08:00
a8a36a420b (fix)org-roam-node-visit: pass correctly optional force parameter (#1821)
This function ignored the `force' optional argument because it always
quoted it, resulting in a non-nil value every time.

This makes the suggested code snippet in
https://github.com/org-roam/org-roam/issues/597#issuecomment-907743125
work as expected (not resetting point to the beginning of the "Index"
buffer on every invocation).
2021-08-30 02:30:04 +03:00
340215a16a (feat) core: support new org-mode citations (#1806)
Support caching the new Org 9.5 citations.

Because citations now has first-class support, and are treated
differently from links, they are now cached in their own table.

Org-ref citations, instead of being stored in the links table, are now
stored in the citations table instead.

To use a citation as a ROAM_REF, use the `@citeKey` syntax
2021-08-29 19:33:14 +08:00
941bd1f6b4 (fix)compat: resolve all the missing compile-time dependencies (#1820)
48a5d01726 was wrong, and the closure wasn't the cause. The source of
the issue stems from a missing compile-time dependency on subr-x.

Emacs 28 doesn't seem to require it for the needed functions anymore,
while older Emacsen still do. What even worse, the byte compiler doesn't
seem to complain about such thing on older Emacsen and the error message
produced at the run-time isn't helpful to identify the cause.

Fixes #1814.
2021-08-29 05:41:36 +03:00
48a5d01726 (fix)capture: refactor org-roam-capture--get-if-new-target-a (#1818)
It looks like Emacs' byte compiler is very naive and cannot properly
sometimes compile closures, which causes error like in #1814, at least
on Emacsen <28. One of the possible solutions is to write the code using
less abstractions in between, so the byte compiler would do the right
thing when arranging instructions.

Possibly addresses #1814.
2021-08-28 16:48:56 +03:00
0e6b93a253 (fix)db: prevent invalid refs from crashing db update (#1816)
Previously when ROAM_REFS is non-empty, but the refs are invalid, this
will cause an empty SQL expression and crash the db caching. This fixes
that scenario.
2021-08-28 13:42:30 +08:00
cfabe0ec38 (feat)capture: rename :if-new template property to :target (#1809)
This name will better reflect the current purpose of the property. At
the beginning of the v2 it would only trigger for the new nodes (hence
:if-new), but through the development it's no longer the case, though
the behavior various from each type of the target.

As for now, this will be soft deprecated and won't be strictly enforced
at the user.
2021-08-27 19:45:50 +08:00
ab87a08e17 (fix)db: prevent empty aliases sql expression (#1813) 2021-08-27 19:01:43 +08:00
714ea7a3fc (chore): upgrade dependency of magit-section to 3.0.0 (#1808)
Closes #1803.
2021-08-26 19:15:16 +08:00
4c4b024b49 (fix)capture: always trigger :if-new template for existing nodes (#1807)
Previously, if org-roam-capture- would be triggered for an existing node
it would just move the point to the beginning of the node, ignoring the
target from the :if-new part of the template.

This patch will now also run the :if-new part of the template for
existing nodes, just like it does right now in case of daily
templates (which happened to be never recognized as existing nodes
during the capture process).
2021-08-26 19:04:46 +08:00
5dde894a0c (fix)org-id: condition-case instead of unwind-protect the error handler
unwind-protect will still propagate the initial error, which isn't
desirable and can confuse both, the end-user and us when resolving
issues.

To keep the backtrace clean (in case of other errors), just
automatically detatch the advice once it ran in the error handling
branch. If the user change the file at the runtime, org-id shouldn't
fail with the error as long as it was handled at least once, and it
still will be handled by us during the next session. At the end of the
day it's a very niche edge case, which most of the users shouldn't ever
see.

Fixes #1805.
2021-08-26 02:29:03 +03:00
74a6fd598a (fix)org-id-locations-file: use :test instead of :type when recovering
The latter is incorrect construct for the make-hash-table.
2021-08-25 19:00:50 +03:00
e9ae19c01c (chore): adding changelog entry (#1800)
Related to #1693 and #1681
2021-08-23 14:34:50 +08:00
d25d477b4f (refactor): ensure dependencies are loaded for org-roam-utils.el (#1799)
If org-roam-utils.el is byte-compiled when org-macs is not loaded (`org-with-point-at` macro missing), error can appear about missing `org-with-point-at`.
2021-08-23 01:41:58 +03:00
04b7780ff9 fix: Do not skip invisible headings when getting node at point. (#1798) 2021-08-22 00:01:52 +08:00
858f531d96 (feat)buffer: optimize reflinks fetch (#1795)
Use SQL join instead of iterating over each ref and running another sql query.
2021-08-21 16:18:41 +08:00
f819720c51 v2.1.0 (#1792) 2021-08-21 02:57:40 +08:00
887c49c89c (docs)readme: update installation section (#1787) 2021-08-19 22:05:18 +08:00
d4cbb1d499 (feat): don't move the point when revisiting already visited nodes (#1788)
This is now the default behavior for `org-roam-find-noselect` and
`org-roam-node-visit`, unless FORCE parameter set to non-nil.

Co-authored-by: Duncan Burke <duncankburke@gmail.com>
2021-08-19 15:16:02 +03:00
f29a770af3 (feat)org-roam-version: output commit hash when available (#1786)
Output the commit hash when it's available (e.g. when using straight to
install packages). This comes in handy during debugging during error
reporting.
2021-08-18 16:16:32 +08:00
4a7ecfbed8 (fix): remove duplicate edges from graphs (#1768)
When a node links to the another node twice, two edges appear in the
graph. To keep the graph clean, remove all duplicate edges.
2021-08-18 15:50:57 +08:00
df65654b2f (fix)completions: allow empty field-width (#1785)
This allows the empty field-width to be used, but using an empty
field-width will result in misalignment. This is useful for people who
use completion frameworks like Ido.
2021-08-18 14:03:16 +08:00
b627298171 (fix){preview,grep}-visit: always navigate to the source of the preview
Previously when the preview and buffer would be opened, it would just
display the buffer at the last visited position without performing any
repositiong.

To enforce the correct behavior, the point should be always moved after
the buffer is visited, and not before.
2021-08-18 00:39:42 +03:00
b8a66deae9 (docs): link to org-roam-ui (#1782)
Closes #1780
2021-08-18 00:29:53 +08:00
aafc8606bb (feat): add generalized template prefixes (#1723)
Adds org-roam-node-template-prefixes to split and prefix node properties
as a query language during completions, and allow 0-width template portions.
2021-08-17 23:40:56 +08:00
95afbc676a (refactor)org-roam-node-visit: always return the visited buffer 2021-08-16 23:20:11 +03:00
59faa3fdaa (fix): refactor error handling using ignore-errors
(condition-case nil
    (test)
  (t nil))

Is a construct that's only available starting from Emacs 27. Since
Org-roam supports Emacs 26, gotta use what's given.

Note: ignore-errors isn't exactly the same as the construct above from
Emacs 27. Compare to ignore-errors to would trap all possible signals,
while ignore-errors will only trap "error" signals. This, however,
shouldn't affect us in case of this refactoring.

Fixes #1777.
2021-08-16 22:25:12 +03:00
c51ce08a40 (fix)org-roam-link-replace-at-point: preseve match-data (#1766)
It lies in between org-in-regexp and replace-match. In some situations, like
when the link looks like roam:a s'b, it changes the match-data.
2021-08-16 21:48:29 +08:00
8d4de78fac (fix)org-id: gracefully handle absence of org-id-locations-file (#1769)
This should be more useful than telling the user to run something
like (org-id-update-id-locations (directory-files-recursively ..))

org-id normally stores the org-id-locations-file in
user-emacs-directory, which should always exist if Emacs is installed.
If the path to the location exists, org-id will be able to create the
file on its own, however, configurations often change the location of
this file to a different one, in which case its path might not be
constructed of existing directories (on the file system) and org-id
won't be able to laydown this path for the user.

This causes org-id to throw unhelpful errors (like in #1734, #1700,
\#1688) that don't allow Org-roam to complete capture process or
properly finish migration, and possibly add malfunctions at other
layers.

Ideally this problem should be handled by org-id itself, but for now
this will be only patched in Org-roam.

Fixes #1700 and fixes #1638.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
Co-authored-by: David Wilson <david@daviwil.com>
2021-08-16 21:38:47 +08:00
8a21131d9f (refactor)org-roam-link: use org-roam-node-visit to follow the links
No need to get through org-id-goto, which would query to
org-id-locations instead of our own database.
2021-08-14 00:01:25 +03:00
3c59c7d74e (feat): automatically reveal context when visiting nodes and files
So if the user have folded content it will will automatically unfold the
surrounded context and reveal the thing at point. This should be very
useful for people who alter initial visibility of headings with
:VISIBILITY: property and of the whole file with something like
"#+startup: fold".
2021-08-13 23:18:14 +03:00
5dce6261a2 (feat): replace org-roam-{setup,teardown} with org-roam-db-autosync-mode (#1758)
Comply with the principle of least astonishment, where in Emacs having a
global minor mode for this purpose would be the most expected thing to
have.
2021-08-10 14:02:17 +08:00
39cd819cfa (fix)completions: fix candidate display (#1759)
Recent changes to how candidates are formatted (using a display property
to allow for searching in the full candidate while only showing enough
to fit in the frame), #1754, causes problems when the field value is already
preformatted (a user function, like the one provided in doom emacs,
already applies some faces with `propertize`). Generally the display
string get messed up and formatting gets applied to the whole display.
This PR updates the call that add the display property to the candidate
to remove all the styling from the candidate before the styled (and
truncated) display string is added as a property. This allows the
display string to look correct according to the properties a user has
already assigned.

This PR also fixes another bug from this change, where if a
`field-value` is and empty string `""` it would not get padded out to
the `field-width` causing misalignments between candidates.
2021-08-10 14:01:58 +08:00
eb1d420c29 (feat)db: include self in outline (#1756)
Include the current headline in outline extraction for links, so the
org-roam-buffer contains this information as well.
2021-08-09 17:02:22 +08:00
1f853ad8e6 (fix)completions: use full string (#1754)
When strings in org-roam-node-display-template are truncated, they are
no longer searchable using completions, resulting in suprising
behaviour. This change allows truncated strings to still be searched
according to their original value. Closes #1728.
2021-08-09 15:38:23 +08:00
3c396f9e91 (fix)replace-link-at-point: preserve description (#1753)
Preserve descriptions (if any) when replacing `roam:` links. Fixes #1737.
2021-08-09 15:28:24 +08:00
f227c03672 (fix)org-roam-db--file-hash: Always compute hash of encrypted file (#1725)
When inserting the GPG decrypted org buffer to to DB, make sure that
the hash of the encrypted file is stored.

This prevents reparsing of GPG files over and over again when
synchronizing the database with the filesystem.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-08-09 15:13:45 +08:00
39b2388768 (feat): add :info key to org-roam-node-{capture/insert} (#1741)
In adding this parameter, the external facing methods expose another
point of parameterization for the inner org-roam-capture- method.

This is most useful for the org-roam-node-insert method which has a
complicated inner logic; By adding the :info &key parameter, we
reduce the likelyhood of needing to duplicate that inner logic.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-08-09 15:09:10 +08:00
b24d874f26 (docs) fix typo in org-roam.org (#1747) 2021-08-09 15:01:57 +08:00
dbb4c592fa (docs): Remove internal ID linking (#1751)
Prefer headline links in docs, because internal id linking can cause
issues in documentation building. Closes #1749.
2021-08-09 14:47:46 +08:00
65b463d3c6 (minor)org-roam-format: Fix code formatting (#1726)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-08-08 14:03:10 +08:00
2d8dc8e31b (feat): globally restructure and refactor the codebase (#1724)
Detangle the codebase and change how dependencies are resolved to
allow the package to better modularize and load itself without
introducing circular dependencies, especially when autoloads involved.
2021-08-08 13:53:35 +08:00
56e66f92d2 Force sync: close the database before removal (#1738)
A force resync of the database does not work in Windows (Cygwin):

apply: Removing old name: Device or resource busy, /home/brschoen/.emacs.d/org-roam.db

Therefore, close the connection first and then try to remove the database file.
2021-08-04 22:07:55 +08:00
1d03f87cd1 (docs)capture: document default-val syntax and available expansions (#1721)
Closes #1399.
2021-08-01 14:26:31 +08:00
48d1c152f5 (feat)db: add org-roam-db-update-on-save (#1720)
Adds new variable org-roam-db-update-on-save, which when set to nil,
will disable db updates on file save. Closes #1717.
2021-08-01 14:00:16 +08:00
e8b720faad (minor)org-roam-get-keyword: make-obsolete (#1716)
Prefer Org's org-collect-keywords over org-roam-get-keyword. This
function is not used anywhere, but perhaps some people's configurations
depend on it, so it will be left as is for now.
2021-07-31 14:36:43 +08:00
cf918c3d18 (fix)capture: check if file exists on disk before template insertion (#1713)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-07-31 03:09:13 +08:00
5fc57b2e06 (minor): correct type for INFO argument in org-roam-capture docstring (#1711) 2021-07-30 17:16:16 +08:00
829ee68860 (feat): add org-roam-extract-subtree (#1710)
Adds org-roam-extract-subtree, which converts the subtree at point
into a top-level file node. This is useful for when a node you are
expanding on gets too big, and deserves its own file.

Closes #1104, #1658
2021-07-30 14:49:32 +08:00
127d6efa48 (feat)org-roam-format: add default-value (#1709)
Allow specification of default values in org-roam-format of the form ${key=default_val}.
2021-07-29 23:27:55 +08:00
d3b7c9b921 (fix)capture: check for buffer existence before template insertion (#1707)
Redefine a new file to Org-roam's capture system as one that does not
have a buffer visiting it yet. This means that if a buffer is already
visiting the file, then the HEAD template will not be inserted. This is
important because Org-roam capture does not enforce the save of files,
and this can lead to scenarios where the template is inserted multiple
times to a buffer for a file that has not yet been written to disk.
2021-07-29 22:39:24 +08:00
a84da59b41 (fix)tags: splitting and joining of multiple filetags (#1705)
Current, when fetching file level org tags (from the #+filetags property), multiple tags are split based on the default `split-string` separator. This is incorrect because the org documentation says that multiple file-level tags should be separated by `:` (like headline level tags). This results in a improper splitting (aka no split) of the tag string into multiple tags. This leads to the inability to delete tags that are there.

Similarly, when writing multiple filetags, the tags are joined by " " instead instead of ":" as mentioned in the org docs. This leads to improperly added tags where newly added tags would not be recognized by org.

This PR fixes both problems, parsing is done by string splitting on ":" (with the `OMIT-NULLS` parameter set to true so you don't get a null values from the fact tags start and end with `:`). Joining multiple tags is now done with the `org-make-tag-string` function instead of manually joining on space. These changes result in the ability to add and remove file level tags such that the resulting value of the `#+filetags` property is a valid tag string.
2021-07-29 18:52:07 +08:00
3f2d42142c (fix)org-roam-id-at-point: ignore top-level excluded nodes (#1704)
Previously if a top-level file node is excluded, it would still be
picked up by org-roam-id-at-point. This adds another org-roam-db-node-p
check before returning an ID, fixing the broken behaviour. Fixes #1635.
2021-07-29 11:15:14 +08:00
b3b6277b96 (docs): roam_key -> ROAM_REFS (#1703)
Also fixes #1697
2021-07-29 02:09:53 +08:00
20514b7c6d (fix)autoloads: Exclude org-roam-graphs from patched autoload cookie
`org-roam-graph` doesn't need the patch from #1673, because it sort of
lives on its own island, isolated from the rest of the codebase and can
simply do `(require 'org-roam)` when its autoload is fired.

Otherwise the autoload for this command will never end-up resolved,
because nothing `require`s it in the codebase.
2021-07-28 20:34:59 +03:00
1db4c34c8a (fix): remove invisible tag (#1641) 2021-07-28 21:41:45 +08:00
0c24540639 (feat): allow special 'ignore key in capture template (#1701)
Allow 'ignore as a valid value in place of function
2021-07-28 20:17:59 +08:00
1848ca2495 (fix): fix url in v2 warning (#1695)
Fixes #1689
2021-07-28 02:20:23 +08:00
e31ac73a4d (feat): add filter-fn and templates to interactive commands (#1693)
The rationale for this change is to allow context-specific capture
consideration.  That is to say, in my experience, when I'm working on a
project, I often want to scope my note finding and creation to that
project.  By adding `filter-fn` and `templates` I can easily craft
context-aware functions for my note-taking.

I chose to switch these to `cl-defun` to expose `&key` parameters, which I
find more useful as the method signature grows.

Closes #1681

From the Github Issue:

> Adding a `filter-fn` parameter to `org-roam-capture` and a `templates`
> parameter to `org-roam-capture` , `org-roam-node-insert`,
> `org-roam-node-find` would improve their general utility, and reduce
> fiddling with the more inner functionality of `org-roam-capture-` and
> `org-roam-node-read`
2021-07-28 02:16:00 +08:00
33ed817826 (fix)db: skip nodes with no title (#1694)
In scenarios where a headline node has no title, skip the node instead
of erroring out. Fixes #1692.
2021-07-28 02:11:08 +08:00
de47f0a28d (fix)autoloads: Point autoloads to org-roam.el file (#1673)
At the current state autoloads from non `org-roam.el` unable to start
loading of the package from their own file. See the following to learn
more about the problem:

  https://github.com/org-roam/org-roam/issues/1590#issuecomment-885817825

This is no more than a workaround to bandage a more deeper underlying
problem. Until the more fundamental problem won't be fixed, all autoload
cookies from non "org-roam.el" file will need to manually point to the
main entry point of the package -- "org-roam.el" file, to load it
without causing errors.

Fixes #1590, #1620, #1600 and other similar issues.
2021-07-27 20:33:50 +08:00
04a0fec5c1 (docs): Add intro video to README (#1685) 2021-07-27 13:28:22 +08:00
7723f6ca88 (fix): correct typo about v1 being incompatible with v1 (#1682) 2021-07-27 11:56:55 +08:00
6dc8dda5e5 (fix)preview: fix link preview when headline contains link (#1676) 2021-07-26 13:48:50 +08:00
4455762c38 (fix)capture: Adjust the point for capture targets in missing places (#1675)
The previous fix[0] for capture targets did the right thing. However, it
didn't account that `org-roam-capture--get-point` branches to 3
different paths, where each of them set the point to a different
location, and the fix only addressed the branch in which
`org-roam-capture--goto-location` would run.

This commit adjusts the point for all other branches, which fixes a
problem where you would try to run capture to existing node with
something like `org-roam-capture` and it wouldn't set the point to the
right location; same with ref capturing through the `org-roam-protocol`.

[0]: c9bed390b6
2021-07-26 11:38:05 +08:00
6ce07cdbf7 (fix) org-roam-get-keyword: fix for cjk characters (#1672) 2021-07-25 23:07:51 +08:00
9acd982332 (docs): add org-id-link-to-org-use-id to FAQ (#1670)
Address a common question about Org-roam creating IDs
2021-07-25 10:31:20 +08:00
028c95a011 (fix)migration: upgrade db to v2 before conversion (#1666)
`org-roam-migrate-v1-to-v2` requires the v2 db to already be in place,
so run `org-roam-db-sync` once first.

Fixes #1664
2021-07-24 16:54:46 +08:00
d1e3a5d9be (feat): formalize node dedicated buffers (#1622)
This adds the whole new section in `org-roam-mode.el` for node dedicated
buffers, with a new global command `org-roam-buffer-display-dedicated`,
which supersedes `org-roam-buffer` command.

Along the way this also refactors the code for the persistent buffers to
clean it up, make it more clear in what it does, improve its robustness,
and to make it play nice with the dedicated buffers.
2021-07-23 19:19:30 +08:00
8e89bad945 (migration)docs: Warn requirement of at least Org 9.4 (#1663)
Closes #1661
2021-07-23 19:17:47 +08:00
9c10a3c04c (feat)preview: improve org-roam link preview (#1655)
1. If it the link is at a headline, it shows the headline's content
instead of just repeating the headline
2. If the link is a bullet item in the plain-list, show the full list instead
2021-07-22 01:46:12 +08:00
1aba91eacd (fix)tags: fix tags migration (#1653)
- prevent botching of existing filetags
- insert new tag list using `org-make-tag-string` (colon-delimited) for resilience

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

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

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

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

Addresses #1596

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

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

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

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

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

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

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

* remove reference to emacsql-sqlite3

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-07-18 14:39:30 +08:00
681873759d Refactor some docstring and parameters in org-roam.el (#1594)
This mostly goes over docstrings, updating them in places where it was
outdated and adding them to places where they didn't exist or were
existed as placeholders.
2021-07-18 14:22:45 +08:00
2168490d5a bump docs for Org-roam v2 (#1591) 2021-07-17 22:54:31 +08:00
3a78422a09 (fix): update filter-fn docstring (#1589)
Fix inconsistency for filter-fn in ref and node functions, and update
docstrings to be consistent.
2021-07-17 21:09:38 +08:00
aee3467b3e Org-roam V2 (#1401) 2021-07-17 19:29:30 +08:00
756f6215b6 (feat): allow setting #+roam_alias and #+roam_tag on multiple lines (#1540)
This brings them more in line with how other Org keywords, such as
\#+PROPERTY, are declared.

Previously

    #+roam_alias: abc def
    #+roam_alias: ghi

would result in only the last one ("ghi") being extracted. Now ("abc"
"def" "ghi") are all extracted (in that order).

* org-roam.el (org-roam--extract-tags-prop, org-roam--extract-titles-alias): Accept and return all values in a list, not just from one line.
(org-roam--extract-prop-as-list): New function. List prop extraction refactored from `org-roam--extract-tags-prop` and `org-roam--extract-titles-alias`

* tests/test-org-roam.el: Add tests for defining tags and aliases in multiple lines
2021-06-09 20:21:08 +08:00
53c9a16e90 (fix): files not excluded when org-roam-list-files-commands is nil (#1542) 2021-06-09 20:07:47 +08:00
8ad1414030 (fix): tags: fix vanilla option (#1520)
Set `org-file-tags` before pulling tags from buffer. Should fix the
'vanilla option in `org-roam-tag-sources`
2021-05-13 15:04:49 +07:00
f754160402 (fix): Fix chronology issue between renaming notes and updating links (#1517) 2021-05-12 09:06:11 +02:00
02e35e3b01 (feat): add org-roam-graph-filetype (#1513)
Co-authored-by: Greg Coladonato <gcoladonato3@gatech.edu>
2021-05-06 19:23:46 +08:00
d2e933cc3e Fix auto save buffer in org-roam-doctor (#1493) 2021-05-03 03:36:09 +08:00
15c1a46e41 (doc): Add file-truename to set org-roam-directory (README and documentation) (#1487)
* (doc): Add file-truename to set org-roam-directory

Refer this debuging Slack exchange:
https://orgroam.slack.com/archives/CV160S8EL/p1619089118195300

Not using `file-truename` to set
`org-roam-directory` can lead to an issue that is
hard to identify.

It appears that cache database may updates with
files but `org-roam-buffer` fails to find the file
as symbolic links do not resolve. This is
confusing as the table query to the table seems to
return what appears to be correct entries, but the
backlink fails to insert context around the
link (as Org-roam fails to find the file).

There have been similiar issues -- by making sure
`file-truename` is added in the documentation and
README, it is hoped to eliminate such issues to
recur.

This is probably relevant for V2.

* undo changes to texi

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-04-28 13:43:42 +08:00
9065f6a999 (fix) make roam headline link completion robust (#1473)
Fixes  #1472
2021-04-16 13:02:48 +08:00
997ddcbf4b (docs): update org-roam dir-locals
use absolute path instead of relative path to prevent errors
2021-04-11 14:50:11 +08:00
2d58651699 optimize filename normalize (#1460)
* Normalize slug using ucs-normalize-NFC-string after remove Unicode spacing mark
* Add org-roam-slug--preserve-chars-from-normalization for Unicode Normalization
* Add org-roam-slug-trim-chars instead of org-roam-slug--preserve-chars-from-normalization
2021-04-05 21:35:58 +08:00
8ad57b1218 (fix): support %i in org-roam-protocol (#1445) 2021-03-08 12:57:38 +08:00
0b964ca428 (fix): fix org-roam buffer insert out-of-order (#1448) 2021-03-06 18:01:48 +08:00
643b98eeb3 (fix): dailies: avoid assuming value of org-roam-dailies-directory (#1426) 2021-03-06 10:51:29 +08:00
b0fd12647b (fix): dailies: prevent inclusion of non-org-roam files (#1409)
Fixes #1398
2021-01-28 21:41:42 +08:00
fde40dc1c4 (fix) parsing of missing props (#1406)
Followup from #1404
2021-01-26 14:45:19 +08:00
96b0a52273 (fix) inconsistency between props writing and reading (alias, tags) (#1404)
Fixes #1403
2021-01-26 11:09:19 +08:00
aa52b65a4a (feat): add org-roam-file-completion-tag-position (#1396) 2021-01-23 18:09:52 +08:00
2a1c73c0a3 (docs): clarify behavior of capture functions (#1393) 2021-01-20 21:55:17 +08:00
16c7a7bd93 (doc): update mac protocol instructions (#1390)
use native script editor, rather than Platypus.
2021-01-18 23:02:53 +08:00
1b3a0abd36 (feat): add org-roam-buffer-preview-function (#1388)
Instead of storing preview content in the database, now provide a
function to fetch these on the fly. This paves the way for future
improvements (e.g. showing more lines)
2021-01-17 02:52:39 +08:00
06e5814898 (fix): org-roam-dailies: fix false warning on new file (#1387)
Fixes #1358
2021-01-16 21:06:50 +08:00
cc2572e48b (doc): add my braindump example (Alexey Shmalko) (#1384)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-01-16 20:44:15 +08:00
05deb64d85 (doc) Update brew install script (#1386)
The API for Homebrew Cask changed (https://brew.sh/)
2021-01-16 16:58:13 +08:00
f10fbad386 (feat): allow org-roam-buffer-position to be a function (#1385)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2021-01-16 13:43:00 +08:00
05a9bc44f2 (fix): fix org-roam-capture--get-point (#1376) 2021-01-11 19:38:02 +08:00
3fb4e21adf (fix): fix org-roam-protocol--open-ref creating new files (#1375)
We need to split the ref into its type/file before querying the db for a
match. Throw a warning when `org-roam--capture-new-file` tries to
recreate an existing file.
2021-01-10 23:05:45 +08:00
62bba9755c (fix): keep id backlinks on filename change (#1367) 2021-01-10 16:01:15 +08:00
78a371cdc4 (fix): fix headline completions erroring (#1374)
updates org-roam-with-file to accept nil FILE arg, to operate on current
buffer. Fixes org-roam-link--get-headlines to kill buffer if not
obtaining markers.
2021-01-09 17:49:36 +08:00
15d864a500 (feat): add useful warning message to org-roam-dailies-find-next-note (#1365)
If the user creates a new daily via `org-roam-dailies-find-today`, they
will get a new buffer that hasn't yet been saved to disk. If they then try
to navigate to the previous daily via
`org-roam-dailies-find-previous-note`, they will get the error:

    `Wrong type argument: number-or-marker-p, nil`

This is because the value of the local variable `position` is set only if
the current buffer exists as a file in the dailies directory. It doesn't
until the user explicitly saves it.

That's not a big problem, but the solution is not obvious from the error
message. I added a check that will provide the user with a more informative
error message, so they know how to fix the issue:

    "Can't find current note file - have you saved it yet?"
2021-01-01 12:48:20 +08:00
65c0f0dc8c (feat): use org-link-display-format in org-roam-insert (#1356)
So that, like org-store-link, the computed description does not
contain the links that were captured.
2020-12-25 13:43:41 +08:00
48e195dd82 (refactor): refactor org-roam-capture (#1355) 2020-12-22 21:57:02 +08:00
777f6d23ec (feat): Support file-property drawers (#1353)
* (feat): Support file-property drawers

Add support for file-property drawers in property extraction. This means
the following is now supported:

:PROPERTIES:
:ROAM_ALIAS: alias
:ROAM_TAGS: tag1 tag2
:END:
2020-12-19 23:59:40 +08:00
8f1cf7b449 (fix): set-global-prop: prefer lowercase (#1352)
Prefer lower-case version of Org properties. Fixed bug where
adding/deleting props will alter the original case of the Org property.

Addresses #1342
2020-12-19 19:23:27 +08:00
3ce6e299d4 (doc) Update README (#1351) 2020-12-19 17:53:25 +08:00
ecf515f650 (doc): Add footnote for tab completion (#1348)
Follow on to #1345.

The discussion in the Slack thread further clarified what was exactly
confusing for a beginner reader of this Getting Started. When a user is using
the built-in completion (no ivy, no ido), then `org-roam-find-file` does not
immediately show any files -- instead, the user has to press TAB. This is not
explicitly mentioned.
2020-12-19 16:42:43 +08:00
43831c5819 (fix): allow link captures (#1347)
Previously we had set `org-capture-link-is-already-stored` to `t` in
org-roam captures, because org-roam-protocol stores links. This
prevented regular captures from utilizing the %a element in the
templates.

Instead, only set `org-capture-link-is-already-stored` in the
org-roam-protocol capture command.

Fixes #1341.
2020-12-16 21:12:21 +08:00
4d63f99fe8 (doc): Add async update to Getting Started (#1345) 2020-12-16 20:58:13 +08:00
57cfb3dbb7 (fix): index file: prevent malformed absolute path (#1346)
When `org-roam-directory` doesn't end with trailing slash and
`org-roam-index-file` contains relative filename, absolute path
to org-roam index file returned by `org-roam--get-index-path` is
malformed and invalid.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-12-16 20:31:32 +08:00
9c23218553 (docs): fix docstring for org-roam--get-title-path-completions (#1344) 2020-12-15 20:26:43 +08:00
7ad32e8395 (feat): make org-roam-buffer-update interactive (#1343)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-12-15 20:04:48 +08:00
d87dd011aa (fix): preserve existing description in a roam: link on replace (#1327)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-12-15 19:47:51 +08:00
f2976fa3be (fix): close files intelligently after modifying (#1330)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-12-15 18:33:55 +08:00
8aa793b021 (docs): org-roam-doctor: fix docs for prefix arg (#1337) 2020-12-12 14:34:04 +08:00
be95b42d32 (docs): fix link to org-capture (#1329)
Required capitalization.
2020-12-01 12:42:33 +08:00
cff1168ac1 (doc): fix link to manual (#1328) 2020-11-28 19:44:15 +08:00
06d0db736a (internal): remove error-checking for olp (#1326)
The `org-roam-capture-find-or-create-olp` function will throw the same
error, so we don't have to explicitly catch and throw.
2020-11-24 21:09:28 +08:00
fb0662efe7 (fix): uniqify title and tag extraction (#1325)
Remove duplicates from title and tag extraction, arising from
multiple (or the same) sources.

Fixes #1324
2020-11-24 20:00:49 +08:00
9ca5461a2f (fix): fix mode toggle not re-enabling buffer-local hooks (#1321) 2020-11-23 19:59:30 +08:00
33805c3ff5 (fix): don't set default-directory if no file is passed (#1318)
This fixes calls like (org-roam--with-temp-buffer nil ...). Fixes #1310, #1316.
2020-11-21 16:42:50 +08:00
3a4ff76508 (fix): dailies: fix capture changing window configuration (#1314)
`*-captures` commands now maintain window configuration, while the
`*-find` commands change to the file.
2020-11-21 01:27:03 +08:00
bf41352c1c (fix): fix title change not triggering rename if new title contains old (#1315)
title

Fixes #1303
2020-11-20 21:32:36 +08:00
1b598a4618 (fix): dailies: misc fixes (#1309)
Fixes #1293
2020-11-19 23:00:33 +08:00
ab34dd138d (fix): fix rename file corrupting database (#1308)
The rename file advice is passed relative file names: e.g. "foo.org" ->
"bar.org". This was not accounted for, and paths in the Org-roam
database are supposed to be absolute paths. This caused the storing of
relative paths in the Org-roam database, which were then never purged.

Fixes #1304
2020-11-19 22:26:59 +08:00
b17cc3b1e3 (internal): org-roam-db--update-maybe -> org-roam-db--upgrade-maybe (#1307) 2020-11-19 21:55:07 +08:00
f9b1e53894 (fix): do not display buffer if it is not processed in db (#1302)
Finding an Org-roam file that does not exist yet triggers the find-file
hook, resulting in an Org-roam buffer update, attempting to show the
file. However, if the file does not yet exist, attempts to show the file
will not work, since the database does not contain the relevant
information yet.

This bug has always been present, but was only recently made visible by
the code cleanups in #1284.

Now, we ensure that the file has been processed by the database before
attempting to re-display the buffer.

Fixes #1297
2020-11-18 20:24:21 +08:00
dbed2bcf5d (fix): set default-directory in org-roam-with-temp-buffer (#1300)
This ensures that relative paths in keywords such as `#+setupfile:` and
`#+include:` work when building cache etc.
2020-11-18 18:33:57 +08:00
060a29c91d (fix): use correct type for org-roam-db-update-method (#1295)
Fixes #1294.
2020-11-18 18:17:00 +08:00
8efec080e0 (ci): fix ci test flow (#1301) 2020-11-18 18:07:05 +08:00
61e01430e0 (perf): improve database update on 'immediate (#1285) 2020-11-16 21:27:23 +08:00
d70198bba9 (fix): fix cache updates on org-id creation in non-existing files (#1288)
closes #1287
2020-11-16 10:38:58 +08:00
face683e00 (internal): remove org-roam--get-title-or-slug function (#1284)
Every file has a title when saved into the database, so this function is
redundant in most cases (e.g. in org-roam-buffer, where backlinks are
fetched from the database).
2020-11-15 19:44:36 +08:00
baf0dd9d00 (doc): document tag completions (#1282) 2020-11-15 14:36:49 +08:00
a9fd6c0fc7 (fix): fix idle-timer not created on org-roam-mode (#1281)
Fixes #1280
2020-11-15 14:21:03 +08:00
6502874576 (doc): document completion-at-point (#1279) 2020-11-15 04:43:57 +08:00
8401784cd2 (doc): document org-roam-tag-sources (#1274) 2020-11-14 21:12:08 +08:00
6dc316c450 (doc): fix menu-comment styling (#1273) 2020-11-14 14:17:08 +08:00
48ef3fee11 (doc): document org-roam-title-sources (#1271) 2020-11-13 22:55:52 +08:00
16c520068b (doc): Fix typo (#1272)
The `olp` option in the lab notes example was swapped.
2020-11-13 14:22:58 +01:00
b1608bf869 (feat): capture: create OLP if does not exist (#1270)
Remove the requirement that the OLP already exists in the captured file.
Also, make OLP available beyond dailies functionality.
2020-11-13 16:29:00 +08:00
cc01cf346e (release): v1.2.3 (#1269) 2020-11-13 14:22:18 +08:00
eaf99cba03 (doc): minor changes (#1268) 2020-11-13 13:17:28 +08:00
65a2cb6efd (fix): readme: fix link to manual 2020-11-13 02:52:48 +08:00
bc12d1cf04 (feat): add org-roam-db-update-method (#1264)
* (feat): add `org-roam-db-update-method`

Add `org-roam-db-update-method`, which can be one of two choices:

1. `immediate`: the cache is updated upon file changes
2. `idle-timer`: Marks the org-roam database as dirty. If Emacs idles
for some seconds, the Org-roam cache is updated. This is the default,
and current behaviour.

The idle method makes for a smoother editing experience, but some
inconsistencies can be faced.

* org-roam-update-db-idle-seconds -> org-roam-db-update-idle-seconds
2020-11-12 19:48:40 +08:00
a86d82b20e (fix): fix backlink-to-current-p killing buffers (#1263)
Change `org-roam--backlink-to-current-p` to only perform a DB query.
2020-11-12 16:11:35 +08:00
d4c875b53b (doc): doc stylistic changes (#1262)
- style tables properly
- reduce pre font-size
2020-11-12 15:40:27 +08:00
2159b6a846 (web): Remove mention to company-org-roam on index.html (#1261) 2020-11-12 08:27:22 +01:00
1db4c22950 (doc): remove top-level TOC (#1260) 2020-11-12 15:13:59 +08:00
9c0f030ffd (doc): add indexes (#1259)
Add keystroke, command, function and variable indexes
2020-11-12 14:56:48 +08:00
983d7a8798 (doc): Link org-journal to section on daily-notes (#1258) 2020-11-12 07:47:44 +01:00
910b37268e (doc): make manual single-page (#1257)
This should make things easier to browse/search for. Also simplify styling.
2020-11-12 14:32:59 +08:00
d39556a78b (fix): unlinked-references: support filenames with spaces (#1256) 2020-11-12 12:05:14 +08:00
167553b8ee (doc): various improvements (#1253)
- options: explicitly enable smart quotes on export
- zettelkasten introduction: add sections for fleeting notes and
  permanent notes for easier access and reference
- anatomy: add a missing period
- encryption: clarify org-roam-encrypt-files is a user option
- roam protocol: remove extraneous heading
- roam protocol: small grammar fix
- doctor: explain what the doctor does by default
- org-roam-bibtex: explain part of what orb actually does
2020-11-11 18:04:09 +08:00
76affe177a (doc): reflect that we now allow multiple refs (#1251) 2020-11-11 15:42:45 +08:00
e96685b1a9 (fix): respect original link type during replacement (#1252)
During automatic link replacement, respect the original link type
i.e. absolute links remain absolute. Fixes #1228.
2020-11-11 14:25:50 +08:00
aef71f1623 (docs): use ox-texinfo+ (#1250)
This generates texi documents with understanding of variables and
functions.
2020-11-11 13:00:49 +08:00
d913447939 (fix): Fix command signature (#1247) 2020-11-10 18:04:59 +01:00
47e83f7d3f (fix): Deprecate old ord commands (#1246) 2020-11-10 17:57:26 +01:00
023bcce867 (internal): remove unnecessary variables (#1244)
For captures, enforce that `:file-name` needs to be specified, and
`:head` when not provided defaults to the empty string (i.e. no head)
2020-11-10 23:58:16 +08:00
4f6eb285bf (feat): Overhaul org-roam-dailies (#978)
Implement ideas from `org-journal` to `org-roam-dailies`.

Update the doc.
2020-11-10 14:31:38 +01:00
8c81104816 (feat): unlinked-references: add error message if rg has no PCRE2 support (#1243) 2020-11-10 13:48:50 +08:00
7602b8c48d (feat): Allow ORP to capture the webpage's selection (#1239)
* (feat): Temporarily store link when capturing with ORP

* org-roam-protocol.el (org-roam-protocol-open-ref): Replicate default
`org-protocol' behaviour temporarily for storing links
* org-roam-capture.el (org-roam-capture--capture): Prevent stored link from
being reset

When capturing a web-page with org-roam-protocol, a link is now temporarily
stored in `org-store-link-plist' via `org-link-store-props'.  This is to allow
the forwarding of properties to `org-capture', one of them being `:initial'
which contains the content of the selected text in the browser.

* (feat): Add toggle for storing link when capturing with ORP

* org-roam-protocol.el (org-roam-protocol-store-links): Add new toggle
(org-roam-protocol-open-ref): Conditionally store link for later used

Building up on b2ee5f2c68, the user can now
decide whether to store links when capturing with org-roam-protocol (default
nil).

* Update changelog
2020-11-08 13:30:16 +01:00
c6797cbd75 (feat): Allow one file to have multiple roam_key statements (#1215) 2020-11-07 15:33:31 +08:00
440461a90b (feat): add org-roam-prefer-id-links to select linking method (#1238) 2020-11-07 15:06:12 +08:00
4d423a916e (doc): add note on unlinked references and encrypted files (#1236) 2020-11-05 16:34:11 +08:00
b184cdaef0 (feat): use :preselect for ivy-read completions (#1234)
This way, in case of the initial-input being an exact match, ivy will suggest this one first.
2020-11-04 17:37:50 +08:00
b2cc997976 (fix): fix relative link replacement (#1233) 2020-11-04 15:25:08 +08:00
bc5c41d212 (fix): widen before title extraction (#1232)
Prevent renaming file and changing links incorrectly due to using (org-narrow-to-subtree) and saving.
2020-11-04 13:34:40 +08:00
7c83a84db3 (fix): only update relative path of file links (#1226) 2020-11-04 00:07:31 +08:00
56c47fbff8 (internal): make sure there are no byte-comp warnings... (#1220)
...about undefined functions or unused lexical variables.

Undefined functions: for example, s.el and org-element should be
`require`'d when their functions are used.

Unused lexical variables: if Org isn't loaded yet, dynamic variables
defined in org.el would be treated as lexical and byte-comp would emit
this warning. This is especially important in the future as
native-comp / gccemacs will optimize away unused lexical variables,
and we cannot rely on Org having been implicitly loaded before our
modules are compiled.

Explicitly stating in our modules that the variables are dynamic
prevents that.
2020-10-30 14:23:53 +08:00
0d235686f4 (fix): fix id-face killing buffers (#1218)
org-roam-id-get-file no longer falls back onto the current buffer: It queries the org-roam database, and optionally org-id-locations, and declares that it does not exist if it isn't in either.
2020-10-27 00:25:39 +08:00
ac2044b84b (fix): save current position in mark ring before id-open (#1217) 2020-10-26 13:36:35 +08:00
cffa0bd201 (fix): support multidir with dirty db flag (#1216) 2020-10-26 11:22:40 +08:00
bd8b5587f5 (internal): rename link columns (#1213)
from -> source
to -> dest

"from" is a reserved keyword in sqlite, so we avoid it.
2020-10-25 22:33:43 +08:00
b937bc9655 (internal): simplify db update operations (#1212)
Instead of maintaining a file queue to process for updating the Org-roam
database, we instead simply call `org-roam-db-build-cache` to rebuild
the db. `org-roam-db-build-cache` feels Fast Enough(TM), and basically
runs instantly if no files are modified. This greatly simplifies the
code, basically allowing to maintaining a single code path for db
operations.

This PR should also address the slowness wrt to ID links. Org-roam now
builds the headline information first, so there is no need to read the
file to check if the headline is there. The downside to this is that
this only works for IDs in Org-roam files.
2020-10-25 16:35:05 +08:00
a7cf48ea89 (fix): org-roam-db-build-cache: fix order of processing (#1201)
* (fix): org-roam-db-build-cache: fix order of processing

Org-roam used to perform the removal of deleted files towards the end.
This can cause some issues with db rebuilds. Consider this scenario:

1. Create a file `foo.org` with `id:abc`
2. Run `org-roam-db-build-cache`
3. Delete `foo.org`
4. Create a file `bar.org` with `id:abc`
5. Run `org-roam-db-build-cache`

Here Org-roam will complain that the id `abc` is a duplicate, and error
out, because the data for `foo.org` has not yet been cleared from the
database. This PR reorders the db creation steps the following way:

1. Figure out which files no longer exist, and which files are modified
2. Clear the database for these files, leaving only files that are
unmodified in the database
3. Insert new data from modified files into the database
2020-10-19 22:12:34 +08:00
46327991ef (fix): let-bind org-roam-last-window (#1198) (#1200)
* org-roam-buffer.el (org-roam-buffer--find-file): Make
org-roam-buffer--find-file insensitive to mutation of global
variables
2020-10-19 21:14:55 +08:00
a4da8f32bf (fix): use org-roam-link-title-format in link replacement (#1199)
* (fix): use org-roam-link-title-format in link replacement

Makes `org-roam-format-link` respect `org-roam-link-title-format`.

Also removes lowercasing via prefix argument in `org-roam-insert`, not
sure how many people use it.

* update changelog
2020-10-19 21:02:25 +08:00
5d483f2d4d (fix): fall back to org-id search ID face computation (#1195)
* (fix): fall back to org-id search ID face computation

Fixes the scenario where the face is reported as invalid although it is
part of Org's ID files (e.g. in the agenda).

Fixes #1191.

This can however slow face computation a lot (when there are many org
id/agenda files). Here, we choose to focus on correctness.

* Document faces, default to only applying to Org-roam notes
2020-10-19 13:47:07 +08:00
09fd41ce24 (fix): do not kill temp buffer when extracting links for file (#1193)
Otherwise it breaks `org-roam-db-build-cache` as it relies on temporary buffer.
Without keeping the buffer, `org-roam--extract-links` kills it and any further
functionality of file processing breaks.
2020-10-19 12:12:36 +08:00
a0c4abf579 (fix): allow title changes that don't modify filename (#1189)
Prevent error when trying to move file to same name

Prevent string matching in org from messing with the current re-search-forward
position which has caused infinite broken search
2020-10-16 02:19:15 +08:00
cbf1b585ac (doc): fix org-roam-buffer-window-parameters documentation (#1190)
Closes #1188
2020-10-16 00:23:47 +08:00
66cd5b6226 (internal): simplify internal db cache update api (#1186) 2020-10-12 21:55:32 +08:00
5348654a7e (feat): add interactive functions for managing aliases and tags (#1183) 2020-10-12 14:51:10 +08:00
87d7c07e87 (fix): correct usage of org-element api (#1181)
content-end -> contents-end
2020-10-11 14:52:27 +08:00
02fda3adb1 (docs): document org-roam-buffer-window-parameters (#1180)
also remove documentation on deprecated variable ~org-roam-buffer-no-delete-other-windows~
2020-10-10 22:28:29 +08:00
82bd6c6cda (fix): fix org-roam--extract-links (#1179)
Co-authored-by: Boris Buliga <boris@d12frosted.io>
Co-authored-by: Gustav <gustav@whil.se>
2020-10-10 21:34:16 +08:00
e8d3516fa8 (fix): fix org-roam--extract-ids at outline level 0 (#1174) 2020-10-09 22:00:58 +08:00
0cce9d1165 (release): Org-roam v1.2.2 (#1168) 2020-10-06 03:02:41 +08:00
7a76f7b476 (internal): remove compat functions (#1167)
* remove org-roam-link-make-string
* remove org-roam-link-store-props and org-roam-link-decode
2020-10-06 02:45:59 +08:00
ceee2348e0 (fix): fix [[*]] completion (#1166)
Links now complete to [[roam:*foo]] rather than the incorrect [[*roam:foo]]
2020-10-05 23:24:32 +08:00
32bf91077e (internal): move org-roam.db default location (#1164)
Move the default location of `org-roam.db` to the user's Emacs
directory. This is a more sensible default: those who sync their
Org files would not have the database synced over as well.
2020-10-05 18:56:28 +08:00
d973e8f6e0 (feat): support file-level IDs (#1163)
Additionally cache IDs at outline-level 0, now that property drawers are supported in Org 9.4.

Update org-roam--format-link to prefer ID links wherever possible. That is, when a file has an ID, use an id link instead of file link.
2020-10-05 16:57:54 +08:00
6759bee56b (doc): add FAQ for completion into manual (#1161)
Fixes #960
2020-10-01 12:30:05 +08:00
ce17e7eecd (fix): fix buffer ref-links (#1160)
remove stray `(org-roam-link-make-string)` call
2020-10-01 11:21:09 +08:00
369753c98b (feat): clean up link expansions (#1157)
Adds `org-roam-link-file-path-type`, used for link path computation
wherever sensible. This includes in the org-roam backlinks buffer, and
in link replacement.

Also moves link expansion/fixing from cache build to Org-roam buffer
render time. This reduces cache build time, but makes buffer rendering
slightly slower.
2020-09-30 19:21:02 +08:00
93d8c477fe (feat): remove file store-link function override (#1155)
Previously we had overwritten the Org's store link function for files,
to create IDs if the point was under the headline. This has several
issues:

1. It becomes impossible to store a link to the file using `org-store-link`
2. This override is global across Org, although we had a guard in
`org-roam-store-link`
3. IDs are created during an org-capture, because org-capture calls `org-store-link`

This is unnecessary. Org provides `org-id-store-link` instead for this
purpose. Instead, we advice `org-id-new`, to queue the file for a DB
update if an ID was created.
2020-09-30 15:27:25 +08:00
30d52e5508 (fix): fix org-roam-id-find buffer-kill logic (#1154) 2020-09-30 13:26:14 +08:00
19c5e9b0f3 (fix): pass file name to extract-headlines. (#1153)
Another location where filename needs to be passed down as per #1150.
2020-09-30 11:57:07 +08:00
3ec2ed8874 (perf): disable org-agenda while building the cache (#1147)
`org-mode` builds the org-agenda-files menu entry for every file
visited. This functionality isn't required and useful when building
the cache in temporary org buffers.
2020-09-29 15:51:12 +08:00
be64f107e9 (internal): replace find-file-noselect with with-temp-buffer where possible (#1150)
`find-file-noselect` is affected by the user's init.el, and there is
little control over what is being activated. For database updates, read
access is all we need, so we use `with-temp-file`.
2020-09-29 12:42:23 +08:00
64d8ba1900 (fix): fix org-roam-completions-everywhere (#1145)
Fix org-roam-completion-everywhere still producing fuzzy links
2020-09-27 15:51:26 +08:00
2f4034cebc (docs): add docs for Org-roam unlinked references (#1144) 2020-09-27 15:21:49 +08:00
668f135aa1 (internal): remove file-name and header default (#1143) 2020-09-27 04:29:10 +08:00
273d0dffa6 (fix): fix refs not showing in backlinks buffer (#1140)
This changes ref extraction to parse the ref using the org plain-links
syntax. This works for arbitrary `cite` links, and web links.

Link storage and ref lookup is now based on the path (e.g.
`//google.com`) or `author_year`.
2020-09-27 02:20:23 +08:00
fadb515a87 (fix): fix emacsql-sqlite3 check (#1142) 2020-09-27 02:14:27 +08:00
2e58d3df19 (fix): add emacsql-sqlite3-executable null check (#1139)
Fixes #1138
2020-09-26 20:39:58 +08:00
c05368a16b (fix): prevent link-extraction from keeping buffers open (#1131)
Fixes #1129 .

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-09-26 19:42:59 +08:00
346bbf50a1 (feat): enable completions for both roam and fuzzy links (#1133)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-09-26 18:05:13 +08:00
176b2bf19d (docs): add git installation instructions (#1136) 2020-09-26 13:55:59 +08:00
ae32c465de (feat): move fuzzy links to roam: links (#1105) 2020-09-23 17:58:18 +08:00
da6af3a468 (fix): fix additional buffers opening from ID face (#1130)
`org-roam-id-find` opens the file containing the ID to get the marker.
We don't need to get the exact point for face computation.

Fixes #1129
2020-09-23 13:09:16 +08:00
cd87cfdd58 (perf): simplify hash computation (#1127)
Treat encrypted and non-encrypted files the same.
2020-09-22 20:35:48 +08:00
feda1f41e5 (feat): extract idle timer interval as a customizable value (#1122)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-09-22 15:10:43 +08:00
d170c4ac85 (fix): remove other occurrences of file-truename (#1125)
org-roam-buffer should no longer be resolving the symlinks as well.
2020-09-22 14:23:02 +08:00
f59c18fda5 (docs): update org-roam-graph-show in README.md (#1121) 2020-09-20 17:11:40 +08:00
f5257cefa7 (ci): make CI pass on non-blocking errors (#1117) 2020-09-19 16:45:38 +08:00
18c0f2da7f (ci): do not return on package-lint error (#1116) 2020-09-19 16:23:09 +08:00
b2aa8bdad0 (feat): remove all symlink resolutions (#1109)
file-truename calls alone accounts for over 20% of CPU samples in org-roam-db-build-cache. It's expensive and unnecessary. To get an absolute path, expand-file-name alone is enough.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-09-19 16:12:08 +08:00
925d225f13 (fix): fix file-name change not working on new files (#1113)
PR #1076 prevented the title change hook from causing errors for new files,
but completely disables the behaviour. To cause the title hooks to take
effect, we set the local variable `org-roam-current-title` upon save,
regardless of whether the hook ran.

This should have the effect of enabling the title change behaviour upon
first save, assuming the save succeeds.

Addresses https://org-roam.discourse.group/t/org-roam-update-file-name-on-title-change-works-discontinuously/767
2020-09-18 14:52:51 +08:00
6c89eb82af (fix): perform link expansion only on file links (#1110)
This prevents ID links from being expanded in the Org-roam buffer
2020-09-17 14:29:40 +08:00
8ec4cafa2b (fix): fix link expansion on URL links (#1103)
Attempting to perform link expansion on URL links caused extreme slowdowns in Windows environment. Ref #1038 #1067.

Co-authored-by: Noboru Ota <me@nobiot.com>
2020-09-17 13:28:42 +08:00
e881ea26b1 (internal): bump required version of emacsql-sqlite3 to 1.0.2 (#1102)
This version includes the fix that ignores the user .sqliterc which can
interfere with expected behaviour.

See https://github.com/cireu/emacsql-sqlite3/pull/15 for more details.
2020-09-15 15:10:36 +08:00
efb592907e (fix): fix org-agenda hangs on face computation (#1101)
Org expects face functions to save-match-data, or it would lead to
infinite recursions with use of some Org functionality such as
org-agenda (h.t. @myshevchuk for figuring this out)

Fixes #1096 and fixes #1045.
2020-09-13 20:42:28 +08:00
da507a5bee (fix): add vanilla option for tag custom interface (#1100) 2020-09-13 02:56:32 +08:00
fc3a03977d (feat): add vanilla org-mode-tag-source (#1093)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-09-13 02:45:45 +08:00
70539c40d2 (fix): fix backlinks in org-roam buffer (#1099)
previously when the file is a symbolic link, the backlinks buffer display will not show correctly.
2020-09-13 01:48:07 +08:00
fac0465dd8 (feat): add org-roam-enable-fuzzy-links (#1097)
`org-roam-enable-fuzzy-links` controls whether to enable Org-roam's
fuzzy link behaviour. This can be undesirable to some users, who would
like to use [[foo]] links to reference named blocks
2020-09-12 19:30:05 +08:00
6d09323218 (fix): fix sort by mtime in completions (#1087) 2020-09-07 10:14:49 +08:00
e3ff54616e (feat): sort backlinks by occurrence (#1086)
Sort display of backlinks in backlinks buffer by occurrence. The default
link extraction behaviour causes it to be inserted roughly in the
reverse order.
2020-09-04 21:05:49 +08:00
d3a920a5b7 (fix): fix link outline extraction (#1085) 2020-09-04 20:37:02 +08:00
8fff0b86f9 (fix): fix link-extraction extracting wrong element (#1084)
Fixes #1082, #1077, #1074

When reverting link extraction to using the `org-element` api, the
preview content (org-element-at-point) was incorrectly extracted,
causing incorrect preview content and cryptic messages.
2020-09-04 15:09:12 +08:00
df174bb52b Fix link extraction error when a file starts with blank lines (#1081)
org-element-at-point doesn't just determine the closest element -- if
it's "within blank lines at the beginning of buffer", it returns nil.

  ;; Within blank lines at the beginning of buffer, return nil.
  ((bobp) nil)

Skip whitespace at beginning of buffer to avoid this.
2020-09-03 10:02:10 +08:00
cb10b16fc0 (feat): add org-roam-tag-face (#1079)
`org-roam-tag-face` controls the appearance of tags in the minibuffer.
Defaults to a bold face.
2020-08-31 23:02:12 +08:00
9ff57c8fd1 (fix): don't run title-change-hooks on new files (#1076) 2020-08-30 02:16:13 +08:00
a6aabf4038 (feat): rename file on title change (#1073)
Adds `org-roam-title-change-hook`. This now contains two functions:

1. `org-roam--update-links-on-title-change`: updates the link
description of all files that link to the current file.
2. `org-roam--update-file-name-on-title-change`: updates the current
buffer's filename to reflect the updated title.
2020-08-27 22:13:23 +08:00
f8c8fcee6b (test): reduce expected cache time-to-build (#1072)
Several performance improvements have vastly improved the cache build
time. We reduce it so CI catches any further degradation.
2020-08-27 13:23:58 +08:00
6f0a38e64e (feat): disable unnecessary org-mode startup for temp buffers (#1057)
Set `org-inhibit-startup` to `t` to reduce the amount of time taken to set up org-mode buffers. For example, this disables latex image generation, and table alignment.

Also introduces `org-roam-doctor-inhibit-startup`, which speeds up `org-roam-doctor` runs.
2020-08-27 13:23:38 +08:00
b8b180d60d (feat): rename link descriptions on title changes (#1071)
Previously the rename file advice was responsible for trying to update
the link descriptions as well. This was brittle and didn't work in some
cases.

The rename-file-advice has now been altered to solely deal with breaking
links. We use the before and after-save-hooks to determine whether the
title has changed, and update the link descriptions accordingly.
2020-08-26 17:24:58 +08:00
fe5566c0dc (fix): fix non-fuzzy links being treated as fuzzy links (#1070)
Fuzzy links were initially detected as anything within double brackets.
This could include code in source blocks.

This PR introduces `(org-roam--fuzzy-link-p)`. This uses an additional
check using the `org-element` API, and ensures that the link type is
fuzzy (not a file: or https: link, for example).

Fixes #1069, and an array of unreported bugs:

1. Link extraction into the database should no longer pick up false
links (in code blocks, for example).
2. Link completion will only truly work within fuzzy links
2020-08-26 15:27:45 +08:00
cc8a2184b7 (internal): replace org-element-parse-buffer calls with regexp search (#1068) 2020-08-26 13:44:35 +08:00
4f0b1b8d43 (internal): use regexp search for link-extraction (#1066)
Replace call to org-element-parse-buffer with simple regexp search.
2020-08-25 18:24:29 +08:00
0a64a5def4 (feat): allow enabling of link completions everywhere (#1062)
Completions for Org-roam files can be enabled everywhere by setting
`org-roam-completion-everywhere` to `t`.
2020-08-25 17:09:10 +08:00
2cd993e0a5 (internal): use regexp-search for fuzzy link replacement (#1065)
This should improve responsiveness on large files
2020-08-25 13:57:02 +08:00
82ac6b6b9c (internal): speed up extraction of global props, headlines, and title (#1061)
Avoids usage of org-element-parse-buffer, preferring simple regex searches.
2020-08-24 22:14:15 +08:00
f6bf9d9401 (fix): remove org-roam-completion-case-sensitive (#1060)
Case sensitivity for completions is already controlled via
`completion-ignore-case`, so we remove this variable that doesn't
actually do what is expected.
2020-08-24 16:59:53 +08:00
38234b491d (feat): add case sensitivity for Org-roam completions (#1056)
Completions are now case-insensitive by default.
`org-roam-completion-case-sensitive` can be set to `t` to allow
case-sensitive completions.
2020-08-22 20:21:01 +08:00
4e5b52fbd3 (fix) strip todo, priority, and tags from headline candidates (#1052)
Fixes #1047
2020-08-20 15:01:19 +08:00
c33867e6bc (feat): allow ignoring files matching a regular expression (#1046)
Adds a new user option, `org-roam-file-exclude-regexp`, to exclude files from Org-roam.
2020-08-18 16:16:56 +08:00
30b2e97426 (feat): add org-capture interactive options to org-roam-capture (#1035) 2020-08-16 19:51:37 +08:00
9ee591f7a4 (fix): fix possibility of multiple idle timers (#1042)
This change ensures that `org-roam--file-update-timer` has only one
instance per Emacs instance. Fixes #1037
2020-08-16 12:08:19 +08:00
2081e1268a (feat): add org-roam-enable-headline-linking (#1030)
When disabled, Org-roam will not attempt to cache headlines, and will not create IDs.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-08-13 11:18:06 +08:00
11aac39a1b (feat): propagate file changes on idle-timer (#1032)
Queue up file updates, to be processed on idle timer. This makes saving files more responsive for large files.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-08-12 17:07:27 +08:00
e58ec84b7c (fix): Require org-macs in org-roam-db to fix undefined macro (#1033)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-08-11 21:22:54 +02:00
7813b1fe1f (internal): fix CI for compat functions (#1031)
Following the advice from the coding conventions from the Emacs manual,
we preface the compatibility functions with the org-roam namespace.
2020-08-12 00:04:15 +08:00
22006be751 (docs): set org-roam-db-location with multiple org-roam-directories (#1027)
Fixes #1025
2020-08-11 13:51:29 +08:00
0318983cac (feat): cache all link-types (#1009)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-08-10 15:59:02 +08:00
9753ee451f (fix): fix fuzzy link completions (#1022) 2020-08-10 15:38:17 +08:00
8c442a72de (fix): fix fuzzy-links opening for file (#1023) 2020-08-10 14:31:10 +08:00
0ed9057a87 (feat): tag completion via capf (#1017) 2020-08-09 21:49:06 +08:00
5d02e6407b (fix): remove save-buffer on id creation (#1018)
This can trigger a lot of hooks, which may not be desirable.
2020-08-09 21:03:27 +08:00
4fa966d366 (feat): fuzzy link auto-replacement (#1011)
Fuzzy links can now be auto-replaced on navigation and on file-save, if
there is already a match. This is now the default behaviour, controlled
via `org-roam-auto-replace-fuzzy-links`.
2020-08-09 12:20:02 +08:00
6d03e7626d (fix): save-restriction for db update (#1016) 2020-08-09 12:06:34 +08:00
c437052b4b (docs): update url of org-fc (#1012)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-08-09 11:55:07 +08:00
a26c262048 (fix): Widen before updating file (#1014) 2020-08-09 00:24:12 +02:00
4f3668a1e3 (fix): fix get-backlinks failing for unescaped strings (#1008)
Revert to emacsql vector format to retain escaping. Fixes #1007.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-08-07 16:06:24 +08:00
09b5357a94 (docs): remove readthedocs build (#1006)
This has long been superceded by the internal and published online manual
2020-08-06 11:15:14 +08:00
444eedc799 (internal): remove with-template-error wrapper (#1004)
This has caused more confusion than it has helped.
2020-08-06 10:51:24 +08:00
da6fdd7542 (feat): support fuzzy links (#910) 2020-08-05 20:52:27 +08:00
f18ecd1fc3 (feat): Implement new face-toggle for id-links (#999)
Also fix a typo.
2020-08-04 15:26:51 +02:00
f206b5bbf9 (fix): skip unreadable files while building the cache (#995)
When using gpg encrypted files it might happen (intended) that on a
certain machine there is no key to decrypt that file.  Currently an
error of type 'file-error' will be raised and the cache building
process will be aborted.  So in a certain sense org-roam will not
be functional in that case.  Furthermore, when the the cache building
process is run from the emacs initialisation it will come to a halt as
well and the user will be left with a halfworking emacs instance.

This patch changes the behaviour to just skipping over offending files
while removing them from the db at the same time.  Here an offending
file is any file that cannot be read for indexing.  As it stands this
case only works reliably for the case of missing gpg keys.

An error buffer will still show up and be prominently displayed,
besides a log to the message buffer.

Implementation note: This io error will only be caught during the
first part of the cache rebuilding ("files and headlines").  If such
an error would occur during the second part ("rebuild the rest")
another (more severe) cause might be the problem and the user better
be informed the hard way (i.e. the same behaviour as before).
2020-08-03 16:58:22 +08:00
30fab7bcc4 (feat): Add toggle for custom-faces for Org-roam links (#997)
* org-roam.el (org-roam-link-use-custom-faces): New toggle
(org-roam--file-link-face): Refactor for new toggle
2020-08-02 18:27:38 +02:00
76d2e3f6b4 (feat): Simplify org-roam-store-link (#994)
* (feat): Simplify org-roam-store-link

Drop the wrapper, and refactor as an org-store-link function.
2020-08-01 08:02:57 +02:00
8881c9732b (fix) Change Emacs date to 1976 (#993)
cf. https://en.wikipedia.org/wiki/Emacs
2020-07-31 15:29:59 +02:00
0aa0a7c05a (doc): Add target audience section (#990) 2020-07-31 02:15:42 +08:00
ea4bfbb55d (fix): fix face-related functionality (#988)
- Ensure `org-roam-store-link-file` has no effect if org-roam-mode is
disabled
- Remove custom styling for ID links when org-roam-mode is disabled
2020-07-30 09:56:13 +08:00
0443351800 (internal): move faces into own file (#987) 2020-07-30 09:12:56 +08:00
6345d0c22e (feat): Protect region targeted by org-roam-insert (#974)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-07-27 20:16:39 +02:00
f2c1500beb (doc): Fix docstring (#979) 2020-07-27 11:43:23 +02:00
89e9121f26 (release): Org-roam v1.2.1 (#975) 2020-07-27 01:03:35 +08:00
c536fd4f2e (fix): check if path is remote before using file-truename (#970)
this prevents cache builds from stalling, on paths that point to remote files
2020-07-27 00:30:54 +08:00
20f876aa6b (feat): enable nested captures (#966)
This PR enables the long-awaited nested-captures.

1. Adds a hook to org-capture-prepare-finalize-hook, which installs org-roam-capture--finalize into org-capture-after-finalize-hook if the capture is an Org-roam capture. This function contains key functionality for Org-roam to Do The Right Thing after specific interactive functions, such as finding the file, or inserting a link.

2. A patch for org-capture-finalize. Specifically, we make org-capture-plist valid during org-capture-finalize.

3. Many hacks that were originally in place are now replaced with nicer alternatives.

Co-authored-by: Leo Vivier <zaephon@gmail.com>
2020-07-27 00:21:41 +08:00
863ae2427e (feat): add customize settings for capture templates (#968)
adds ability to customize capture templates using the Customize interface for:

1. org-roam-capture-ref-templates
2. org-roam-dailies-capture-templates
3. org-roam-capture-immediate-template
2020-07-26 15:15:56 +08:00
379d5e4770 (doc): Add Andreas to backers (#969) 2020-07-25 16:33:36 +08:00
4d992ce9e3 (doc): add debian/ubuntu installation instructions (#965)
Addresses #964
2020-07-23 22:46:21 +08:00
1d9968bf69 Make the db caching more efficient for gpg encrypted files (#963)
Before this patch all hash-sums were computed over the files or
buffers content.  For encrypted files this means that we first have
decrypt the file before we can compute the hash-sum.  So when the
cache get's updated all gpg files need to be decrypted which is a very
expensive operation and nearly defeats the purpose of having a cache
in the first place (for gpg files).

This changes the computation of hash-sums for gpg encrypted files.
Instead of the content the raw files on disk will be read.

This shouldn't interfere with the current use of hashes.

There is one ugly (but otherwise inconsequential) ward, though.
For open buffers of to be gpg encrypted files we need to compute the
hash sum over the contents as well.  This is because there is
no (easy) way to get the encrypted version.  The consequence is that
that buffers file will be rehashed again (then using the bytes on
disk).  But all other non changed gpg files will only be hashed once,
as desired.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-07-23 22:36:57 +08:00
650744adc7 (doc): Create ‘Getting Help’ (#961)
* (doc): Create ‘Getting Help’

* README.md: Add ‘Getting Help’

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-07-22 19:06:54 +02:00
d099f9bef9 (fix): enable org-mode in temp buffers (#957)
Fixes #956.

The extraction of links rely on appropriate regexp being set for
outline-mode, to determine the outline information. Because the
information were extracted in a temporary buffer, the outline regexp was
not set. This corrects for that, but probably adds significant
extraction time.
2020-07-22 20:59:35 +08:00
b5f3f04318 (doc): Add an FAQ section (#959)
* README.md: Create FAQ section and mention `C-M-j` for `ivy`
2020-07-22 09:07:49 +02:00
c20c8f9a0a (fix): Check sqlite3’s executability using boundp (#954)
Fixes #837. The existing merged fixes do not actually work, because fboundp tests for a function.
2020-07-21 15:51:43 +08:00
c24fb51b03 (feat): cache entered template variables (#952)
Fixes #951.
2020-07-20 22:14:21 +08:00
80390b5a84 (fix): fix display of preview content (#950)
Don't modify line-breaks in preview content. Closes #630.
2020-07-19 13:33:01 +08:00
eb7ee0ef6c (docs): add docs on notes versioning (#949) 2020-07-19 12:37:53 +08:00
fb5beeb14d (docs): clarify org-roam-completion-system (#948) 2020-07-19 12:26:00 +08:00
10e91a88c1 (docs): make explicit need to set org-roam-directory early (#946) 2020-07-18 18:04:52 +08:00
4cdab9103f (fix): fix possible nil dbs on update operations (#945)
Addresses #942
2020-07-18 13:09:40 +08:00
4ec4e60358 (doc): Add SVG source for logo (#943) 2020-07-16 10:20:42 +02:00
7a4b15fd36 (fix): Check if link-description is empty prior to inserting in db (#927)
* (fix): Check if link-description is empty prior to inserting in db

Caused problems with plain links, i.e., those not framed by
brackets (e.g. `file:foo.org` or `id:$uuid`).
2020-07-11 23:42:05 +02:00
f9fea29c44 (feat): Add customize settings to org-roam-capture-templates (#924)
* (feat): Add customize settings to `org-roam-capture-templates`

Declare `org-roam-capture-templates` with `defcustom` and update the
docstring.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-07-11 20:48:10 +02:00
569aeb84ed (fix): Change symbol used for delta (#925)
7f56df7f4d introduced the delta symbol in the
db-rebuild message to make it clearer the the db was updated as opposed to
being completely rebuilt.

However, the unicode symbol used, U+1D6AB, which is the mathematical, bold
variant of the Greek letter is not present in many fonts.  Switching to
U+0394, the base Greek letter, is better for compatibility.
2020-07-11 20:19:55 +02:00
1574e0d351 Exclude backup files from renaming advice (#915)
Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-07-10 23:18:33 +02:00
fffef6711f (fix): Update rename-file-advice to new schemata (#917)
Caused by #908.
2020-07-10 19:59:07 +02:00
ef23f507ec (fix): Adapt get-title-or-slug to new schemata (#916)
Follow-up to #908.
2020-07-10 19:34:12 +02:00
f1dbe3fdf9 (fix): fix org-roam graph building with new db schema (#914) 2020-07-10 19:23:38 +08:00
efba3c2bf0 (internal): normalize titles in database (#908)
Instead of storing titles as a list within in the Org-roam cache, e.g.
file, ("title1" "title2"). We normalize it and store it as:

file, "title1"
file, "title2"
2020-07-10 14:36:54 +08:00
6770c3eaf5 (feat): Implement basic output for find-ref with C-u arg (#907) 2020-07-10 08:24:04 +02:00
b8aa5c1f23 (feat): Improve interactive format for ref completions (#906) 2020-07-10 11:47:07 +08:00
ca4a7421bc (docs): Update org-roam-capture documentation (#904) 2020-07-09 12:56:17 +08:00
3348298527 (internal): org-roam-db--clear -> org-roam-db-clear (#902)
Since it is a called interactive, it should be given a public name.
2020-07-08 15:55:23 +08:00
d77f897400 (feat): support more ref links (#900)
This adds support for all sorts of ref links (http, https, and any
custom link types). If the ref is not a file or org-ref citation link,
the full link path is used.

Closes #744.
2020-07-08 12:29:06 +08:00
9f7ed4353c (feat): add org-roam-random-note (#898) 2020-07-07 14:45:28 +08:00
d19a711a44 (fix): fix escaping of backslashes in graph generation (#897)
Fixes #884
2020-07-07 13:07:10 +08:00
9766862e84 (docs): Add forkrul to BACKERS (#896) 2020-07-07 12:36:27 +08:00
aedfca8de2 (fix): rename links as long as old file is Org-roam file (#894)
Previously, if the new file is no longer an Org-roam file, links will
not be fixed. The current behaviour is now to perform the link fixes as
long as the old file as an Org-roam file.

Closes #893
2020-07-06 21:34:52 +08:00
21bc220ed3 (docs): fix qutebrowser roam-protocol binding (#891) 2020-07-06 11:39:11 +08:00
d58fc31dfb (docs): add docs for using winner-mode as history (#890) 2020-07-05 23:07:41 +08:00
64a0bfd168 (docs): add Burke to BACKERS (#889) 2020-07-05 22:43:13 +08:00
3aff6b2be7 (bugfix): prevent file-exists-p opening tramp links (#885)
Links like /ssh:me@host:/ cause emacs to lock up asking for the password repeatedly due to using file-exists-p in a function passed to font lock.

Co-authored-by: Herbert Jones <herbert@hj-desktop.home>
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-07-05 22:36:35 +08:00
7f56df7f4d (internal): add delta symbol in cache build message (#886)
This makes it clearer that the message shows the changes in the database, and not the total number.
2020-07-05 17:48:17 +08:00
0830da4504 (tests): increase perf test threshold (#887)
Things take more time to run now that we are also caching headline hierarchies.
2020-07-05 17:36:44 +08:00
3a1c826aa0 (docs): add protocol instructions for Windows and WSL2 (#882)
See #870
2020-07-04 00:25:23 +08:00
1e11a3a16f (feat): add customizable org-capture function (#877)
New option: `org-roam-capture-function`

Specifies which command is used by org-roam to run the org-capture
process. The default behaviour maintains compatibility with earlier
versions of org-roam. I.E.:
- uses `org-capture`.
- immeadiately chooses the first capture template when
  `org-roam-capture-templates` has only one template.

When you've changed `org-roam-capture-function` AND
`org-roam-capture-templates` has multiple templates,
`org-roam-capture-function` is run interactively to
start the org capture process.

Eg. usage: `(setq org-roam-capture-function 'counsel-org-capture)`
2020-07-01 23:24:40 +08:00
e33c3bcb3f (internal): lower default value of org-roam-db-gc-threshold (#872)
The high value has been reported to cause significant slowdowns, so we
reset the default, and add documentation for its customization instead.
Ref #834
2020-06-28 15:16:14 +08:00
610d4ced85 (internal): save-match-data on outline extraction (#871) 2020-06-27 21:26:03 +08:00
2f13d1fe64 (internal): fix expand-file usage in org-roam--expand-links (#866) 2020-06-26 14:57:27 +08:00
ee28b5e6b1 (docs): improve roam-ref docs (#865)
The current documentation made me think that bookmarklet feature was limited to Firefox. This patch slightly improves it.
2020-06-26 14:52:08 +08:00
79c75ac174 (feat): Add header level to backlinks buffer (#863)
adds the outline hierarchy to the backlinks buffer
2020-06-25 12:40:22 +08:00
c59d6c4f7c (internal): wrap db updates in a sql transaction (#862)
This will ensure atomicity with updates and should stop any partial updates that may occur.
2020-06-24 13:30:44 +08:00
220f395c1f (feat): add org-roam-find-file-immediate (#852)
Addresses #852.
2020-06-22 16:19:27 +08:00
76b2ac3460 (bugfix): fix tag extraction for symlinked directories (#857)
* (bugfix): fix tag extraction for symlinked directories

Resolves symlinks before computing relative paths, fixes #855

* Update changelog
2020-06-21 19:34:04 +08:00
11e0aa4c55 (feat): warn on duplicate IDs and refs rather than fail (#854)
Instead of having db update operations fail, a useful error is shown, and the db updates complete. Closes #816.
2020-06-21 17:00:20 +08:00
408e38f8ba (perf): use sqlite transactions, and GC less (#847)
We use sqlite transactions to commit changes into the database, rather
than storing all the data in a list before running one big insert.
Hopefully this gives a noticeable perf boost.

We also add `org-roam-db-gc-threshold`, which shaves time by deferring the garbage collection to the end.
2020-06-19 18:27:14 +08:00
f16de357a6 (feat): add 'first-directory option for org-roam-tag-sources (#851)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-06-19 18:22:52 +08:00
abd81918e1 (docs): update docs link in README (#850)
Thanks for the catch!
2020-06-19 12:04:09 +08:00
6a37fff1e6 (fix): fix bad upcase for org-roam-tag-sources (#849) 2020-06-19 01:58:17 +08:00
527c693f65 (docs): Update links to online page (#848)
We now own and use the orgroam.com domain
2020-06-18 19:30:42 +08:00
76d419cc89 (fix): fix emacsql-sqlite3-executable possibly unbound (#846)
On old versions of emacsql-sqlite3, this will catastrophically fail.
2020-06-18 14:44:26 +08:00
3f2f7e3ff7 (docs): use org-roam-graph-show on README (#844) 2020-06-18 02:56:25 +08:00
fd73da9410 (feat): org-roam-insert: return selected file (#839)
This is useful in scenarios when you want to automatically do something with the
context where the link was inserted.
2020-06-17 19:07:35 +08:00
11902bc790 (tests): add performance tests to CI (#841) 2020-06-17 18:38:10 +08:00
185f9877ae (tests): add test for headline extraction (#840) 2020-06-17 15:32:12 +08:00
1276e801c0 (feat): add customizable org-roam-title-to-slug-function (#833)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-06-17 14:58:11 +08:00
04d335cc40 (fix): Check sqlite3’s executability before existence (#838) 2020-06-17 14:52:26 +08:00
N V
8b16e5d520 (feat): org-roam-find-file-function customization (#807)
Allow users to specify a function for finding files in various commands.
Can be let-bound to define new commands that suit user preferences.

See: #790
2020-06-16 15:37:03 +08:00
7ab67436a7 (feat): Implement ‘org-roam-insert-immediate’ (#814) 2020-06-15 18:34:27 +08:00
87403b330c (feat): Split org-roam-buffer-toggle into -activate and -deactivate (#819)
Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-06-14 08:12:23 +02:00
N V
fae45434b5 (doc): Add :ensure to use-package declaration (#820)
Ensure use-package installs org-roam.

See: #803
2020-06-14 11:58:42 +08:00
9cf26494e8 (ux): update the error message for org-roam-unlinked-references (#818)
Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
Co-authored-by: Santiago Gepigon <santiago.gepigon@gmail.com>
2020-06-13 22:33:37 +08:00
0d5efe1c14 (fix): fix unlinked-references for older Emacs (#812)
Emacs' in-built rx.el was rewritten in Emacs 27, and the form `anychar`
only exists in later versions. We use the older form `anything` that has
support even in Emacs 26.

Emacs 26: https://github.com/emacs-mirror/emacs/blob/emacs-26/lisp/emacs-lisp/rx.el#L889
2020-06-13 11:14:57 +02:00
2eb0aac88a (feat): Switch to a minor-mode for the dev-suite (#805)
* (feat): Switch to a minor-mode for the dev-suite

Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>

Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>
2020-06-12 22:01:52 +02:00
eca07277ce (release): Org-roam v1.2.0 (#802) 2020-06-12 23:29:52 +08:00
48158e67d4 (feat): add org-roam-unlinked-references (#787)
`org-roam-unlinked-references` uses rg to search for unlinked references. Regex courtesy of @angelsl.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-06-12 23:21:01 +08:00
278e3df95d (fix): Remove space in docstring (#800) 2020-06-12 13:54:49 +02:00
48d2c199ac (fix): Fix local-var loading for dev suite (#799) 2020-06-12 13:49:33 +02:00
7f7ba857de (feat): add support for headlines (#783)
Achieve 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 you’re not using `org-id` in your global configuration for Org-mode.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-06-12 18:51:13 +08:00
cf368ab4d8 (chore): remove unused mkdocs.yml (#798) 2020-06-12 17:47:18 +08:00
43dbad1f62 (UX): Add more meaningful error message for sqlite3 (#776)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-06-12 17:14:59 +08:00
040913151f (docs): update docstring for org-roam-db-location (#797)
Closes #792
2020-06-12 13:59:25 +08:00
1a964520f2 (doc): Add documentation about multiple templates for capture (#796)
* Add sentence noting that you can have multiple templates

* Add sentence describing that `file-name` can specify directory

* Make changes in .org instead

* Fix grammar and reflow

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-06-12 07:14:09 +02:00
39276362d7 (docs): add entries to changelog (#795) 2020-06-12 11:31:06 +08:00
1168c9b6da (fix): Fix syntax for calling compiled versions of functions (#791) 2020-06-11 08:39:12 +02:00
92e02b5d14 (internal): remove redundant org-ref require (#788) 2020-06-10 20:02:37 +08:00
26b90b28e3 (fix): fix false failure from case in org-roam-doctor 2020-06-10 18:33:12 +08:00
f4376f39a9 (docs): update roam-ref qutebrowser configuration (#780) 2020-06-09 16:49:11 +08:00
898c6c8178 (docs): Add link to Roam-migration (#779) 2020-06-09 16:11:03 +08:00
30599cc3e8 (fix): fix prop extraction failures (#772)
This fixes a bug introduced in #770. Interestingly,
`org-element-property` always returns the prop in allcaps, so a
string-equal would have been sufficient. This commit reverts all usages
of `org-roam--extract-global-props` to use the upcase version of the
properties.
2020-06-07 22:10:47 +08:00
9d5a34d0f4 (internal): lowercase all properties (#770) 2020-06-07 16:25:34 +08:00
N V
5bf3e596c8 (feat): prefer lowercase versions of org in-file settings (#769)
See #768
2020-06-07 13:55:07 +08:00
N V
14f83bdb07 (fix): org-roam-capture append to existing file (#767)
org-roam-capture was querying plist for :file-path
instead of :path.

See: #766
2020-06-07 13:29:26 +08:00
81e7a5b231 (fix): fix org-roam--list-files elisp fallback (#764)
Always fallback to the elisp implementation, when the shell commands
return garbage (possibly from shell configurations).
2020-06-06 19:27:15 +08:00
1756ec6441 (fix): fix bad behaviour on malformed properties (#763)
Org-roam now skips over bad properties and throws a warning for the
given file that contains a malformed property. This allows most of the
database rebuild to complete, and for the user to fix the offending
file.

Fixes #728.
2020-06-06 16:48:42 +08:00
c61f7e20f2 (fix): simplify org-roam--str-to-list (#762)
This simplifies `org-roam--str-to-list`, and ensures that it parses
numbers correctly too. Fixes #745.
2020-06-05 20:27:02 +08:00
563252a6f6 (fix): remove alias for org-roam-buffer-no-delete-other-windows (#761)
This variable is made obsolete, and replaced with
`org-roam-buffer-window-parameters`, but their shape are different and
cannot be used interchangeably.
2020-06-05 15:54:02 +08:00
fdaf07da43 (fix): fix update-tags to correct delete removed tags (#760)
see https://github.com/org-roam/org-roam/pull/759#discussion_r435704588
2020-06-05 14:33:39 +08:00
5d25c4552d (internal): change org-roam-db--update-tags to only add non-nil tags (#759) 2020-06-05 13:36:13 +08:00
c46d153fd3 (internal): Make org-roam-db--get non-interactive (#758) 2020-06-04 22:07:09 +08:00
0cd4bc05c5 (feat): make roam properties case-insensitive (#757) 2020-06-04 16:39:23 +08:00
c5e0c6b9fa (fix): fix bug in org-roam-buffer-get-create (#754) 2020-06-04 12:32:45 +08:00
721689d5b5 (feat): add org-roam-buffer-window-parameters (#750)
The variable `org-roam-buffer-window-parameters` gives more
flexibility in customizing the org-roam-buffer window parameters.
`org-roam-buffer-no-delete-other-windows` is deprecated in favour of
this.
2020-06-03 23:25:31 +08:00
d36d3185ae Remove reliance on the current buffer when opening the *org-roam* window (#731)
If the `org-roam-buffer--get-create' function is called from a hook
then `get-buffer-window' will return `nil' since the current buffer
may not have been placed in a window yet.  This eventually leads to an
error.

This change moves some code around so that we can use
`save-selected-window' to allow temporary focu
s on the org-roam
side window so the resizing functions can work.
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-06-03 21:11:46 +08:00
3ad43b0823 (internal): make org-roam--org-link-file-bracket-re more intelligible (#749) 2020-06-03 12:38:56 +08:00
b2594b84ae (docs): add section introducing the Zettelkasten method (#719) 2020-05-31 14:22:44 +08:00
3440e647c0 (fix): add org-roam--directory-files-recursively (#737)
Emacs 26 does not have the follow-symlinks option in
`directory-files-recursively`, so we have to add it ourselves.
2020-05-30 22:32:30 +08:00
1d28b07a7c (fix): org-roam--list-files: canonicalize filenames (#735) 2020-05-30 20:32:32 +08:00
195669ad10 (docs): Add missing Org package-install instructions (#734) 2020-05-30 19:04:42 +08:00
47feff5a8b (feat): allow for symlinks in the org roam directory (#733) 2020-05-30 18:52:25 +08:00
N V
7200364d31 (internal): remove org-roam--touch-file (#718)
Unused function.
2020-05-28 02:37:01 -04:00
873a314746 (fix): hide citelinks if buffer has no ROAM_KEY (#717) 2020-05-28 14:23:18 +08:00
N V
91c905d7e3 (docs): org-roam.el clarify documentation (#716)
Fix typo, reword docstring, remove decorative ellipses
2020-05-28 14:12:01 +08:00
f9a9f15a8b (fix): don't print no citelinks if org-ref is not present (#714)
Change confusing behaviour where org-roam buffer prints "no citelinks"
even when org-ref is not present.
2020-05-28 13:53:10 +08:00
N V
9ddadc9c25 (internal): org-roam-doctor require s, dash (#715)
Silence flycheck warnings
2020-05-28 01:44:13 -04:00
d0fab34287 (fix): fix support for Emacs 26 built-in org (#711)
org-make-link-string was changed to org-link-make-string in org 9.3. But Emacs
26 ships with org 9.1. Defining an alias to the old function name when using an
older org version.

Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>
2020-05-28 13:35:24 +08:00
N V
e3281fc31f (internal): Exclude org-roam-compat.el from linting (#713)
org-roam-compat.el may contain symbols that belong to other packages.
e.g. functions backported to older versions of Org mode.
2020-05-28 01:22:51 -04:00
N V
5ee38f2d89 (fix): autoloaded commands load org-roam-mode (#712)
Users should not have to explicitly enable the minor mode before using
autoloaded commands.
2020-05-28 00:25:19 -04:00
N V
2e220f511e (fix): org-roam-db-build-cache filter non-file input (#709)
If a shell command is used to find files, it may include
output from another command.

see: #706, #688
2020-05-27 15:15:55 +08:00
1581d875ce (fix): doctor: add ROAM_KEY to supported props (#708) 2020-05-27 13:53:30 +08:00
50cc81c76d (internal): use emacsql-sqlite3 everywhere (#701) 2020-05-27 13:20:06 +08:00
f95cea7067 (feat): doctor: add check for misspelled roam properties (#703) 2020-05-26 14:52:51 +08:00
41a1970c6f (internal): add BACKERS.md (#702) 2020-05-26 14:41:09 +08:00
8818f50f41 (fix): fix symlinked directories and files not picked up (#700)
The implementations for org-roam--list-files-{find,rg} did not follow
symlinks, which cause them to not pick up symlinked files and
directories.
2020-05-26 13:46:08 +08:00
ea6bd215fc (fix): set default org-roam-list-files-commands for windows to nil (#698) 2020-05-25 13:26:46 +08:00
N V
a05b1ebcc3 (internal): refactor org-roam-find-file logic (#691)
Fail faster in case of nested capture.
Simplify logic for completions.
2020-05-23 17:42:47 -04:00
N V
214f9df844 (fix): org-roam--list-files strip ANSI color codes (#689)
Prevent shell commands from passing ANSI color codes through to callers.

see: #688
2020-05-22 23:51:52 -04:00
N V
4f5a82e291 (internal): org-roam.el formatting (#687)
Organize org-roam.el:
- Move functions so they are defined before they are referenced
- Move defcustoms to appropriate section, sort alphabetically
- Move interactive commands to appropriate section, autoload, sort.

Should not change any behavior, but make review easier.
2020-05-22 21:34:50 -04:00
4d0b5734c8 (fix): fix org-roam--list-files escape (#684) 2020-05-22 21:14:03 +08:00
4cd0fe4e41 (internal): add rg and find support for org-roam--list-files (#664)
Speeds up org-roam--list-files using external tools. Simple benchmarks:

(benchmark 1000 '(org-roam--list-files-rg "./jethrokuan/braindump"))
"Elapsed time: 9.012230s (0.399595s in 5 GCs)"

(benchmark 1000 '(org-roam--list-files-find "./jethrokuan/braindump"))
"Elapsed time: 5.543965s (0.318566s in 4 GCs)"

(benchmark 1000 '(org-roam--list-files-elisp "./jethrokuan/braindump"))
"Elapsed time: 55.781495s (3.220956s in 41 GCs)"

Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-05-22 14:25:29 +08:00
N V
1eefc264f5 (fix): org-roam-graph--build notify user when build starts (#683)
Displays a message to user to let them know the build (which may take
a variable amount of time) has started.
2020-05-21 22:19:27 -04:00
N V
525a58dd86 (fix): org-roam-graph--build in seperate process (#679)
org-roam-graph--build accepts a callback function which is passed the
resultant graph file as its sole argument. This prevents a race between
graph building and opening.

See: #666
2020-05-21 13:03:16 -04:00
4a9401dd40 (feat): org-roam-doctor: add ROAM_TAGS and ROAM_ALIAS checks (#680) 2020-05-21 21:08:52 +08:00
dd2406ec92 (fix): fix 'ref context not returning path to file (#678) 2020-05-21 13:14:06 +08:00
c4189ffa04 (internal): remove github stale bot (#676)
bad bot.
2020-05-20 13:42:37 +08:00
e3d101f495 (doc): Update org-roam-bibtex repo URL (#675) 2020-05-19 15:12:28 -04:00
2cced712fa (docs): add landing page (#673)
Fixes #623 
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-05-19 23:41:48 +08:00
cce2db8b5a (release): v1.1.1 (#668) 2020-05-18 22:04:51 +08:00
2147adf95c Create FUNDING.yml 2020-05-18 21:27:31 +08:00
d2654f6023 (docs): add a nice default theme (#667) 2020-05-18 19:15:12 +08:00
N V
78b518efd3 (fix): org-roam-capture--capture shadow org-capture-templates-contexts (#662)
Lexically bind org-capture-templates-contexts to nil before calling org-capture
with org-roam-capture-templates. Otherwise, contexts may shadow
org-roam-templates which have same keys as org-capture-templates.

mentioned in #651
2020-05-17 11:51:25 -04:00
N V
1b5e55b6c4 (fix): org-roam-capture allow creating new file (#661)
Set title correctly when no match found in prompt's candidates.
fixes #651
2020-05-17 11:36:15 -04:00
4b45f1dbf5 (fix): fix link updating on file-renames (#660)
Fixes #647: file: links are now updated to reflect the directory change.
Also fixes #554: rename-files to directories are also resolved correctly now.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-05-17 18:51:52 +08:00
N V
e0aee184a7 (fix): prevent org-roam-version from loading org-roam-dev (#659)
Instead of visiting file, insert library into temp buffer.
Prevents loading .dir-local dev environment, accompanying unsafe-variable prompt.
Prevents interference with org-roam.el if already open.
2020-05-17 03:41:40 -04:00
N V
eae97487dc (internal): fix free variable reference (#658)
Define org-roam-backlinks-mode before it is referenced.
2020-05-17 02:56:15 -04:00
N V
f5a9dfab9b (fix): Require seq.el (#657)
seq.el is is not guaranteed to be loaded otherwise.
2020-05-17 02:20:48 -04:00
N V
7844827757 (feature): org-roam-diagnostics command (#653)
Automates collection of user environment information.
2020-05-17 01:57:38 -04:00
N V
74f12ee8aa (internal): org-roam-version save-excursion (#656)
Restore user's point in org-roam.el
2020-05-17 01:46:41 -04:00
N V
055669817a (feature): org-roam-version command (#655)
Useful for diagnostic information.
Should be supplemented with finer grained info (commit hash would be
ideal) once we figure out a more sophisticated approach.
2020-05-17 13:33:53 +08:00
N V
1fc08b4428 (internal): inline minor-mode keymaps (#654)
define-minor-mode macro creates appropriate symbol/documentation for
inlined keymaps.
2020-05-17 01:24:21 -04:00
N V
cfe3b19a73 (doc): bug_report.md request more info (#652)
Request interactive commands for more build/version info.
Request Org mode version.
2020-05-16 23:24:29 -04:00
1bc1559743 (fix): fix regression in find-ref (#650)
Fixes #649.
2020-05-17 00:09:58 +02:00
265182a698 (fix): adapt find-ref to new format (#646) 2020-05-16 14:03:37 +02:00
4b4ebf76c7 (fix): fix parsing for ido (#645)
This reverts commit 47763f49fd, after #643
reverted completions from hash-table to alist.
2020-05-16 19:38:52 +08:00
3bc174a6f0 (fix): reimplement mtime sorting (#642) 2020-05-16 19:32:23 +08:00
8091f4598e (internal): revert completions from hash table to alist (#643)
Initially we thought that using hash-tables would shave some seconds
because searching for a key is O(1), but when we present completions, we
typically want them sorted, and hash-tables do not support sorted keys.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-05-16 18:17:37 +08:00
1267a43043 (fix): refactor get-ref-path-completions (#633)
* (fix): refactor get-ref-path-completions

* Remove leftover variable

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-05-16 08:40:41 +02:00
N V
8ff09b4b6d (docs): Mention steps to provide backtrace in bug_report.md (#641) 2020-05-15 22:54:37 -04:00
2499c7e220 (feat): add COMPLETIONS argument to insert and find-file (#637)
Needed for smoother interaction with ORB.  I’ve elected to keep FILTER-FN for
the moment, even though it’s a bit redundant, and the description in the
docstring is not correct with the addition of tags.
2020-05-16 01:29:18 +02:00
d816250614 (fix): move from alist to hash for find-ref (#640) 2020-05-16 01:23:36 +02:00
47763f49fd (fix): fix parsing of new hash-table for ido
* Use hash-table-keys to extract titles for ido

* Same change for helm
2020-05-16 01:01:35 +02:00
9961a22a8c (fix): replace if with when (#632) 2020-05-15 20:23:06 +08:00
f390593cfb (feat): Add a tagging system (#604)
Tags are used as meta-data for files: they facilitate interactions with notes where titles are insufficient. For example, tags allow for categorization of notes: differentiating between bibliographical and structure notes during interactive commands.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>
2020-05-15 16:10:11 +08:00
N V
59c18c0e8c (internal): org-roam-dev -> sentence-end-double-space nil (#629)
Required by CI.
2020-05-15 13:11:19 +08:00
3df3b6519c (doc): fix org-roam-buffer-no-delete-other-windows (#628)
It appears the option has changed name, but this was not yet reflected
in the documentation.
2020-05-14 22:52:27 +02:00
b47b76aa41 (refactor): refactor title extraction (#625)
Introduces '(org-roam-title-sources), which can be a list of lists. Each symbol corresponds to a function, that when called returns a list of titles. If the element is a list, use the first function in the list that returns a successful result.
2020-05-14 19:45:07 +08:00
abb36d11ef (docs): remove redundant word in docstring (#626) 2020-05-14 19:04:59 +08:00
e55a38530d (fix): fix org-roam-doctor broken-link checker (#624)
The checker originally returns reports of wrong format when there are no
errors
2020-05-14 13:51:35 +08:00
80bc19cbda (docs): update manual location (#622) 2020-05-13 20:19:31 +08:00
85b3e488b2 (ci): fix 2020-05-13 19:56:06 +08:00
5a9f765a49 (ci): move images to the correct location 2020-05-13 19:54:08 +08:00
1c7c5b3b9b (ci): add nojekyll to docs 2020-05-13 19:48:39 +08:00
4266a81b51 (ci): build the correct folder, clean builds 2020-05-13 19:43:36 +08:00
36940e1eef Revert "(ci): deploy docs to docs branch"
This reverts commit 176aac67e6.
2020-05-13 19:39:12 +08:00
176aac67e6 (ci): deploy docs to docs branch 2020-05-13 19:36:36 +08:00
376ff71616 (ci): run doc build commands directly (#621) 2020-05-13 19:35:48 +08:00
232921b9a1 (docs): track landing page (#620) 2020-05-13 19:26:37 +08:00
9e2998c580 (ci): remove old docs, add landing page (#619) 2020-05-13 19:24:17 +08:00
e44b84b791 (ci): make multi-page manual (#618) 2020-05-13 18:56:42 +08:00
5e63bf32ed (ci): makeinfo -> texinfo (#617) 2020-05-13 18:49:18 +08:00
e62bda799a (docs): use gh actions to deploy documentation (#616) 2020-05-13 18:45:32 +08:00
46975107a2 (internal): remove assignment in issue templates (#615) 2020-05-13 17:58:34 +08:00
N V
b388fd3db2 (refactor): org-roam-db--clear pull tables from schemata (#611)
Programatically pull tables from schemata, rather than manually
specifying each table.
2020-05-13 02:24:50 -04:00
N V
e0cefa7377 (refactor): org-roam-db--clear-file pull tables from schemata (#613)
Programatically pull tables from schemata, rather than manually
specifying.
2020-05-13 14:14:46 +08:00
N V
fca1777648 (internal): Summarize features (#608)
* (internal): Summarize features

Replace generic package description in features' first line summary.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-05-12 15:06:19 -04:00
N V
1722fae9af (internal): org-roam-dev use directory-local variable (#607)
Add .dir-locals.el to load org-roam-dev for all source files.
2020-05-12 13:46:12 -04:00
N V
3727f015cd (internal): add org-roam-dev.el (#606)
Help ensure source code consistency.
emacsql indentation for now, but can easily be expanded as needed.
2020-05-13 01:21:54 +08:00
a85205e7bc (fix): Respect org-roam-file-extensions during file creation (#602) 2020-05-12 19:08:00 +08:00
b4927abbd7 (fix): Enforce default for ‘org-roam-index-file’ (#599) 2020-05-12 16:12:14 +08:00
N V
ad5fca5440 "Refactor org-roam-message as a function" (#595)
* Refactor org-roam-message as a function

Add to commentary that org-roam-macs may contain other utility
functions (similar to org-macs).

* Fix typos

* Try again

* Fix typo

* fix syntax error

* fix syntax error

* Apply args correctly

* Refactor with funcall

* Revert "Refactor with funcall"

This reverts commit 0807252d64.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-05-10 23:17:55 +02:00
3efe315ff1 (internal): add org-roam-message (#593)
This macro simplifies message printing, so we can respect
`org-roam-verbose` in more places. Also silences more messages when
`org-roam-verbose` set to false.
2020-05-10 16:44:28 +08:00
d68d1f8ebb (feat): add org-roam-doctor (#570)
`org-roam-doctor` provides a diagnostic tool for checking an Org-roam
file for things that are broken. Currently implemented is a check for
broken links, and methods to fix them. The checker is designed to be
extensible.
2020-05-10 13:57:18 +08:00
c70f2d5f54 (fix): update repo root to group (#591) 2020-05-10 13:48:16 +08:00
d3206b797a (docs): link to discourse in README (#577)
Also, add information about Graphviz on the README.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-05-09 19:54:05 +08:00
dee540b62f (fix): do not store empty-string refs in db (#586)
* (fix): do not store empty-string refs in db

* Error when ROAM_KEY is empty

* Handle nil

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-05-09 13:47:56 +02:00
46fd2a9a68 (fix): allow group templates in capture-templates (#584)
Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>
2020-05-09 18:08:08 +08:00
c1bfa99ace (fix): make graph--build error on non-string (#580)
* (fix): make graph--build error on non-string

* Replace let* with let

* Fix wording
2020-05-07 20:38:17 +02:00
9bc80ff9f7 (fix): improve error message on missing executable (#579) 2020-05-08 01:44:28 +08:00
1912beebc3 (docs): mention where to modify org-roam templates (#575)
Addresses #573
2020-05-07 16:33:42 +08:00
f8f7e6009c (internal): add longer sleep time to tests (#574) 2020-05-07 15:41:58 +08:00
689f559080 (doc): Add a gif for ORB (#571) 2020-05-06 18:59:09 +08:00
3ca2d9f4ca (doc): Improve wording 'A Preview' (#568)
* (doc): Improve wording of the first paragraph

Can’t believe nobody told us that we used ‘screenshot’ instead of
‘screencast’. :(

* Fill to 72
2020-05-05 14:19:00 +08:00
cd0850f1c1 (feat): simplify format of INFO for find-ref and add FILTER (#567)
* (feat): simplify format of `INFO` for find-ref

The format of the `INFO` argument of `org-roam-find` has been simplified, thanks
to the split of `type` and `ref` in the db permitted by #547.

The non-interactive behaviour of `org-roam-find-ref` has also been isolated
into `org-roam--find-ref`.  Even if it makes us repeat ourselves a bit, it
avoids having to nil the interactive argument just to get the non-interactive
us, which I think is better syntax.

* (feat): implement get-ref-path-completions filtering
2020-05-04 22:31:28 +02:00
11e15594cc (feat): add custom face for invalid links (#564)
* (feat): add custom face for links without destinations

* Rename to ‘invalid’

* Update docstring

* Remove ‘typically’
2020-05-04 15:47:27 +02:00
f6e84caf72 (chore): inherit org-roam-link-current from org-link (#563)
A better default for org-roam-link-current is the original org-link
face, rather than org-block.
2020-05-04 20:58:12 +08:00
11d239d661 (feat): fix citation links not showing up in graph (#547)
This change adds a `type` column to the refs column, and strips the prefix before storing the key in the `refs` table.
2020-05-04 20:44:15 +08:00
7df50c14ec (internal): make lint errors fail CI, and disable spellcheck during linting (#561)
- make lint errors fail CI
- disable indentation linting
- disable package linting for org-roam-macs.el
- disable spellcheck for checkdoc
- fixes compilation errors
2020-05-04 15:17:39 +08:00
a723199d68 (feat): apply error face if file link is broken (#560) 2020-05-04 12:57:43 +08:00
N V
1bbfb0cdc9 (ehancement): Improve org-roam-graph (#559)
Allow showing/building the whole graph from any buffer.
Allow programatically specifying connected component path.
2020-05-03 18:03:02 -04:00
69d4f05a13 (feat): add prefix argument to force database rebuild (#553)
* (feat): add prefix argument to force database rebuild

* Update changelog
2020-05-03 18:40:32 +08:00
4cad2cf6e6 (internal): use Make and Org to build manual (#546) 2020-05-03 18:06:27 +08:00
e698ed7f53 Generate cite backlinks using all org ref cite types (#551)
This would fail on pathological cases where the key itself contains other prefixes e.g. if the key
is `cite:parencite:autocite:key`. Although this is unlikely...

To use org-ref-cite-types, we must ensure that org-ref is loaded. This would likely already be done
otherwise as the user is obviously using cite links.
2020-05-02 18:50:11 +08:00
0132546e56 Create stale.yml 2020-05-01 20:16:57 +08:00
a8e2544435 graph: add an option of wrapping the title (#542)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-05-01 19:49:46 +08:00
1ad3539c54 (fix): ensure that multicite links are correctly split (#545)
* Ensure that multicite links are correctly split

org-ref multi-citations are handled by "cite:key1,key2". In the org-roam databases this was
previously stored as a single "cite" link to the (non-existing) key "key1,key2". This means that
cite backlinks and cite graph behaviour does not work correctly for these links.

This fix will split any cite links with a comma into separate links to each individual ref

* Refactor with ->>

* Refactor to use org-ref-split-and-strip-string instead

* Update changelog with #545

* (fix): optimize processing

* (fix): avoid repetition

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
2020-05-01 11:57:28 +02:00
5b773b687b (doc): add key-binding for index in default configs (#543)
* (doc): add key-binding for index in default configs

* (fix): rename org-roam-find-index to -jump-to-index
2020-05-01 09:07:37 +02:00
08aa5c630d (feat): reintroduce org-roam-link-current face (#516) 2020-04-30 20:20:33 +08:00
e05ee1240d (feat) cond display relative subdir in title for selection (#427)
* (feat) cond display relative subdir in title for selection

A title can now be constructed as ‘subdir/file-title’ where ‘subdir’ is the
sub-directory relative from ‘org-roam-directory’.

When ‘org-roam-title-include-subdirs’ is non-nil, ‘org-roam--extract-titles’
now outputs titles in this format.

* (fix) improve docstrings

* (feat) add var for modifying subdir-separator

* (fix) nitpick docstring

* (doc) document subdir creation in templates with :file-name

* (feat) make subdir-format accept a function

* (fix) respect docstring one-line-description

* (fix) address checkdoc errors

* (fix) also add subdirs when db--update-titles

* (feat) improve modularisation

`org-roam--extract-titles' is now reverted to its default definition, i.e. it
doesn’t format the titles.  In its stead,
`org-roam--extract-and-format-titles' is created to both extract the titles
and process all of them with `org-roam--format-title', which is a much better
way to do this.

* Refactor with ->>

* Refactor with let*

Pretty sure I got confused because I thought I needed to use the result of the
db-queryr.

* Remove useless ->>
2020-04-30 13:13:19 +02:00
65d99e998c (feat): prettier graph defaults (#541)
Use settings provided by @tecosaur. Closes #539.
2020-04-30 13:56:54 +08:00
ea3f5d00a0 (feat) expand rel-links upon extraction (#520) 2020-04-30 13:44:45 +08:00
7680663205 (feat): optionally use headline as title (#538)
Optionally pulls title from the first headline in Org file. Closes #506.
2020-04-29 12:42:55 +08:00
d0819aeffb (feat) implement org-roam-find-index (#513) 2020-04-29 12:08:42 +08:00
bd4b9d41e8 (bugfix): quote graphviz configuration options (#537)
Always quote graphviz configuration options. This allows passing
configurations with spaces. Fixes #535.
2020-04-29 11:30:39 +08:00
4142300501 (internal): refactor org-roam--pluralize (#525) 2020-04-26 19:07:19 +08:00
487025aa2f (chore): remove org-roam-completion-fuzzy-match (#523)
Remove the fuzzy matching variable introduced in #289. The rationale is
addressed in
https://github.com/jethrokuan/org-roam/issues/514#issuecomment-619438401:
Helm, Ido and Ivy have their own mechanisms for fuzzy search, and can be
tweaked using their own configuration options outside of org-roam, e.g.
through `ivy-re-builders-alist`.
2020-04-26 18:32:27 +08:00
bd3c97bb30 (feat) conditionally pluralize heading in org-roam-buffer (#521) 2020-04-26 17:51:32 +08:00
265a3054be (fix): resolve symlinks during cache build (#524)
Fixes #518.
2020-04-26 17:42:57 +08:00
8bb2465e61 (docs): update reference to Roam Protocol documentation (#519)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-26 17:29:21 +08:00
c3a5544da9 (docs): add docs for qutebrowser keybindings (#512) 2020-04-26 17:23:11 +08:00
963692f353 (bugfix): Fix invalid usage of error handler (#511)
The error handler was never invoked when executing `org-roam-graph-viewer` failed
2020-04-25 18:53:09 +08:00
d01f7b2daf (bugfix): fix inserting backup files into database (#509)
In #470, the `and` clause was removed, so `org-roam--org-roam-file-p`
returns `t` on `foo.org~` backup files. This PR adds that back in.

In addition, the `after-save-hook` function was not checking for whether
the file was within the org-roam system, which meant files from outside
`org-roam` would also be added into the database. This PR adds a guard
clause.
2020-04-22 14:35:47 +08:00
8a99febd0b (fix): lowercase username in url to org-roam-bibtex (#505) 2020-04-22 14:28:30 +08:00
b5786edb30 (docs): Fix org-roam-protocol JS Bookmarklet (#508) 2020-04-22 13:57:12 +08:00
dce8c47d6e (docs): mention org-roam-bibtex (#503) 2020-04-21 20:55:12 +08:00
86 changed files with 12445 additions and 4717 deletions

16
.dir-locals.el Normal file
View File

@ -0,0 +1,16 @@
((emacs-lisp-mode
(fill-column . 110)
(indent-tabs-mode . nil)
(elisp-lint-ignored-validators . ("byte-compile" "package-lint"))
(elisp-lint-indent-specs . ((describe . 1)
(it . 1)
(thread-first . 0)
(cl-flet . 1)
(cl-flet* . 1)
(org-element-map . defun)
(org-roam-dolist-with-progress . 2)
(org-roam-with-temp-buffer . 1)
(org-with-point-at . 1)
(magit-insert-section . defun)
(magit-section-case . 0)
(org-roam-with-file . 2)))))

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [jethrokuan]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -1,14 +1,15 @@
---
name: Bug Report
about: Something's not working.
title: ''
labels: ''
assignees: 'jethrokuan'
title: ""
labels: ""
assignees: ""
---
### Description
#### Steps to Reproduce
<!--
Example:
@ -18,13 +19,23 @@ Example:
...
-->
#### Backtrace
<!--
Will help us track and understand issues faster.
How to provide a backtrace:
1. M-x toggle-debug-on-error
2. Trigger error. The debugger buffer should pop up.
3. Copy the contents of the debugger buffer and paste here
-->
#### Expected Results
<!-- Example: File A is there -->
#### Actual Results
<!-- Example: File A is missing -->
### Versions
- Emacs (`C-h v emacs-version`): vX.X.X
- Org-roam commit: https://github.com/jethrokuan/org-roam/commit/commithashhere
### Environment
<!-- Please M-x org-roam-diagnostics and paste results here -->

View File

@ -1,9 +1,9 @@
---
name: Feature Request
about: Create a feature request to improve Org-roam
title: ''
labels: 'enhancement'
assignees: 'jethrokuan'
title: ""
labels: "enhancement"
assignees: ""
---
### Brief Abstract
@ -13,4 +13,5 @@ assignees: 'jethrokuan'
### Proposed Implementation (if any)
### Please check the following:
- [ ] No similar feature requests

31
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,31 @@
# * docs.yml --- Build the documentation and publish to Github Pages
name: "Docs"
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: true
steps:
- uses: actions/checkout@v2
- name: Install deps
run: |
sudo apt-get install texinfo
- name: Build docs
continue-on-error: false
run: make html
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3
with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: doc # The folder the action should deploy.
CLEAN: true

View File

@ -28,41 +28,38 @@ on:
pull_request:
push:
branches:
- master
- develop
- main
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
emacs_version:
# 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
steps:
- uses: purcell/setup-emacs@master
with:
version: ${{ matrix.emacs_version }}
- uses: purcell/setup-emacs@master
with:
version: ${{ matrix.emacs_version }}
- uses: actions/checkout@v2
- uses: actions/checkout@v2
- name: Initialize sandbox
run: |
SANDBOX_DIR=$(mktemp -d) || exit 1
echo ::set-env name=SANDBOX_DIR::$SANDBOX_DIR
./makem.sh -vv --sandbox $SANDBOX_DIR --install-deps --install-linters
- name: Install Eldev
run: curl -fsSL https://raw.github.com/org-roam/org-roam/master/github-eldev | sh
# The "all" rule is not used, because it treats compilation warnings
# as failures, so linting and testing are run as separate steps.
- name: Install dependencies
run: make prepare
- name: Lint
continue-on-error: true
run: ./makem.sh -vv --sandbox $SANDBOX_DIR lint
- name: Test
if: always() # Run test even if linting fails.
run: ./makem.sh -vv --sandbox $SANDBOX_DIR test
- name: Lint
run: make lint
- name: Test
run: make test
# Local Variables:
# eval: (outline-minor-mode)
# End:

14
.gitignore vendored
View File

@ -1,2 +1,16 @@
/.sandbox/
**/*.elc
/doc/dir
/doc/*.info
/doc/*.pdf
/doc/*.epub
/doc/META_INF/
/doc/OEBPS/
/doc/dir
/doc/epub.xml
/doc/org-roam/
/doc/mimetype
/doc/stats/
/config.mk
/doc/manual.html
/.eldev/

View File

@ -1,8 +0,0 @@
version: 2
mkdocs:
configuration: mkdocs.yml
formats: all
python:
version: 3.7
install:
- requirements: doc/requirements.txt

8
BACKERS.md Normal file
View File

@ -0,0 +1,8 @@
# Backers
Many thanks to the following backers, your contributions are greatly appreciated!
- Nathan Tran
- Burke Libbey
- forkrul
- Andreas Stuhlmüller

View File

@ -1,6 +1,404 @@
# Changelog
## 1.1.0 (21-04-2020)
## 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
### Added
- [#2138](https://github.com/org-roam/org-roam/pull/2138) export: add new module
- [#2170](https://github.com/org-roam/org-roam/pull/2170) log: add new module for working with org logs
- [#2158](https://github.com/org-roam/org-roam/pull/2158) db: support emacsql-sqlite-builtin and emacsql-sqlite-module
- [#2160](https://github.com/org-roam/org-roam/pull/2160) core: support a list of `org-roam-file-exclude-regexp`
### Removed
### Fixed
- [#2091](https://github.com/org-roam/org-roam/pull/2091) node: fix org-roam-promote-entire-buffer structural errors
- [#2130](https://github.com/org-roam/org-roam/pull/2130) buffer: unlinked-references section now also searches within symlinked directories
- [#2152](https://github.com/org-roam/org-roam/pull/2152) org-roam-preview-default-function: doesn't copy copy content of next heading node when current node's content is empty
- [#2159](https://github.com/org-roam/org-roam/pull/2159) db: fix db syncs on narrowed buffers
- [#2156](https://github.com/org-roam/org-roam/pull/2157) capture: templates with functions are handled correctly to avoid signaling `char-or-string-p`
### Changed
- [#2160](https://github.com/org-roam/org-roam/pull/2160) core: ignore files in `org-attach-id-dir` by default
## 2.2.1 (2022-03-15)
### Breaking
- [#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:
```emacs-lisp
(setq org-roam-node-display-template
(concat "${title:*} "
(propertize "${tags:10}" 'face 'org-tag)))
```
### Added
- [#2042](https://github.com/org-roam/org-roam/pull/2042) db: add `org-roam-db-extra-links-elements` and `org-roam-db-extra-links-exclude-keys` for fine-grained control over additional link parsing
- [#2049](https://github.com/org-roam/org-roam/pull/2049) capture: allow ID to be used as part of `org-roam-capture-templates`
- [#2050](https://github.com/org-roam/org-roam/pull/2050) core: add `FILTER-FN` to `org-roam-node-random`
- [#2065](https://github.com/org-roam/org-roam/pull/2065) dailies: add `keys` argument to the remaining dailies functions `org-roam-dailies-goto-yesterday`/`-today`/`-tomorrow`/`-date` and `org-roam-dailies-capture-yesterday`/`-tomorrow`/`-date` to give the abilty to get into a capture buffer bypassing the selection screen in all dailies commands. Extension of #2055
- [#2079](https://github.com/org-roam/org-roam/pull/2079) capture: ensure that `:ref` info captured in all cases.
- [#2121](https://github.com/org-roam/org-roam/pull/2121) buffer: add unique option to `org-roam-backlinks-section`
### Removed
### Fixed
- [#2086](https://github.com/org-roam/org-roam/pull/2086) capture: correctly update org-id-locations on capture
- [#2082](https://github.com/org-roam/org-roam/pull/2082) buffer: don't destroy window if `org-roam-node-toggle` reuses window
- [#2080](https://github.com/org-roam/org-roam/pull/2080) dailies: prevent multiple "dailies/" subdir expansions
- [#2055](https://github.com/org-roam/org-roam/pull/2055) dailies: removed stray f require, which was causing require and compilation errors
- [#2117](https://github.com/org-roam/org-roam/pull/2117) capture: preserve trailing whitespace content in capture templates
### Changed
- [#2060](https://github.com/org-roam/org-roam/pull/2060) node: added double acute accent normalization for Unicode characters in titles
- [#2040](https://github.com/org-roam/org-roam/pull/2040) completions: fix completions display-width for Helm users
- [#2025](https://github.com/org-roam/org-roam/pull/2025) chore: removed the dependencies on f.el and s.el
- [#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
## 2.2.0 (2022-01-14)
### 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
- [#1963](https://github.com/org-roam/org-roam/pull/1963) db: cache file title into files table
- [#1977](https://github.com/org-roam/org-roam/pull/1977) db: support Org-ref v3 citations
- [#1907](https://github.com/org-roam/org-roam/pull/1907), [#2009](https://github.com/org-roam/org-roam/pull/2009), [#2018](https://github.com/org-roam/org-roam/pull/2018) db: support sqlite3
- [#2028](https://github.com/org-roam/org-roam/pull/2028) dailies: add `keys` argument to `org-roam-dailies-capture-today` and `org-roam-dailies--capture` functions to give the abilty to get into a capture buffer bypassing the selection screen
### Removed
### Changed
- [#1795](https://github.com/org-roam/org-roam/pull/1795) buffer: optimized reflinks fetch
- [#1809](https://github.com/org-roam/org-roam/pull/1809) capture: the mandatory `:if-new` property of each capture template is now renamed to `:target`
- [#1829](https://github.com/org-roam/org-roam/pull/1829) perf: file sql updates are now wrapped in a transaction
- [#1877](https://github.com/org-roam/org-roam/pull/1877) dailies: stop asking for time, only date
- [#1949](https://github.com/org-roam/org-roam/pull/1949) db: check for property drawers are now case-insensitive
### Fixed
- [#1798](https://github.com/org-roam/org-roam/pull/1798) org-roam-node-at-point: do not skip invisible headings
- [#1807](https://github.com/org-roam/org-roam/pull/1807) capture: always trigger `:if-new` template for existing nodes
- [#1813](https://github.com/org-roam/org-roam/pull/1813) db: prevent empty ROAM_ALIASES from crashing db updates
- [#1816](https://github.com/org-roam/org-roam/pull/1816) db: prevent invalid ROAM_REFS from crashing db updates
- [#1893](https://github.com/org-roam/org-roam/pull/1893), [#1896](https://github.com/org-roam/org-roam/pull/1896), [#1901](https://github.com/org-roam/org-roam/pull/1901), [#1895](https://github.com/org-roam/org-roam/pull/1895), [#1904](https://github.com/org-roam/org-roam/pull/1904) completions: various mini-buffer related completion fixes
- [#1931](https://github.com/org-roam/org-roam/pull/1931) utils: org-roam-set-keyword now skips over all drawers
- [#1947](https://github.com/org-roam/org-roam/pull/1947) db: links in ROAM_REFS are no longer considered as links
- [#1948](https://github.com/org-roam/org-roam/pull/1948) completions: fix same-line completions
- [#1953](https://github.com/org-roam/org-roam/pull/1953) db: refresh CATEGORY before writing to db
- [#1946](https://github.com/org-roam/org-roam/pull/1946), [#1946](https://github.com/org-roam/org-roam/pull/1946), [#1958](https://github.com/org-roam/org-roam/pull/1958) various performance improvements
- [#1980](https://github.com/org-roam/org-roam/pull/1980) utils: fix org-roam-with-file changing the minor-mode
- [#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
## 2.1.0 (2021-08-20)
### 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`
- [#1709](https://github.com/org-roam/org-roam/pull/1709) added ability to specify default value in org-roam capture templates
- [#1710](https://github.com/org-roam/org-roam/pull/1710) added `org-roam-extract-subtree`
- [#1720](https://github.com/org-roam/org-roam/pull/1720) added `org-roam-db-update-on-save`
- [#1758](https://github.com/org-roam/org-roam/pull/1758) added `org-roam-db-autosync-mode`, replacing `org-roam-setup` and `org-roam-teardown`
### Removed
- [#1716](https://github.com/org-roam/org-roam/pull/1716) helper function `org-roam-get-keyword` is now obsolete: prefer `org-collect-keywords`
### Changed
- [#1595](https://github.com/org-roam/org-roam/pull/1595), [#1724](https://github.com/org-roam/org-roam/pull/1724) Major refactoring and restructuring of the codebase
- [#1655](https://github.com/org-roam/org-roam/pull/1655) improved org-roam contents preview
- [#1741](https://github.com/org-roam/org-roam/pull/1741) expose `org-roam-capture-` keys in interactive commands
- [#1786](https://github.com/org-roam/org-roam/pull/1786) org-roam-version now outputs commit hash if found
- [#1788](https://github.com/org-roam/org-roam/pull/1788) the point is not moved if the node is already visited
### Fixed
- [#1608](https://github.com/org-roam/org-roam/pull/1608) migration: empty ROAM_REFS are now removed
- [#1609](https://github.com/org-roam/org-roam/pull/1609) migration: fixed file-link replacement
- [#1653](https://github.com/org-roam/org-roam/pull/1653) migration: fixed tags migration
- [#1694](https://github.com/org-roam/org-roam/pull/1694) core: nodes with no title are now skipped
- [#1637](https://github.com/org-roam/org-roam/pull/1637) core: fix org-ref multi-cite links not being split
- [#1651](https://github.com/org-roam/org-roam/pull/1651) core: fix org-roam-file-p crashing when there is no corresponding file
- [#1705](https://github.com/org-roam/org-roam/pull/1705) core: fix for add/remove of file-level tags
- [#1769](https://github.com/org-roam/org-roam/pull/1769) core: gracefully handle absence of `org-id-locations-file`
- [#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
## 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
- [#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`.
- [#1353](https://github.com/org-roam/org-roam/pull/1353) support file-level property drawers
### Changed
- [#1352](https://github.com/org-roam/org-roam/pull/1352) prefer lower-case for roam_tag and roam_alias in interactive commands
- [#1513](https://github.com/org-roam/org-roam/pull/1513) replaced hardcoded "svg" with defcustom org-roam-graph-filetype
- [#1540](https://github.com/org-roam/org-roam/pull/1540) allow `roam_tag` and `roam_alias` to be specified on multiple lines
### Fixed
- [#1281](https://github.com/org-roam/org-roam/pull/1281) fixed idle-timer not instantiated on `org-roam-mode`
- [#1308](https://github.com/org-roam/org-roam/pull/1308) fixed file renames corrupting database
- [#1325](https://github.com/org-roam/org-roam/pull/1325) make titles and tags extracted unique per note
- [#1327](https://github.com/org-roam/org-roam/pull/1327) preserve existing link description during automatic replacement
- [#1346](https://github.com/org-roam/org-roam/pull/1346) prevent malformed path to `org-roam-index-file`
- [#1347](https://github.com/org-roam/org-roam/pull/1347) allow use of `%a` element in regular Org-roam captures
- [#1352](https://github.com/org-roam/org-roam/pull/1352) fixed org-roam-{tag/alias}-{add/delete} altering the original case of the Org property
- [#1374](https://github.com/org-roam/org-roam/pull/1374) fix headline completions erroring out
- [#1375](https://github.com/org-roam/org-roam/pull/1375) fix org-roam-protocol to use existing ref file
- [#1403](https://github.com/org-roam/org-roam/issues/1403) fixed inconsistency between how we write and read props like alias and tags
- [#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
## 1.2.3 (2020-11-13)
Primarily a stabilization and bug-fix release.
Org-roam-dailies has also been revamped to include new features, see [this video](https://www.youtube.com/watch?v=1q9x2aZCJJ4) for a quick overview.
### Added
- [#978](https://github.com/org-roam/org-roam/pull/978) Revamp org-roam-dailies
- [#1183](https://github.com/org-roam/org-roam/pull/1183) Interactive functions for managing aliases and tags in Org-roam file, namely `org-roam-alias-add`, `org-roam-alias-delete`, `org-roam-tag-add`, and `org-roam-tag-delete`.
- [#1215](https://github.com/org-roam/org-roam/pull/1215) Multiple `ROAM_KEY` keywords can now be specified in one file. This allows bibliographical entries to share the same note file.
- [#1238](https://github.com/org-roam/org-roam/pull/1238) Add `org-roam-prefer-id-links` variable to select linking method
- [#1239](https://github.com/org-roam/org-roam/pull/1239) Allow `org-roam-protocol` to capture the webpage's selection, and add a toggle for storing the links to the pages
- [#1264](https://github.com/org-roam/org-roam/pull/1264) add `org-roam-db-update-method` to control when the cache is rebuilt.
### Changed
- [#1264](https://github.com/org-roam/org-roam/pull/1264) renamed `org-roam-update-db-idle-seconds` to `org-roam-db-idle-idle-seconds`
### Fixed
- [#1074](https://github.com/org-roam/org-roam/issues/1074) fix `org-roam--extract-links` to handle content boundaries.
- [#1193](https://github.com/org-roam/org-roam/issues/1193) fix `org-roam-db-build-cache` by not killing temporary buffer in `org-roam--extract-links`.
- [#1195](https://github.com/org-roam/org-roam/issues/1195) fix ID face showing as invalid if within Org ID files, but not Org-roam's.
- [#1199](https://github.com/org-roam/org-roam/issues/1199) make Org-roam link insertions respect `org-roam-link-title-format` everywhere.
- [#1201](https://github.com/org-roam/org-roam/issues/1201) fix `org-roam-db-build-cache` failing in scenarios involving duplicate IDs and deleted files.
- [#1226](https://github.com/org-roam/org-roam/issues/1226) only update relative path of file links
- [#1232](https://github.com/org-roam/org-roam/issues/1232) fix incorrect title extractions from narrowed buffers
- [#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
## 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`.
Org-roam now does not resolve symlinks. This significantly speeds up cache builds, but may result in some workflows breaking. In particular, Org-roam now cannot figure out if two distinct file paths in the Org-roam directory are the same file, and both files will be processed as if they were different files. This error seems to be unavoidable now that symlinks are not resolved, but this workflow is rare and should not affect most users.
This change requires you to set `org-roam-directory` to the resolved path of a folder. That is:
```elisp
(setq org-roam-directory (file-truename "/path/to/directory/"))
```
### Breaking Changes
- [#1164](https://github.com/org-roam/org-roam/pull/1164) Org-roam now stores the database in the user's Emacs directory by default
- [#910](https://github.com/org-roam/org-roam/pull/910) Deprecate `company-org-roam`, using `completion-at-point` instead. To use this with company, add the `company-capf` backend instead.
- [#1109](https://github.com/org-roam/org-roam/pull/1109) Org-roam now does not resolve symlinks.
### Features
- [#1163](https://github.com/org-roam/org-roam/pull/1163) Support file-level IDs introduced in Org 9.4
- [#1093](https://github.com/org-roam/org-roam/pull/1093) Add `vanilla` org-roam-tag-source to extract buffer Org tags
- [#1079](https://github.com/org-roam/org-roam/pull/1079) Add `org-roam-tag-face` to customize appearance of tags in interactive commands
- [#1073](https://github.com/org-roam/org-roam/pull/1073) Rename file on title change, when `org-roam-rename-file-on-title-change` is non-nil.
- [#1071](https://github.com/org-roam/org-roam/pull/1071) Update link descriptions on title changes, and clean-up rename file advice
- [#1061](https://github.com/org-roam/org-roam/pull/1061) Speed up the extraction of file properties, headlines, and titles
- [#1046](https://github.com/org-roam/org-roam/pull/1046) New user option to exclude files from Org-roam
- [#1032](https://github.com/org-roam/org-roam/pull/1032) File changes are now propagated to the database on idle timer. This prevents large wait times during file saves.
- [#974](https://github.com/org-roam/org-roam/pull/974) Protect region targeted by `org-roam-insert`
- [#994](https://github.com/org-roam/org-roam/pull/994) Simplify org-roam-store-link
- [#1062](https://github.com/org-roam/org-roam/pull/1062) Variable `org-roam-completions-everywhere` allows for completions everywhere from word at point
- [#910](https://github.com/org-roam/org-roam/pull/910), [#1105](https://github.com/org-roam/org-roam/pull/1105) Support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`
### Bugfixes
- [#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
## 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.
We also added some new features that had been a long time coming:
1. We made the backlinks more outline-friendly by also showing the outline hierarchy for a backlink (#863)
2. We now support nested captures, which is crucial for `org-roam-protocol` (#966)
### Breaking Changes
- [#908](https://github.com/org-roam/org-roam/pull/908) Normalized titles in database. May break external packages that rely on unnormalized titles.
### Features
- [#814](https://github.com/org-roam/org-roam/pull/814) Implement `org-roam-insert-immediate`
- [#833](https://github.com/org-roam/org-roam/pull/833) Add customization of file titles with `org-roam-title-to-slug-function`.
- [#839](https://github.com/org-roam/org-roam/pull/839) Return selected file from `org-roam-insert`
- [#847](https://github.com/org-roam/org-roam/pull/847) Add GC threshold `org-roam-db-gc-threshold` to temporarily change the threshold on expensive operations.
- [#847](https://github.com/org-roam/org-roam/pull/847) Use sqlite3 transactions instead of storing the values to be inserted.
- [#851](https://github.com/org-roam/org-roam/pull/851) Add `'first-directory'` option for `org-roam-tag-sources`
- [#863](https://github.com/org-roam/org-roam/pull/863) Display outline hierarchy in backlinks buffer
- [#898](https://github.com/org-roam/org-roam/pull/898) Add `org-roam-random-note` to browse a random note.
- [#900](https://github.com/org-roam/org-roam/pull/900) Support and index all valid org links
- [#966](https://github.com/org-roam/org-roam/pull/966) Enable nested captures
### Bugfixes
- [#854](https://github.com/org-roam/org-roam/pull/854) Warn instead of fail when duplicate refs and IDs exist.
- [#857](https://github.com/org-roam/org-roam/pull/857) Fix tag extraction for symlinked directories.
- [#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
## 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.
This is a major step forward. Supporting the in-file structure of Org-mode files means that we can interface with many of its core-features like TODOs, properties, priorities, etc. UX will have to be figured out, but this release ushers in a new age in terms of functionalities.
We also add `org-roam-unlinked-references`, which naively finds text that could be references to the current Org-roam file.
### Breaking Changes
- [#701](https://github.com/org-roam/org-roam/pull/701) Use `emacsql-sqlite3` instead of `emacsql-sqlite` for better Windows compatibility. This requires the presence of the standard `sqlite3` binary on your machine.
- [#750](https://github.com/org-roam/org-roam/pull/750) Deprecate `org-roam-buffer-no-delete-other-windows` in favour of `org-roam-buffer-window-parameters`.
### Features
- [#787](https://github.com/org-roam/org-roam/pull/787) Add `org-roam-unlinked-references`
- [#783](https://github.com/org-roam/org-roam/pull/783) Add support for headlines
- [#757](https://github.com/org-roam/org-roam/pull/757) Roam global properties are now case-insensitive
- [#680](https://github.com/org-roam/org-roam/pull/680) , [#703](https://github.com/org-roam/org-roam/pull/703), [#708](https://github.com/org-roam/org-roam/pull/708) Add `org-roam-doctor` checkers for `ROAM_*` properties
- [#664](https://github.com/org-roam/org-roam/pull/664) Add support for shelling out to `rg` and `find` in `org-roam--list-files`
- [#679](https://github.com/org-roam/org-roam/pull/679), [#683](https://github.com/org-roam/org-roam/pull/683) Building of the graph now happens in a separate process
### Bugfixes
- [#714](https://github.com/org-roam/org-roam/pull/714) No longer print citelinks in backlinks buffer if there is no `ROAM_KEY` property or `org-ref` is not installed
- [#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
## 1.1.1 (2020-05-18)
In this release, we added two new features:
1. `org-roam-doctor`: a linting system that helps you discover possible problems with your Org-roam files. This is in the spirit of keeping notes in top quality.
2. A tagging system: one can now use sub-directories, and the `#+roam_tags` key add additional meta data to notes. For more information, see [here](https://www.orgroam.com/manual/Tags.html#Tags).
As usual, this release comes with a multitude of bug-fixes and refactorings.
### Breaking Changes
- [#523](https://github.com/org-roam/org-roam/pull/523) remove `org-roam-completion-fuzzy-match` in favor of using completion mechanism's configuration options directly
- [#547](https://github.com/org-roam/org-roam/pull/547) Deprecate `org-roam-db--maybe-update`, in favour of `org-roam-db--update-maybe`
- [#604](https://github.com/org-roam/org-roam/pull/604) Deprecate `org-roam-title-include-subdirs`, `org-roam-title-subdir-format` `org-roam-title-subdir-separator`, for a more general tagging system built on subdirectories
### Bugfixes
- [#509](https://github.com/org-roam/org-roam/pull/509) fix backup files being tracked in database
- [#509](https://github.com/org-roam/org-roam/pull/509) fix external org files being tracked in database
- [#537](https://github.com/org-roam/org-roam/pull/537) quote graphviz node and edge configuration options to allow multi-word configurations
- [#545](https://github.com/org-roam/org-roam/pull/545) fix `org-roam--extract-links` to ensure that multiple citations (`cite:key1,key2`) are split correctly
- [#547](https://github.com/org-roam/org-roam/pull/547) Fix unlinked citations
- [#660](https://github.com/org-roam/org-roam/pull/660) fix rename-file advice not working for renaming to directories
- [#660](https://github.com/org-roam/org-roam/pull/660) fix links breaking within file on file movement
### Features
- [#538](https://github.com/org-roam/org-roam/pull/538) Optionally use text in first headline as title
- [#553](https://github.com/org-roam/org-roam/pull/553) Add prefix argument to `org-roam-db-build-cache` for forcing rebuilds
- [#560](https://github.com/org-roam/org-roam/pull/560) Apply 'error face to distinguish broken links
- [#570](https://github.com/org-roam/org-roam/pull/570) Add `org-roam-doctor` to diagnose org-roam files
- [#625](https://github.com/org-roam/org-roam/pull/625) Add `org-roam-title-sources` to control how titles are retrieved within notes
- [#604](https://github.com/org-roam/org-roam/pull/604) Add a tagging system. `org-roam-tag-sources` controls how tags are retrieved from notes
### Internal Changes
- [#547](https://github.com/org-roam/org-roam/pull/547) Added `type` column to the `refs` table
- [#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
## 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:
@ -8,50 +406,56 @@ To the average user, this release is mainly a bugfix release with additional opt
2. [@kljohann](https://github.com/kljohann) did some fantastic work on graph generation: allowing building images for connected components within the graph up to a specified distance
3. We also started supporting `org-ref` natively: cite links now show up in both the graph and the org-roam buffer.
In the coming months, you can expect work on bigger projects (e.g. revamping the org-roam buffer).
In the coming months, you can expect work on bigger projects (e.g. revamping the org-roam buffer).
### Breaking Changes
* [#385](https://github.com/jethrokuan/org-roam/pull/385) Deprecate `org-roam-graph-node-shape` in favour of `org-roam-graph-node-extra-config`.
* [#473](https://github.com/jethrokuan/org-roam/pull/473) Deprecate `org-roam-date-filename-format` and `org-roam-date-title-format`, in favour of `org-roam-dailies-capture-templates`.
- [#385](https://github.com/org-roam/org-roam/pull/385) Deprecate `org-roam-graph-node-shape` in favour of `org-roam-graph-node-extra-config`.
- [#473](https://github.com/org-roam/org-roam/pull/473) Deprecate `org-roam-date-filename-format` and `org-roam-date-title-format`, in favour of `org-roam-dailies-capture-templates`.
### New Features
* [#350](https://github.com/jethrokuan/org-roam/pull/350) Add `org-roam-db-location` to customize location of org-roam database.
* [#359](https://github.com/jethrokuan/org-roam/pull/359) Add `org-roam-verbose` to allow or silence printing of information.
* [#374](https://github.com/jethrokuan/org-roam/pull/374) Add support for `org-ref` `cite:` links
* [#380](https://github.com/jethrokuan/org-roam/pull/380) Allow `org-roam-buffer-position` to also be `top` or `bottom`
* [#385](https://github.com/jethrokuan/org-roam/pull/385) Add `org-roam-graph-node-extra-config` to configure Graphviz nodes
* [#398](https://github.com/jethrokuan/org-roam/pull/398), [#418](https://github.com/jethrokuan/org-roam/pull/418) Add graph building for connected components
* [#435](https://github.com/jethrokuan/org-roam/pull/435) Add `org-roam-graph-edge-extra-config` to configure Graphviz edges
* [#439](https://github.com/jethrokuan/org-roam/pull/439) Add support for `org-ref` citations to display as edges in graph. Add `org-roam-graph-edge-cites-extra-config` to configure these edges
* [#465](https://github.com/jethrokuan/org-roam/pull/465) Add `org-roam-file-extensions` to allow detection of org files with different file extensions
* [#488](https://github.com/jethrokuan/org-roam/pull/488) Allow a function for `org-roam-graph-viewer`
* [#491](https://github.com/jethrokuan/org-roam/pull/491) Use TITLE as description when linking before first heading
- [#350](https://github.com/org-roam/org-roam/pull/350) Add `org-roam-db-location` to customize location of org-roam database.
- [#359](https://github.com/org-roam/org-roam/pull/359) Add `org-roam-verbose` to allow or silence printing of information.
- [#374](https://github.com/org-roam/org-roam/pull/374) Add support for `org-ref` `cite:` links
- [#380](https://github.com/org-roam/org-roam/pull/380) Allow `org-roam-buffer-position` to also be `top` or `bottom`
- [#385](https://github.com/org-roam/org-roam/pull/385) Add `org-roam-graph-node-extra-config` to configure Graphviz nodes
- [#398](https://github.com/org-roam/org-roam/pull/398), [#418](https://github.com/org-roam/org-roam/pull/418) Add graph building for connected components
- [#435](https://github.com/org-roam/org-roam/pull/435) Add `org-roam-graph-edge-extra-config` to configure Graphviz edges
- [#439](https://github.com/org-roam/org-roam/pull/439) Add support for `org-ref` citations to display as edges in graph. Add `org-roam-graph-edge-cites-extra-config` to configure these edges
- [#465](https://github.com/org-roam/org-roam/pull/465) Add `org-roam-file-extensions` to allow detection of org files with different file extensions
- [#488](https://github.com/org-roam/org-roam/pull/488) Allow a function for `org-roam-graph-viewer`
- [#491](https://github.com/org-roam/org-roam/pull/491) Use TITLE as description when linking before first heading
### Bugfixes
* [#470](https://github.com/jethrokuan/org-roam/pull/470) Add workaround for undocumented `file-truename` behaviour in `org-roam--org-roam-file-p`.
- [#470](https://github.com/org-roam/org-roam/pull/470) Add workaround for undocumented `file-truename` behaviour in `org-roam--org-roam-file-p`.
### Internal Changes
* [#363](https://github.com/jethrokuan/org-roam/pull/363), [#473](https://github.com/jethrokuan/org-roam/pull/473) Modularize org-roam features.
* [#497](https://github.com/jethrokuan/org-roam/pull/497) Simplify `org-roam--list-files` implementation
## 1.0.0 (23-03-2020)
- [#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
## 1.0.0 (2020-03-23)
Org-roam is now on MELPA! We have squashed most of the bugs, and Org-roam has
been stable for the most part.
### New Features
* [#269](https://github.com/jethrokuan/org-roam/pull/269) Add `org-roam-graphviz-extra-options`
* [#257](https://github.com/jethrokuan/org-roam/pull/257) Add a company-backend `company-org-roam`
* [#284](https://github.com/jethrokuan/org-roam/pull/284), [#289](https://github.com/jethrokuan/org-roam/pull/289) Configurable `org-roam-completion-system` with options `'default`, `'ido`, `'ivy` and `'helm`
* [#289](https://github.com/jethrokuan/org-roam/pull/289) Add customizable `org-roam-fuzzy-match` to allow fuzzy-matching of candidates
* [#290](https://github.com/jethrokuan/org-roam/pull/290) Add `org-roam-date-title-format` and `org-roam-date-filename-format` for customizing Org-roam's date files
* [#296](https://github.com/jethrokuan/org-roam/pull/296) Allow multiple exclusion matchers in `org-roam-graph-exclude-matcher`
- [#269](https://github.com/org-roam/org-roam/pull/269) Add `org-roam-graphviz-extra-options`
- [#257](https://github.com/org-roam/org-roam/pull/257) Add a company-backend `company-org-roam`
- [#284](https://github.com/org-roam/org-roam/pull/284), [#289](https://github.com/org-roam/org-roam/pull/289) Configurable `org-roam-completion-system` with options `'default`, `'ido`, `'ivy` and `'helm`
- [#289](https://github.com/org-roam/org-roam/pull/289) Add customizable `org-roam-fuzzy-match` to allow fuzzy-matching of candidates
- [#290](https://github.com/org-roam/org-roam/pull/290) Add `org-roam-date-title-format` and `org-roam-date-filename-format` for customizing Org-roam's date files
- [#296](https://github.com/org-roam/org-roam/pull/296) Allow multiple exclusion matchers in `org-roam-graph-exclude-matcher`
### Bugfixes
* [#293](https://github.com/jethrokuan/org-roam/pull/293) Fix capture templates not working as expected for `org-roam-find-file`
* [#275](https://github.com/jethrokuan/org-roam/pull/275) Fix database rebuild when `org-roam-directory` is set locally
## 1.0.0-rc1 (06-03-2020)
- [#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
## 1.0.0-rc1 (2020-03-06)
This is a pre-release before the push to MELPA. It contains large
internal changes, with little user-facing changes. Most notably, the
@ -59,82 +463,95 @@ backing storage has been changed to a SQLite database, and a
templating system using `org-capture` is introduced.
### Breaking Changes
* [#200](https://github.com/jethrokuan/org-roam/pull/200) Move Org-roam cache into a SQLite database.
* [#203](https://github.com/jethrokuan/org-roam/pull/203) Roam protocol is deprecated, in favour of extending org-roam-protocol.
- [#200](https://github.com/org-roam/org-roam/pull/200) Move Org-roam cache into a SQLite database.
- [#203](https://github.com/org-roam/org-roam/pull/203) Roam protocol is deprecated, in favour of extending org-roam-protocol.
### New Features
* [#182](https://github.com/jethrokuan/org-roam/pull/182) Support file name aliases via `#+ROAM_ALIAS`.
* [#216](https://github.com/jethrokuan/org-roam/pull/216) Adds templating functionality by extending org-capture.
* [#232](https://github.com/jethrokuan/org-roam/pull/232) Adds a prefix key to `org-roam-show-graph`, to generate graph without opening it.
* [#233](https://github.com/jethrokuan/org-roam/pull/233) Adds `org-roam-graph-exclude-matcher`, which allows exclusion of nodes from graph.
* [#247](https://github.com/jethrokuan/org-roam/pull/247) Add `org-roam-backlink` face, which allows customizing backlinks appearance
* [#259](https://github.com/jethrokuan/org-roam/pull/259) Add optional initial-prompt to `org-roam-find-file`
- [#182](https://github.com/org-roam/org-roam/pull/182) Support file name aliases via `#+ROAM_ALIAS`.
- [#216](https://github.com/org-roam/org-roam/pull/216) Adds templating functionality by extending org-capture.
- [#232](https://github.com/org-roam/org-roam/pull/232) Adds a prefix key to `org-roam-show-graph`, to generate graph without opening it.
- [#233](https://github.com/org-roam/org-roam/pull/233) Adds `org-roam-graph-exclude-matcher`, which allows exclusion of nodes from graph.
- [#247](https://github.com/org-roam/org-roam/pull/247) Add `org-roam-backlink` face, which allows customizing backlinks appearance
- [#259](https://github.com/org-roam/org-roam/pull/259) Add optional initial-prompt to `org-roam-find-file`
### Bugfixes
* [#207](https://github.com/jethrokuan/org-roam/pull/207), [#221](https://github.com/jethrokuan/org-roam/pull/221) small bugfixes to Org-roam graph generation
* [#230](https://github.com/jethrokuan/org-roam/pull/230) remove nonspacing marks from filenames, to prevent cross-platform errors
- [#207](https://github.com/org-roam/org-roam/pull/207), [#221](https://github.com/org-roam/org-roam/pull/221) small bugfixes to Org-roam graph generation
- [#230](https://github.com/org-roam/org-roam/pull/230) remove nonspacing marks from filenames, to prevent cross-platform errors
### New Contributors
* [@acowley][https://github.com/acowley]
* [@teesloane][https://github.com/teesloane]
- [@acowley][https://github.com/acowley]
- [@teesloane][https://github.com/teesloane]
## 0.1.2 (2020-02-21)
### Breaking Changes
* [#143](https://github.com/jethrokuan/org-roam/pull/143) `org-roam-mode` is now a global mode. The installation instructions have changed accordingly.
* [#103](https://github.com/jethrokuan/org-roam/pull/103) Change `org-roam-file-format` to a function: `org-roam-file-name-function` to allow more flexible file name customizaton. Also changes `org-roam-use-timestamp-as-filename` to `org-roam-filename-noconfirm` to better describe what it does.
- [#143](https://github.com/org-roam/org-roam/pull/143) `org-roam-mode` is now a global mode. The installation instructions have changed accordingly.
- [#103](https://github.com/org-roam/org-roam/pull/103) Change `org-roam-file-format` to a function: `org-roam-file-name-function` to allow more flexible file name customizaton. Also changes `org-roam-use-timestamp-as-filename` to `org-roam-filename-noconfirm` to better describe what it does.
### New Features
* [#145](https://github.com/jethrokuan/org-roam/pull/145) `org-roam-show-graph`: Fallback to Emacs SVG viewer
* [#141](https://github.com/jethrokuan/org-roam/pull/141) add variable `org-roam-new-file-directory` for new Org-roam files
* [#138](https://github.com/jethrokuan/org-roam/pull/138) add `org-roam-switch-to-buffer`
* [#124](https://github.com/jethrokuan/org-roam/pull/124), [#141](https://github.com/jethrokuan/org-roam/pull/141) Maintain cache consistency on file rename and delete
* [#87](https://github.com/jethrokuan/org-roam/pull/87), [#90](https://github.com/jethrokuan/org-roam/pull/90) Support encrypted Org files
* [#110](https://github.com/jethrokuan/org-roam/pull/110) Add prefix to `org-roam-insert`, for inserting titles down-cased
* [#99](https://github.com/jethrokuan/org-roam/pull/99) Add keybinding so that `<return>` or `mouse-1` in the backlinks buffer visits the source file of the backlink at point
- [#145](https://github.com/org-roam/org-roam/pull/145) `org-roam-show-graph`: Fallback to Emacs SVG viewer
- [#141](https://github.com/org-roam/org-roam/pull/141) add variable `org-roam-new-file-directory` for new Org-roam files
- [#138](https://github.com/org-roam/org-roam/pull/138) add `org-roam-switch-to-buffer`
- [#124](https://github.com/org-roam/org-roam/pull/124), [#141](https://github.com/org-roam/org-roam/pull/141) Maintain cache consistency on file rename and delete
- [#87](https://github.com/org-roam/org-roam/pull/87), [#90](https://github.com/org-roam/org-roam/pull/90) Support encrypted Org files
- [#110](https://github.com/org-roam/org-roam/pull/110) Add prefix to `org-roam-insert`, for inserting titles down-cased
- [#99](https://github.com/org-roam/org-roam/pull/99) Add keybinding so that `<return>` or `mouse-1` in the backlinks buffer visits the source file of the backlink at point
### Changes
* [#108](https://github.com/jethrokuan/org-roam/pull/108) Locally overwrite the link following behaviour in the org-roam-buffer to open files in the same window `org-roam` was called from
- [#108](https://github.com/org-roam/org-roam/pull/108) Locally overwrite the link following behaviour in the org-roam-buffer to open files in the same window `org-roam` was called from
### Bugfixes
* [#86](https://github.com/jethrokuan/org-roam/pull/86) Fix `org-roam--parse-content` incorrect `:to` computation for nested files
* [#98](https://github.com/jethrokuan/org-roam/pull/98) Fix `org-roam--find-file` picking up temporary files
* [#136](https://github.com/jethrokuan/org-roam/pull/136) Misc bugfixes
- [#86](https://github.com/org-roam/org-roam/pull/86) Fix `org-roam--parse-content` incorrect `:to` computation for nested files
- [#98](https://github.com/org-roam/org-roam/pull/98) Fix `org-roam--find-file` picking up temporary files
- [#136](https://github.com/org-roam/org-roam/pull/136) Misc bugfixes
### Internal
* [#122](https://github.com/jethrokuan/org-roam/pull/122), [#128](https://github.com/jethrokuan/org-roam/pull/128) Improve performance of post-command-hook
* [#92](https://github.com/jethrokuan/org-roam/pull/92), [#105](https://github.com/jethrokuan/org-roam/pull/105) Add tests for core functionality
- [#122](https://github.com/org-roam/org-roam/pull/122), [#128](https://github.com/org-roam/org-roam/pull/128) Improve performance of post-command-hook
- [#92](https://github.com/org-roam/org-roam/pull/92), [#105](https://github.com/org-roam/org-roam/pull/105) Add tests for core functionality
### New Contributors
* [@frigge](https://github.com/frigge)
* [@juergenhoetzel](https://github.com/juergenhoetzel)
* [@chip2n](https://github.com/chip2n)
* [@l3kn](https://github.com/l3kn)
* [@jdormit](https://github.com/jdormit)
* [@herbertjones](https://github.com/herbertjones)
* [@CeleritasCelery](https://github.com/CeleritasCelery)
* [@daniel-koudouna](https://github.com/daniel-koudouna)
- [@frigge](https://github.com/frigge)
- [@juergenhoetzel](https://github.com/juergenhoetzel)
- [@chip2n](https://github.com/chip2n)
- [@l3kn](https://github.com/l3kn)
- [@jdormit](https://github.com/jdormit)
- [@herbertjones](https://github.com/herbertjones)
- [@CeleritasCelery](https://github.com/CeleritasCelery)
- [@daniel-koudouna](https://github.com/daniel-koudouna)
## 0.1.1 (2020-02-15)
Mostly a documentation/cleanup release.
### New Features
* [#62](https://github.com/jethrokuan/org-roam/pull/62) Add the options `org-roam-use-timestamps-as-filename` and `org-roam-file-format`, more in documentation.
- [#62](https://github.com/org-roam/org-roam/pull/62) Add the options `org-roam-use-timestamps-as-filename` and `org-roam-file-format`, more in documentation.
### Breaking Changes
* [#62](https://github.com/jethrokuan/org-roam/pull/62) The ID (file-name) workflow is no longer first-class, but a fallback when titles don't exist.
- [#62](https://github.com/org-roam/org-roam/pull/62) The ID (file-name) workflow is no longer first-class, but a fallback when titles don't exist.
### Changes
* [#66](https://github.com/jethrokuan/org-roam/pull/66), [#68](https://github.com/jethrokuan/org-roam/pull/68): Improved the quality of the package in preparation of submission to MELPA
* [#73](https://github.com/jethrokuan/org-roam/pull/73): Added CI to the project via Github Issues (Thanks [@alphapapa](https://github.com/alphapapa/) for scripts and setup)
* [#69](https://github.com/jethrokuan/org-roam/pull/69), [#72](https://github.com/jethrokuan/org-roam/pull/72), [#75](https://github.com/jethrokuan/org-roam/pull/75): Major cleanup and de-duplication of code
- [#66](https://github.com/org-roam/org-roam/pull/66), [#68](https://github.com/org-roam/org-roam/pull/68): Improved the quality of the package in preparation of submission to MELPA
- [#73](https://github.com/org-roam/org-roam/pull/73): Added CI to the project via Github Issues (Thanks [@alphapapa](https://github.com/alphapapa/) for scripts and setup)
- [#69](https://github.com/org-roam/org-roam/pull/69), [#72](https://github.com/org-roam/org-roam/pull/72), [#75](https://github.com/org-roam/org-roam/pull/75): Major cleanup and de-duplication of code
### Bugfixes
* [#67](https://github.com/jethrokuan/org-roam/pull/67): Fixed `org-roam--make-file` not creating files with extensions
* [#71](https://github.com/jethrokuan/org-roam/pull/71), [#78](https://github.com/jethrokuan/org-roam/pull/78): Fixed `org-roam-insert` not inserting correct paths
* [#82](https://github.com/jethrokuan/org-roam/pull/82): Fixed nested Org-roam files not being detected as part of Org-roam
- [#67](https://github.com/org-roam/org-roam/pull/67): Fixed `org-roam--make-file` not creating files with extensions
- [#71](https://github.com/org-roam/org-roam/pull/71), [#78](https://github.com/org-roam/org-roam/pull/78): Fixed `org-roam-insert` not inserting correct paths
- [#82](https://github.com/org-roam/org-roam/pull/82): Fixed nested Org-roam files not being detected as part of Org-roam
<!-- Local Variables: -->
<!-- eval: (auto-fill-mode -1) -->

29
Eldev Normal file
View File

@ -0,0 +1,29 @@
; -*- mode: emacs-lisp; lexical-binding: t; no-byte-compile: t -*-
;; explicitly set main file
(setf eldev-project-main-file "org-roam.el")
(eldev-use-package-archive 'gnu)
(eldev-use-package-archive 'melpa-unstable)
;; allow to load test helpers
(eldev-add-loading-roots 'test "test/utils")
;; Tell checkdoc not to demand two spaces after a period.
(setq sentence-end-double-space nil)
(setf eldev-lint-default '(elisp))
(setf eldev-standard-excludes `(:or ,eldev-standard-excludes "org-roam-macs.el"))
(with-eval-after-load 'elisp-lint
;; We will byte-compile with Eldev.
(setf elisp-lint-ignored-validators '("package-lint" "fill-column")
enable-local-variables :all))
;; Teach linter how to properly indent emacsql vectors
(eldev-add-extra-dependencies 'lint 'emacsql)
(add-hook 'eldev-lint-hook
(lambda ()
(eldev-load-project-dependencies 'lint nil t)
(require 'emacsql)
(call-interactively #'emacsql-fix-vector-indentation)))

View File

@ -1,56 +1,29 @@
# * makem.sh/Makefile --- Script to aid building and testing Emacs Lisp packages
.PHONY: clean
clean:
eldev clean all
# This Makefile is from the makem.sh repo: <https://github.com/alphapapa/makem.sh>.
.PHONY: prepare
prepare:
eldev -C --unstable -p -dtT prepare
# * Arguments
.PHONY: lint
lint:
eldev -C --unstable -T lint
# For consistency, we use only var=val options, not hyphen-prefixed options.
.PHONY: test
test:
eldev -C --unstable -T test
# NOTE: I don't like duplicating the arguments here and in makem.sh,
# but I haven't been able to find a way to pass arguments which
# conflict with Make's own arguments through Make to the script.
# Using -- doesn't seem to do it.
docs:
make -C doc all
ifdef install-deps
INSTALL_DEPS = "--install-deps"
endif
ifdef install-linters
INSTALL_LINTERS = "--install-linters"
endif
html:
make -C doc html-dir
ifdef sandbox
ifeq ($(sandbox), t)
SANDBOX = --sandbox
else
SANDBOX = --sandbox $(sandbox)
endif
endif
install: install-docs
ifdef debug
DEBUG = "--debug"
endif
install-docs: docs
make -C doc install-docs
# ** Verbosity
# Since the "-v" in "make -v" gets intercepted by Make itself, we have
# to use a variable.
verbose = $(v)
ifneq (,$(findstring vv,$(verbose)))
VERBOSE = "-vv"
else ifneq (,$(findstring v,$(verbose)))
VERBOSE = "-v"
endif
# * Rules
# TODO: Handle cases in which "test" or "tests" are called and a
# directory by that name exists, which can confuse Make.
%:
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS) $(@)
.DEFAULT: init
init:
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS)
install-info: info
make -C doc install-info

275
README.md
View File

@ -1,80 +1,235 @@
[![License GPL 3][badge-license]](http://www.gnu.org/licenses/gpl-3.0.txt)
[![Documentation Status](https://readthedocs.org/projects/org-roam/badge/?version=latest)](https://org-roam.readthedocs.io/en/latest/?badge=latest)
[![GitHub Release](https://img.shields.io/github/v/release/jethrokuan/org-roam)](https://img.shields.io/github/v/release/jethrokuan/org-roam)
[![MELPA](https://melpa.org/packages/org-roam-badge.svg)](https://melpa.org/#/org-roam)
# Org-roam [![GitHub Release][release-badge]][release] [![MELPA][melpa-badge]][melpa] [![License GPL 3][gpl3-badge]][gpl3]
## Synopsis
<img src="https://www.orgroam.com/img/logo.svg" align="right" alt="Org-roam Logo" width="240">
Org-roam is a [Roam][roamresearch] replica built on top of the
all-powerful [Org-mode][org].
Org-roam is a plain-text knowledge management system. It brings some of
[Roam's][roamresearch] more powerful features into the [Org-mode][org]
ecosystem.
Org-roam is a solution for effortless non-hierarchical note-taking
with Org-mode. With Org-roam, notes flow naturally, making note-taking
fun and easy. Org-roam should also work as a plug-and-play solution
for anyone already using Org-mode for their personal wiki.
Org-roam borrows principles from the Zettelkasten method, providing a solution
for non-hierarchical note-taking. It should also work as a plug-and-play
solution for anyone already using Org-mode for their personal wiki.
Org-roam aims to implement the core features of Roam, leveraging the
mature ecosystem around Org-mode where possible. Eventually, we hope
to further introduce features enabled by the Emacs ecosystem.
- **Private and Secure**: Edit your personal wiki completely offline, entirely
in your control. Encrypt your notes with GPG. Take lasting notes in
plain-text.
- **Networked Thought**: Connect notes and thoughts together with ease using
backlinks. Discover surprising and previously unseen connections in your notes
with the built-in graph visualization.
- **Extensible and Powerful**: Leverage Emacs' fantastic text-editing interface,
and the mature Emacs and Org-mode ecosystem of packages.
- **Free and Open Source**: Org-roam is licensed under the GNU General Public
License version 3 or later.
[@technovangelist](https://github.com/technovangelist/) has produced a video
describing Org-roam and the concepts behind it:
[![Making Connections in your Notes](http://img.youtube.com/vi/Lg61ocfxk3c/0.jpg)](http://www.youtube.com/watch?v=Lg61ocfxk3c "Making Connections in your Notes")
As of February 2020, it is in a very early stage of development.
Important links:
<p align="center">
<img src="https://www.orgroam.com/img/screenshot.png" alt="Org-roam Screenshot" width="738">
</p>
- **[Documentation][docs]**
- **[Org-roam Slack][slack]**
## A Preview
Here's a screenshot of `org-roam`. The `org-roam` buffer shows
backlinks for the active org buffer in the left window, as well as the
surrounding content in the backlink file. The database is built once,
and updated incrementally. The graph is generated from the link
structure, and can be used to navigate to the respective files.
![img](doc/images/org-roam-graph.gif)
- **[Discourse][discourse]**
- **[Slack][slack]**
- **[Frequently Asked Questions][faq]**
- **[Changelog](CHANGELOG.md)**
## Installation
You can install `org-roam` using `package.el`:
Down below you will find basic installation instructions for how to quickly
install `org-roam` using various environments for various purposes. For more
detailed information, please read the [manual][docs].
### Using `package.el`
<details>
<summary>Toggle instructions</summary>
You can install `org-roam` from [MELPA](https://melpa.org/) or [MELPA
Stable](https://stable.melpa.org/) using `package.el`:
```
M-x package-install RET org-roam RET
```
</details>
Here's a sample configuration with using `use-package`:
### Using `straight.el`
<details>
<summary>Toggle instructions</summary>
Installation from MELPA or MELPA Stable using `straight.el`:
```emacs-lisp
(straight-use-package 'org-roam)
```
Or with `use-package`:
```emacs-lisp
(use-package org-roam
:hook
(after-init . org-roam-mode)
:custom
(org-roam-directory "/path/to/org-files/")
:bind (:map org-roam-mode-map
(("C-c n l" . org-roam)
("C-c n f" . org-roam-find-file)
("C-c n g" . org-roam-show-graph))
:map org-mode-map
(("C-c n i" . org-roam-insert))))
:straight t
...)
```
For more detailed installation and configuration instructions (including for
Doom and Spacemacs users), please see [the
documentation](https://org-roam.readthedocs.io/en/master/installation/).
If you need to install the package directly from the source repository, instead
of from MELPA, the next sample shows how to do so:
```emacs-lisp
(use-package org-roam
:straight (:host github :repo "org-roam/org-roam"
:files (:defaults "extensions/*"))
...)
```
If you plan to use your own local fork for the development and contribution, the
next sample will get you there:
```emacs-lisp
(use-package org-roam
:straight (:local-repo "/path/to/org-roam-fork"
:files (:defaults "extensions/*")
:build (:not compile))
...)
```
</details>
### Using Doom Emacs
<details>
<summary>Toggle instructions</summary>
Doom's `:lang org` module comes with support for `org-roam`, but it's not
enabled by default. To activate it pass `+roam2` flag to `org` module in your
`$DOOMDIR/init.el` (e.g. `(org +roam2)`), save the file and run `doom sync -u`
in your shell.
To provide better stability, Doom pins the package to a specific commit. If you
need to unpin it *(not recommended doing that, request Doom to bump the package
instead)* use the next in your `packages.el`:
```emacs-lisp
(unpin! org-roam)
```
If for some reasons you want to use a different recipe for `org-roam`, you can
use the next form in your `packages.el` to install the package from a recipe
repository (e.g. MELPA):
```emacs-lisp
(package! org-roam)
```
You can pass `:pin "commit hash"` to pin the package to a specific commit.
With the next sample you can install the package directly from the source
repository:
```emacs-lisp
(package! org-roam
:recipe (:host github :repo "org-roam/org-roam"
:files (:defaults "extensions/*")))
```
And if you plan to use your own local fork for the development or contribution,
the next sample will get you there:
```emacs-lisp
(package! org-roam
:recipe (:local-repo "/path/to/org-roam-fork"
:files (:defaults "extensions/*")
:build (:not compile)))
```
</details>
### Without a package manager
<details>
<summary>Toggle instructions</summary>
To install the package without using a package manager you have the next two
options:
1. Install the package by cloning it with `git` from the source repository.
2. Or install the package by downloading the latest [release
version](https://github.com/org-roam/org-roam/releases).
In both of the cases you will need to ensure that you have all the required
dependencies. These include:
- dash
- f
- s
- org (9.6 is the minimum required version!)
- emacsql
- magit-section
- filenotify-recursive
After installing the package, you will need to properly setup `load-path` to the
package:
``` emacs-lisp
(add-to-list 'load-path "/path/to/org-roam/")
(add-to-list 'load-path "/path/to-org-roam/extensions/")
```
After which you should be able to resolve `(require 'org-roam)` call without any
problems.
Org-roam also comes with `.texi` files to integrate with Emacs' built-in Info
system. Read the manual to find more details for how to install them manually.
</details>
## Configuration
Here's a very basic sample for configuration of `org-roam` using `use-package`:
```emacs-lisp
(use-package org-roam
:ensure t
:custom
(org-roam-directory (file-truename "/path/to/org-files/"))
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph)
("C-c n i" . org-roam-node-insert)
("C-c n c" . org-roam-capture)
;; Dailies
("C-c n j" . org-roam-dailies-capture-today))
:config
;; If you're using a vertical completion framework, you might want a more informative completion interface
(setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
(org-roam-db-autosync-mode)
;; If using org-roam-protocol
(require 'org-roam-protocol))
```
Note that the `file-truename` function is only necessary when you use symbolic
link to `org-roam-directory`. Org-roam won't automatically resolve symbolic link
to the directory.
## Getting Started
[David Wilson](https://github.com/daviwil) of [System
Crafters](https://www.youtube.com/c/SystemCrafters) has produced an introductory
video that covers the basic commands:
[![Getting Started with Org Roam - Build a Second Brain in Emacs](https://img.youtube.com/vi/AyhPmypHDEw/0.jpg)](https://www.youtube.com/watch?v=AyhPmypHDEw)
## Getting Help
Before creating a new topic/issue, please be mindful of our time and ensure that
it has not already been addressed on [GitHub][issues] or on
[Discourse][discourse].
- If you are new to Emacs and have problem setting up Org-roam, please ask your
question on [Slack, channel #how-do-i][slack].
- For quick questions, please ask them on [Slack, channel
#troubleshooting][slack].
- If something is not working as it should, or if you would like to suggest a
new feature, please [create a new issue][issues].
- If you have questions about your workflow with the slip-box method, please
find a relevant topic on [Discourse][discourse], or create a new one.
## Knowledge Bases using Org-roam
- [Jethro Kuan](https://braindump.jethro.dev/)
([Source](https://github.com/jethrokuan/braindump/tree/master/org))
## Changelog
A changelog is being maintained [here](CHANGELOG.md)
- [Alexey Shmalko](https://www.alexeyshmalko.com/)
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
- [Martin Edström](https://edstrom.dev/)
## Contributing
@ -85,10 +240,18 @@ request. Please also see [CONTRIBUTING.md](.github/CONTRIBUTING.md).
## License
Copyright © Jethro Kuan and contributors. Distributed under the GNU
General Public License, Version 3
General Public License, Version 3.
[roamresearch]: https://www.roamresearch.com/
[org]: https://orgmode.org/
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
[docs]: https://org-roam.readthedocs.io/
[slack]: https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg
[gpl3-badge]: https://img.shields.io/badge/license-GPL_3-green.svg
[gpl3]: http://www.gnu.org/licenses/gpl-3.0.txt
[melpa-badge]: https://melpa.org/packages/org-roam-badge.svg
[melpa]: https://melpa.org/#/org-roam
[release-badge]: https://img.shields.io/github/v/release/org-roam/org-roam
[release]: https://github.com/org-roam/org-roam/releases
[docs]: https://www.orgroam.com/manual.html
[discourse]: https://org-roam.discourse.group/
[slack]: https://join.slack.com/t/orgroam/shared_invite/zt-wuoize1z-x3UyQnQ0WHF0RhuEQ2NLnQ
[issues]: https://github.com/org-roam/org-roam/issues
[faq]: https://www.orgroam.com/manual.html#FAQ

107
default.mk Normal file
View File

@ -0,0 +1,107 @@
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
## User options ######################################################
#
# You can override these settings in "config.mk" or on the command
# line.
#
# You might also want to set LOAD_PATH. If you do, then it must
# contain "-L .".
#
# If you don't do so, then the default is set in the "Load-Path"
# section below. The default assumes that all dependencies are
# installed either at "../<DEPENDENCY>", or when using package.el
# at "ELPA_DIR/<DEPENDENCY>-<HIGHEST-VERSION>".
sharedir ?= $(HOME)/.local/share
lispdir ?= $(sharedir)/emacs/site-lisp/org-roam
infodir ?= $(sharedir)/info
docdir ?= $(sharedir)/doc/org-roam
statsdir ?= $(TOP)/doc/stats
CP ?= install -p -m 644
MKDIR ?= install -p -m 755 -d
RMDIR ?= rm -rf
TAR ?= tar
SED ?= sed
EMACSBIN ?= emacs
BATCH = $(EMACSBIN) -Q --batch $(LOAD_PATH)
INSTALL_INFO ?= $(shell command -v ginstall-info || printf install-info)
MAKEINFO ?= makeinfo
MANUAL_HTML_ARGS ?= --css-ref /assets/page.css
## Files #############################################################
PKG = org-roam
PACKAGES = org-roam
TEXIPAGES = $(addsuffix .texi,$(PACKAGES))
INFOPAGES = $(addsuffix .info,$(PACKAGES))
HTMLFILES = $(addsuffix .html,$(PACKAGES))
HTMLDIRS = $(PACKAGES)
PDFFILES = $(addsuffix .pdf,$(PACKAGES))
EPUBFILES = $(addsuffix .epub,$(PACKAGES))
ELS = org-roam.el
ELS += org-roam-capture.el
ELS += org-roam-compat.el
ELS += org-roam-db.el
ELS += org-roam-mode.el
ELS += org-roam-node.el
ELS += org-roam-utils.el
ELS += extensions/org-roam-dailies.el
ELS += extensions/org-roam-graph.el
ELS += extensions/org-roam-overlay.el
ELS += extensions/org-roam-protocol.el
ELCS = $(ELS:.el=.elc)
ELMS = org-roam.el $(filter-out $(addsuffix .el,$(PACKAGES)),$(ELS))
ELGS = org-roam-autoloads.el org-roam-version.el
## Versions ##########################################################
VERSION ?= $(shell test -e $(TOP).git && git describe --tags --abbrev=0 | cut -c2-)
EMACS_VERSION = 26.1
EMACSOLD := $(shell $(BATCH) --eval \
"(and (version< emacs-version \"$(EMACS_VERSION)\") (princ \"true\"))")
ifeq "$(EMACSOLD)" "true"
$(error At least version $(EMACS_VERSION) of Emacs is required)
endif
## Load-Path #########################################################
ifndef LOAD_PATH
ELPA_DIR ?= $(HOME)/.emacs.d/elpa
SYSTYPE := $(shell $(EMACSBIN) -Q --batch --eval "(princ system-type)")
ifeq ($(SYSTYPE), windows-nt)
CYGPATH := $(shell cygpath --version 2>/dev/null)
endif
LOAD_PATH = -L $(TOP)
# When making changes here, then don't forget to adjust "Makefile",
# ".travis.yml", ".github/ISSUE_TEMPLATE/bug_report.md",
# `magit-emacs-Q-command' and the "Installing from the Git Repository"
# info node accordingly. Also don't forget to "rgrep \b<pkg>\b".
endif # ifndef LOAD_PATH
ifndef ORG_LOAD_PATH
ORG_LOAD_PATH = $(LOAD_PATH)
ORG_LOAD_PATH += -L $(TOP)../ox-texinfo-plus
ORG_LOAD_PATH += -L $(TOP)../org-mode/contrib/lisp
ORG_LOAD_PATH += -L $(TOP)../org-mode/lisp
endif
## Publish ###########################################################
PUBLISH_TARGETS ?= html html-dir pdf epub
DOCBOOK_XSL ?= /usr/share/xml/docbook/stylesheet/docbook-xsl/epub/docbook.xsl
EPUBTRASH = epub.xml META-INF OEBPS

0
doc/.nojekyll Normal file
View File

37
doc/AUTHORS.md Normal file
View File

@ -0,0 +1,37 @@
Authors
=======
The following people have contributed to Org-Roam.
Names below are sorted alphabetically.
Author
------
- Jethro Kuan <jethrokuan95@gmail.com>
Maintainers
----------
- Jethro Kuan <jethrokuan95@gmail.com>
- Leo Vivier <leo.vivier+dev@gmail.com>
Contributors
------------
- Alexey Shmalko <rasen.dubi@gmail.com>
- James Ravn <james@r-vn.org>
- Jethro Kuan <jethrokuan95@gmail.com>
- Johann Klähn <johann@jklaehn.de>
- Josh English <josh@joshenglish.com>
- Jürgen Hötzel <juergen@archlinux.org>
- Langston Barrett <langston.barrett@gmail.com>
- Leo Vivier <leo.vivier+dev@gmail.com>
- Michael Glaesemann <grzm@seespotcode.net>
- Michael Herold <github@michaeljherold.com>
- Noboru <noboru.ota@gmail.com>
- N V <44036031+progfolio@users.noreply.github.com>
- Rafael Accácio Nogueira <raccacio@poli.ufrj.br>
- Roland Coeurjoly <rolandcoeurjoly@gmail.com>
- Sayan <dit7ya@users.noreply.github.com>
- Tim Quelch <tim@tquelch.com>

127
doc/Makefile Normal file
View File

@ -0,0 +1,127 @@
-include ../config.mk
include ../default.mk
###################################################################
MANUAL_HTML_ARGS = --css-ref assets/page.css
.PHONY: texi install clean AUTHORS.md stats
all: info
## Build #############################################################
info: $(INFOPAGES) dir
html: $(HTMLFILES)
pdf: $(PDFFILES)
epub: $(EPUBFILES)
%.info: %.texi
@printf "Generating $@\n"
@$(MAKEINFO) --no-split $< -o $@
dir: org-roam.info
@printf "Generating dir\n"
@echo $^ | xargs -n 1 $(INSTALL_INFO) --dir=$@
%.html: %.texi
@printf "Generating $@\n"
@$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) $<
html-dir:
@$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) org-roam.texi
mv org-roam.html manual.html
%.pdf: %.texi
@printf "Generating $@\n"
@texi2pdf --clean $< > /dev/null
%.epub: %.texi
@printf "Generating $@\n"
@$(MAKEINFO) --docbook $< -o epub.xml
@xsltproc $(DOCBOOK_XSL) epub.xml 2> /dev/null
@echo "application/epub+zip" > mimetype
@zip -X --quiet --recurse-paths -0 $@ mimetype
@zip -X --quiet --recurse-paths -9 --no-dir-entries $@ META-INF OEBPS
@$(RMDIR) $(EPUBTRASH)
## Install ###########################################################
install: install-info install-docs
install-docs: install-info
@$(MKDIR) $(DESTDIR)$(docdir)
$(CP) AUTHORS.md $(DESTDIR)$(docdir)
install-info: info
@$(MKDIR) $(DESTDIR)$(infodir)
$(CP) $(INFOPAGES) $(DESTDIR)$(infodir)
## Clean #############################################################
clean:
@printf "Cleaning doc/*...\n"
@$(RMDIR) dir $(INFOPAGES) $(HTMLFILES) $(HTMLDIRS) $(PDFFILES)
@$(RMDIR) $(EPUBFILES) $(EPUBTRASH)
## Release management ################################################
ORG_ARGS = --batch -Q $(ORG_LOAD_PATH)
ORG_ARGS += -l ox-extra -l ox-texinfo+
ORG_ARGS += --eval "(or (require 'org-man nil t) (require 'ol-man))"
ORG_EVAL = --eval "(ox-extras-activate '(ignore-headlines))"
ORG_EVAL += --eval "(setq indent-tabs-mode nil)"
ORG_EVAL += --eval "(setq org-src-preserve-indentation nil)"
ORG_EVAL += --funcall org-texinfo-export-to-texinfo
# This target first bumps version strings in the Org source. The
# necessary tools might be missing so other targets do not depend
# on this target and it has to be run explicitly when appropriate.
#
# AMEND=t make texi Update manual to be amended to HEAD.
# VERSION=N make texi Update manual for release.
#
texi:
@$(EMACSBIN) $(ORG_ARGS) $(PKG).org $(ORG_EVAL)
@printf "\n" >> $(PKG).texi
@rm -f $(PKG).texi~
stats:
@printf "Generating statistics\n"
@gitstats -c style=/assets/stats.css -c max_authors=999 $(TOP) $(statsdir)
authors: AUTHORS.md
AUTHORS.md:
@printf "Generating AUTHORS.md..."
@test -e $(TOP).git \
&& (printf "$$AUTHORS_HEADER\n" > $@ \
&& git log --pretty=format:'- %aN <%aE>' | sort -u >> $@ \
&& printf "done\n" ; ) \
|| printf "FAILED (non-fatal)\n"
# Templates ##########################################################
define AUTHORS_HEADER
Authors
=======
The following people have contributed to Org-Roam.
Names below are sorted alphabetically.
Author
------
- Jethro Kuan <jethrokuan95@gmail.com>
Maintainers
----------
- Jethro Kuan <jethrokuan95@gmail.com>
- Leo Vivier <leo.vivier+dev@gmail.com>
Contributors
------------
endef
export AUTHORS_HEADER

View File

@ -1,41 +0,0 @@
The bulk of Org-roam's functionality is built on top of vanilla
Org-mode. However, to support additional functionality, Org-roam adds
several Org-roam-specific keywords. These functionality are not
crucial to effective use of Org-roam.
## File Aliases
Suppose you want a note to be referred to by different names (e.g.
"World War 2", "WWII"). You may specify such aliases using the
`#+ROAM_ALIAS` attribute:
```org
#+TITLE: World War 2
#+ROAM_ALIAS: "WWII" "World War II"
```
## File Refs
Refs are unique identifiers for files. Each note can only have 1 ref.
For example, a note for a website may contain a ref:
```org
#+TITLE: Google
#+ROAM_KEY: https://www.google.com/
```
These keys come in useful for when taking website notes, using the
`roam-ref` protocol (see [Roam Protocol](roam_protocol.md)).
Alternatively, add a ref for notes for a specific paper, using its
[org-ref](https://github.com/jkitchin/org-ref) citation key:
```org
#+TITLE: Neural Ordinary Differential Equations
#+ROAM_KEY: cite:chen18_neural_ordin_differ_equat
```
The backlinks buffer will show any cites of this key: e.g.
![org-ref-citelink](images/org-ref-citelink.png)

68
doc/assets/page.css Normal file
View File

@ -0,0 +1,68 @@
:root {
--border: #526980;
--code: #007;
}
body {
margin: 5ex 10ex;
max-width: 80ex;
line-height: 1.5;
font-family: sans-serif;
}
h1, h2, h3 {
font-weight: normal;
}
pre, code {
font-family: x, monospace;
}
pre {
padding: 1ex;
background: #eee;
border: solid 1px #ddd;
min-width: 0;
font-size: 80%;
overflow: auto;
}
code {
color: var(--code);
}
img {
max-width: 100%;
}
table {
border-collapse: collapse;
width: 100%;
}
pre.menu-comment {
background: none;
border: none;
font-family: sans-serif;
padding: 0;
margin: 0;
font-size: 100%;
}
thead {
border-bottom: 1px solid var(--border);
}
tfoot {
border-top: 1px solid var(--border);
}
blockquote {
margin-left: 1rem;
font-style: italic;
font-family: serif;
border-left: 3px solid;
border-left-color: currentcolor;
border-color: var(--text-color);
padding-left: 1em;
}

View File

@ -1,11 +0,0 @@
---
title: "Comparing Org-roam With Other Packages"
metaTitle: "Comparing Org-roam With Other Packages"
metaDescription: "Comparing Org-roam With Other Packages"
---
# Org-brain
# Zetteldeft
# Org-zettelkasten

View File

@ -1,142 +0,0 @@
The number of configuration options is deliberately kept small, to
keep the Org-roam codebase manageable. However, we attempt to
accommodate as many usage styles as possible.
All of Org-roam's customization options can be viewed via `M-x
customize-group org-roam`.
## Setting the Org-roam Directory
Set `org-roam-directory` to the folder containing all your Org files:
```emacs-lisp
(setq org-roam-directory "/path/to/org/")
```
Every Org file, at any level of nesting, within `/path/to/org/` is
considered part of the Org-roam ecosystem.
### Having More Than One Org-roam Directory
Emacs supports directory-local variables, allowing the value of
`org-roam-directory` to be different in different directories. It does
this by checking for a file named `.dir-locals.el`.
To add support for multiple directories, override the
`org-roam-directory` variable using directory-local variables. This is
what `.dir-locals.el` may contain:
```emacs-lisp
((nil . ((org-roam-directory . "/path/to/here/"))))
```
All files within that directory will be treated as their own separate
set of Org-roam files. Remember to run `org-roam-db-build-cache` from a
file within that directory, at least once.
## Org-roam Buffer
The Org-roam buffer defaults to popping up from the right. You may
choose to set it to pop up from the left with `(setq
org-roam-buffer-position 'left)`.
The Org-roam buffer name can also be renamed: e.g. `(setq
org-roam-buffer "*my-buffer-name*")`.
The Org-roam buffer width is adjustable via `org-roam-buffer-width`.
The value of `org-roam-buffer-width` set as a percentage of the total
frame width. For example:
```emacs-lisp
(setq org-roam-buffer-width 0.4)
```
Will result in the Org-roam buffer taking up 40% of the screen width.
You can change backlinks appearance in the buffer by customizing
`org-roam-backlink` face (`M-x customize-face org-roam-backlink`).
## Org-roam Links
By default, links are inserted with the title as the link description.
This can make them hard to distinguish from external links. You may
choose add special indicators for Org-roam links by tweaking
`org-roam-link-title-format`, for example:
```emacs-lisp
(setq org-roam-link-title-format "R:%s")
```
If your version of Org is at least `9.2`, you may also choose to
simply style the link differently, by customizing `org-roam-link` face
(`M-x customize-face org-roam-link`).
## Org-roam Files
Org-roam files are created and prefilled using Org-roam's templating
system. The templating system is customizable, and the system is
described in detail in the [Org-roam Template](templating.md) page.
### Encryption
Encryption (via GPG) can be enabled for all new files by setting
`org-roam-encrypt-files` to `t`. When enabled, new files are created
with the `.org.gpg` extension and decryption are handled automatically
by EasyPG.
Note that Emacs will prompt for a password for encrypted files during
cache updates if it requires reading the encrypted file. To reduce the
number of password prompts, you may wish to cache the password.
## Org-roam Graph Viewer
Org-roam generates an SVG image using
[Graphviz](https://graphviz.org/). To setup graph navigation, see the
[Graph Setup](graph_setup.md) page.
Org-roam tries its best to locate the Graphviz executable from your
`PATH`, but if it fails to do so, you may set it manually:
```
(setq org-roam-graph-executable "/path/to/dot")
```
You may also choose to use `neato` in place of `dot`, which generates a more compact graph layout.
```
(setq org-roam-graph-executable "/path/to/neato")
(setq org-roam-graph-extra-config '(("overlap" . "false")))
```
Org-roam also attempts to use Firefox (located on `PATH`) to view the
SVG, you may choose to set it to any compatible program:
```
(setq org-roam-graph-viewer "/path/to/image-viewer")
```
### Excluding Nodes and Edges
One may want to exclude certain files to declutter the graph. You can do so by setting `org-roam-graph-exclude-matcher`.
```
(setq org-roam-graph-exclude-matcher '("private" "dailies"))
```
This setting excludes all files whose path contain "private" or "dailies".
## Org-roam Completion System
Org-roam offers completion when choosing note titles etc.
The completion system is configurable. The default setting,
```
(setq org-roam-completion-system 'default)
```
uses Emacs' standard `completing-read`. If you prefer [Helm](https://emacs-helm.github.io/helm/), use
```
(setq org-roam-completion-system 'helm)
```
Other options included `'ido`, and `'ivy'`.

85
doc/css/styles.css Normal file
View File

@ -0,0 +1,85 @@
body {
margin: 20px;
background: #303030;
color: #f5f5f5;
font-size: 1.6rem;
font-weight: 300;
}
.container {
max-width: 800px;
}
.nav {
margin-top: 5rem;
}
.nav-item a {
/* color: #797979; */
color: #bebebe;
text-decoration: none;
font-family: "Consolas", "Monaco", "Menlo", monospace;
}
.nav-item a:hover {
cursor: pointer;
/* color: #4d4a4a; */
color: #dcdcdc;
border: none;
}
.hero {
color: #f5f5f5;
}
.hero div {
margin-bottom: 5rem;
}
.hero h3 {
/* font-family: "Edelsans", sans-serif; */
font-size: 5rem;
margin-bottom: 0;
}
.hero h5 {
margin-top: 1rem;
margin-bottom: 0;
/* font-weight: 200; */
font-weight: 250;
}
.grid-demo-col {
background: #e4e4e4;
}
a {
color: #cd86ff;
}
a:hover {
color: #dbb9f3;
}
img {
max-width: 100%;
}
.footer-links {
font-size: 1.5rem;
color: #f5f5f5;
text-decoration: none;
font-weight: 250;
}
.header {
font-weight: 200;
}
#footer {
margin-bottom: 3rem;
}
#footer h5 {
margin-bottom: 1.5rem;
}

View File

@ -1,134 +0,0 @@
A number of packages work well combined with Org-Roam:
## Deft
[Deft][deft] provides a nice interface for browsing and filtering
org-roam notes.
```emacs-lisp
(use-package deft
:after org
:bind
("C-c n d" . deft)
:custom
(deft-recursive t)
(deft-use-filter-string-for-filename t)
(deft-default-extension "org")
(deft-directory "/path/to/org-roam-files/"))
```
If the title of the Org file is not the first line, you might not get
nice titles. You may choose to patch this to use `org-roam`'s
functionality. Here I'm using [el-patch](https://github.com/raxod502/el-patch):
```emacs-lisp
(use-package el-patch
:straight (:host github
:repo "raxod502/el-patch"
:branch "develop"))
(eval-when-compile
(require 'el-patch))
(use-package deft
;; same as above...
:config/el-patch
(defun deft-parse-title (file contents)
"Parse the given FILE and CONTENTS and determine the title.
If `deft-use-filename-as-title' is nil, the title is taken to
be the first non-empty line of the FILE. Else the base name of the FILE is
used as title."
(el-patch-swap (if deft-use-filename-as-title
(deft-base-filename file)
(let ((begin (string-match "^.+$" contents)))
(if begin
(funcall deft-parse-title-function
(substring contents begin (match-end 0))))))
(org-roam--get-title-or-slug file))))
```
The Deft interface can slow down quickly when the number of files get
huge. [Notdeft][notdeft] is a fork of Deft that uses an external
search engine and indexer.
## Org-journal
[Org-journal](https://github.com/bastibe/org-journal) is a more powerful
alternative to the simple function `org-roam-dailies-today`. It provides better
journaling capabilities, and a nice calendar interface to see all dated entries.
```emacs-lisp
(use-package org-journal
:bind
("C-c n j" . org-journal-new-entry)
:custom
(org-journal-date-prefix "#+TITLE: ")
(org-journal-file-format "%Y-%m-%d.org")
(org-journal-dir "/path/to/org-roam-files/")
(org-journal-date-format "%A, %d %B %Y"))
```
## Note-taking Add-ons
These are some plugins that make note-taking in Org-mode more
enjoyable.
### Org-download
[Org-download][org-download] lets you screenshot and yank images from
the web into your notes:
![org-download](images/org-download.gif)
```emacs-lisp
(use-package org-download
:after org
:bind
(:map org-mode-map
(("s-Y" . org-download-screenshot)
("s-y" . org-download-yank))))
```
### mathpix.el
[mathpix.el][mathpix-el] uses [Mathpix's](https://mathpix.com/) API to convert clips into
latex equations:
![mathpix](images/mathpix.gif)
```emacs-lisp
(use-package mathpix.el
:straight (:host github :repo "jethrokuan/mathpix.el")
:custom ((mathpix-app-id "app-id")
(mathpix-app-key "app-key"))
:bind
("C-x m" . mathpix-screenshot))
```
### Org-noter / Interleave
[Org-noter][org-noter] and [Interleave][interleave] are both projects
that allow synchronised annotation of documents (PDF, EPUB etc.)
within Org-mode.
### Org-ref
[Org-ref][org-ref] does citation and bibliography management in
Org-mode, and a great tool for scientific notes.
### Spaced Repetition
[Org-fc][org-fc] is a spaced repetition system that scales well with a
large number of files. Other alternatives include
[org-drill][org-drill], and [pamparam][pamparam].
[deft]: https://jblevins.org/projects/deft/
[notdeft]: https://github.com/hasu/notdeft
[org-download]: https://github.com/abo-abo/org-download
[mathpix-el]: https://github.com/jethrokuan/mathpix.el
[org-noter]: https://github.com/weirdNox/org-noter
[interleave]: https://github.com/rudolfochrist/interleave
[org-ref]: https://github.com/jkitchin/org-ref
[org-fc]: https://github.com/l3kn/org-fc/
[org-drill]: https://orgmode.org/worg/org-contrib/org-drill.html
[pamparam]: https://github.com/abo-abo/pamparam

15
doc/htmlxref.cnf Normal file
View File

@ -0,0 +1,15 @@
# https://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Configuration.html
EMACS = https://www.gnu.org/software/emacs/manual
auth mono ${EMACS}/html_mono/auth.html
auth node ${EMACS}/html_node/auth/
ediff mono ${EMACS}/html_mono/ediff.html
ediff node ${EMACS}/html_node/ediff/
elisp mono ${EMACS}/html_mono/elisp.html
elisp node ${EMACS}/html_node/elisp/
emacs mono ${EMACS}/html_mono/emacs.html
emacs node ${EMACS}/html_node/emacs/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
doc/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

572
doc/img/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 42 KiB

BIN
doc/img/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

168
doc/index.html Normal file
View File

@ -0,0 +1,168 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="An Effortless PKM System." />
<meta name="author" content="Org-roam Contributors" />
<title>Org-roam</title>
<link rel="stylesheet" href="https://unpkg.com/wingcss" />
<link rel="stylesheet" type="text/css" href="./css/styles.css" />
<script src="https://code.iconify.design/1/1.0.6/iconify.min.js"></script>
</head>
<body>
<section class="hero container center text-center">
<div>
<img src="./img/logo.png" alt="Org-roam Logo" height="200" />
<h3>Org-roam</h3>
<h5>A plain-text personal knowledge management system.</h5>
</div>
</section>
<section class="container center">
<div>
<img src="./img/screenshot.png" alt="screenshot" />
</div>
</section>
<section id="features" class="container center">
<div>
<h3 class="header">FEATURES</h3>
<div class="row">
<div class="col">
<h5 class="left">
<iconify-icon data-icon="fxemoji:lock"></iconify-icon> &nbsp;
Private and Secure
</h5>
<p class="content">
Edit your personal wiki completely offline, entirely in your
control. Encrypt your notes with GPG. Take lasting notes in
plain-text.
</p>
</div>
<div class="col">
<h5 class="left">
<iconify-icon data-icon="flat-color-icons:link"></iconify-icon>
&nbsp; Make Connections
</h5>
<p class="content">
Connect notes and thoughts together with ease using backlinks.
Discover surprising and previously unseen connections in your
notes with the built-in graph visualization.
</p>
</div>
</div>
<div class="row">
<div class="col">
<h5 class="left">
<iconify-icon data-icon="twemoji:puzzle-piece"></iconify-icon>
&nbsp; Extensible and Powerful
</h5>
<p class="content">
Leverage Emacs' fantastic text-editing interface, and the mature
Emacs and Org-mode ecosystem of packages.
</p>
</div>
<div class="col">
<h5 class="left">
<iconify-icon data-icon="logos:git-icon"></iconify-icon> &nbsp;
Free and Open Source
</h5>
<p class="content">
Org-roam is licensed under the GNU General Public License version
3 or later. You are free to extend its functionality and
contribute back. Find
us <a href="https://github.com/org-roam/org-roam">here</a>.
</p>
</div>
</div>
</div>
</section>
<section id="links" class="container">
<div>
<h3 class="header">LINKS</h3> New to Emacs and Org-mode, and trying to
find your way around? Org-roam has an inclusive community of users
passionate about Personal Knowledge Management -- we're happy to help!
You can find us on Discourse and Slack.
<ul>
<li>Read our documentation within Emacs, or on the <a href="https://www.orgroam.com/manual.html">Online Manual</a></li>
<li>Participate in our forum discussions on <a href="https://org-roam.discourse.group">Discourse</a></li>
<li>Chat with us on <a href="https://join.slack.com/t/orgroam/shared_invite/zt-wuoize1z-x3UyQnQ0WHF0RhuEQ2NLnQ">Slack</a></li>
</ul>
</div>
</section>
<section id="footer" class="row container">
<div class="col">
<div class="row">
<h5 class="header">Ecosystem</h5>
</div>
<div class="row">
<a
class="content footer-links"
href="https://github.com/org-roam/org-roam-bibtex"
>org-roam-bibtex</a
>
</div>
<div class="row">
<a
class="content footer-links"
href="https://github.com/org-roam/org-roam-ui"
>org-roam-ui</a
>
</div>
</div>
<div class="col">
<div class="row">
<h5 class="header">Resources</h5>
</div>
<div class="row">
<a
class="content footer-links"
href="https://github.com/org-roam/org-roam/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc"
>Open Issues</a
>
</div>
<div class="row">
<a
class="content footer-links"
href="https://github.com/org-roam/org-roam/releases"
>Releases</a
>
</div>
</div>
<div class="col">
<div class="row">
<h5 class="header">Connect</h5>
</div>
<div class="row">
<a
class="content footer-links"
href="https://join.slack.com/t/orgroam/shared_invite/zt-wuoize1z-x3UyQnQ0WHF0RhuEQ2NLnQ"
>Slack</a
>
</div>
<div class="row">
<a
class="content footer-links"
href="https://org-roam.discourse.group/"
>Discourse</a
>
</div>
</div>
</section>
</body>
</html>

View File

@ -1,62 +0,0 @@
![org-roam][org-roam-intro-image]
## What is Org-roam?
Org-roam is a [Roam][roamresearch] replica built around the
all-powerful [Org-mode][org].
Org-roam is a solution for effortless non-hierarchical note-taking
with Org-mode. With Org-roam, notes flow naturally, making note-taking
fun and easy. Org-roam should also work as a plug-and-play solution
for anyone already using Org-mode for their personal wiki.
To understand more about Roam, a collection of links are available in
[the appendix](notetaking_workflow.md).
Org-roam aims to implement the core features of Roam, leveraging the
mature ecosystem around Org-mode where possible. Eventually, we hope
to further introduce features enabled by the Emacs ecosystem.
## Why use Org-roam?
##### Private and Secure
Edit your personal wiki completely offline, entirely in your control.
Encrypt your notes with GPG.
##### Longevity
Unlike web solutions like Roam research, the notes are first and
foremost plain Org-mode files -- Org-roam simply builds up an
auxilliary database to give the personal wiki superpowers. Having your
notes in plain-text is crucial for the longevity of your wiki. Never
have to worry about proprietary web solutions being taken down. Edit
your plain-text notes in notepad if all other editors cease to exist.
##### Free and Open-source
Org-roam is free and open-source, which means that if you feel unhappy
with any part of Org-roam, you may choose to extend Org-roam, or open
a PR.
##### Leverage the Org-mode Ecosystem
Over the years, Emacs and Org-mode has developed into a mature system
for plain-text organization. Building upon Org-mode already puts
Org-roam light-years ahead of many other solutions.
Emacs is also a fantastic interface for editing text, and we can
inherit many of the powerful text-navigation and editing packages
available to Emacs.
There are several packages that are similar to Org-roam, see the
[Comparison](comparison.md) page for a detailed comparison.
## Project Status
As of March 2020, most of the core functionality and interfaces have
stabilized, and a stable release is near.
[org-roam-intro-image]: images/org-roam-intro.png
[roamresearch]: https://www.roamresearch.com/
[org]: https://orgmode.org/

View File

@ -1,195 +0,0 @@
## Basic Install and Configuration
Org-roam is now available on MELPA, so you can install it via the following
command:
```
M-x package-install RET org-roam RET
```
Alternatively, you may use package managers such as [straight][straight] or
[quelpa][quelpa] to install the package.
The recommended method of configuration is to use [use-package][use-package].
```emacs-lisp
(use-package org-roam
:hook
(after-init . org-roam-mode)
:custom
(org-roam-directory "/path/to/org-files/")
:bind (:map org-roam-mode-map
(("C-c n l" . org-roam)
("C-c n f" . org-roam-find-file)
("C-c n b" . org-roam-switch-to-buffer)
("C-c n g" . org-roam-graph))
:map org-mode-map
(("C-c n i" . org-roam-insert))))
```
Or without `use-package`:
```emacs-lisp
(require 'org-roam)
(define-key org-roam-mode-map (kbd "C-c n l") #'org-roam)
(define-key org-roam-mode-map (kbd "C-c n f") #'org-roam-find-file)
(define-key org-roam-mode-map (kbd "C-c n b") #'org-roam-switch-to-buffer)
(define-key org-roam-mode-map (kbd "C-c n g") #'org-roam-graph)
(define-key org-mode-map (kbd "C-c n i") #'org-roam-insert)
(org-roam-mode +1)
```
The [Configuration](configuration.md) page details some of the common
configuration options available.
### Completion
Link auto-completion is offered via
[company-org-roam](https://github.com/jethrokuan/company-org-roam/), refer to
the documentation there for further details.
## Spacemacs
If you are using Spacemacs, install org-roam by creating a simple layer that
wraps Org-roam. Paste the following into a new file
`~/.emacs.d/private/org-roam/packages.el`.
```emacs-lisp
(defconst org-roam-packages
'(org-roam))
(defun org-roam/init-org-roam ()
(use-package org-roam
:hook
(after-init . org-roam-mode)
:custom
(org-roam-directory "/path/to/org-files/")
:init
(progn
(spacemacs/declare-prefix "ar" "org-roam")
(spacemacs/set-leader-keys
"arl" 'org-roam
"art" 'org-roam-dailies-today
"arf" 'org-roam-find-file
"arg" 'org-roam-graph)
(spacemacs/declare-prefix-for-mode 'org-mode "mr" "org-roam")
(spacemacs/set-leader-keys-for-major-mode 'org-mode
"rl" 'org-roam
"rt" 'org-roam-dailies-today
"rb" 'org-roam-switch-to-buffer
"rf" 'org-roam-find-file
"ri" 'org-roam-insert
"rg" 'org-roam-graph))))
```
Next, append `org-roam` to the `dotspacemacs-configuration-layers`
list in your `.spacemacs` configuration file. Reload (`SPC f e R`) or
restart Emacs to load `org-roam`. It's functions are available under
the prefix `SPC a r` and `, r` when visiting an org-mode buffer.
If you also have the ranger layer installed, the prefix 'ar' conflict
with that of the ranger layer. You might want to change it to 'aor'
(also change the 'ar' to 'aor' in the other key-binding declarations)
## Doom Emacs
[Doom Emacs][doom] has a `+roam` flag on its `org` module for easy
installation and configuration. Simply add the flag to the `org` section
of your `~/.doom.d/init.el` and run `~/.emacs.d/bin/doom sync`.
[use-package]: https://github.com/jwiegley/use-package
[straight]: https://github.com/raxod502/straight.el
[quelpa]: https://github.com/quelpa/quelpa
[doom]: https://github.com/hlissner/doom-emacs
[doom-getting-started]: https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org#configuring-packages
## Windows
On Windows, if you follow the installation instructions above, you will likely get the error message: **"No EmacSQL SQLite binary available, aborting"**, and `org-roam` won't start properly.
You need to do some additional steps to get `org-roam` to work.
Essentially, you will need to have a binary file for `emacsql-sqlite` so that your Emacs can work with `sqlite` database -- `org-roam` uses it to track backlinks. The following options have been reported to work by Windows users in the community.
Option 1. **Windows Subsystem for Linux (WSL)**
: This option lets you use Linux on your Windows machine. It's Linux, so you don't need to do anything specific for Windows.
Option 2. **mingw-x64**
: Use mingw-x64. You would spend a bit of time to download it, and get familiar with how it works. You should be able to use Linux tools within your Windows [more contribution welcome].
Option 3. **scoop**
: Use [scoop](https://scoop.sh/) to install a couple of software tools (make and gcc) and manually compile a binary (`.exe`) file yourself. Find a short step-by-step guide below.
Option 4. **emacsql-sqlite3**
: Use another Emacs package called [`emacsql-sqlite3`](https://github.com/cireu/emacsql-sqlite3). You can download an [official binary](https://sqlite.org/download.html) for `sqlite3`. `emacsql-sqlite3` lets you use it. For this option to work, you need to adjust the `org-roam` source code, and get your modified version to work in your Emacs environment. Find a suggestion below.
### scoop
**Step 1.** In PowerShell, install `scoop` ([instruction here](https://scoop.sh/)).
```powershell
iwr -useb get.scoop.sh | iex
```
**Step 2.** In PowerShell, install `make` and `gcc` via scoop
```powershell
scoop install make gcc
```
**Step 3.** In Emacs, install the `emacsql-sqlite` package for your Emacs if it is not done yet.
**Step 4.** In PowerShell, move to the directory where `emacsql.c` is stored.
With MELPA, it is likely to be under your ELPA folder:
```
~\AppData\Roaming\.emacs.d\elpa\emacsql-sqlite-20190727.1710\sqlite
```
With Doom Emacs, it should be under your `.emacs\.local`:
```
~\.emacs.d\.local\straight\build\emacsql-sqlite\sqlite
```
Check the files via `dir` command. You should see these files:
```powershell
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 22/03/2020 12:10 PM 5170 emacsql.c
-a---- 22/03/2020 12:10 PM 439 Makefile
-a---- 22/03/2020 12:10 PM 7516138 sqlite3.c
-a---- 22/03/2020 12:10 PM 526684 sqlite3.h
```
**Step 5.** Compile the `.exe` file with `make`
```powershell
make emacsql-sqlite CC=gcc LDLIBS=
```
You will see the process triggered with lots of text automatically scrolling down; it may take a couple of minutes for compilation to finish.
Once compilation is done, check that `emacsql-sqlite.exe` has been added to the directory.
**Step 6.** Relaunch Emacs, use `org-roam`
When you start `org-roam` (e.g. via `org-roam-mode`), now you should no longer see the "No EmacSQL SQLite binary available, aborting" error. You are good to go.
### emacsql-sqlite3
1. In Emacs, install the `emacsql-sqlite3` package
2. Using your text editor, etc. modify `org-roam-db.el`:
1. Replace `(require 'emacsql-sqlite)` with `(require 'emacsql-sqlite3)`
2. Comment/deactivate the complete `(defconst org-roam-db--sqlite-available-p ... )`
3. In `(defun org-roam-db ...`, replace `emacsql-sqlite`
with `emacsql-sqlite3`
3. If you compile `.el` files, ensure to replace `org-roam-db.elc` with the new source you modified.

View File

@ -1,24 +0,0 @@
## Recommended Books
- [How to Take Smart Notes][1]
## Articles
- [How to Take Smart Notes in Org-mode - Jethro Kuan][7]
- [The Zettelkasten Method - LessWrong 2.0][3]
- [Building a second brain in Roam][4]
- [Roam: Why I Love It and How I Use It][5]
- [Adam Keesling's Twitter Thread][6]
## Threads
- [Ask HN: How to Take Good Notes][8]
## What to Do With Your Notes
- [How to Use Roam to Outline a New Article in Under 20 Minutes][2]
[1]: https://www.goodreads.com/book/show/34507927-how-to-take-smart-notes?ac=1&from_search=true&qid=6L8iEE1FIA&rank=1
[2]: https://www.youtube.com/watch?v=RvWic15iXjk
[3]: https://www.lesswrong.com/posts/NfdHG6oHBJ8Qxc26s/the-zettelkasten-method-1
[4]: https://reddit.com/r/RoamResearch/comments/eho7de/building_a_second_brain_in_roamand_why_you_might
[5]: https://www.nateliason.com/blog/roam
[6]: https://twitter.com/adam_keesling/status/1196864424725774336?s=20
[7]: https://blog.jethro.dev/posts/how_to_take_smart_notes_org/
[8]: https://news.ycombinator.com/item?id=22473209

1804
doc/org-roam.org Normal file

File diff suppressed because it is too large Load Diff

2425
doc/org-roam.texi Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
While exporting your documents to another format such as HTML -- whether using Org's in-built export or ox-hugo -- you can add a backlinks section which would display the backlinks to the current file. This is done via org-export's preprocessing hooks. See more at [Advanced Export Configuration (The Org Manual)](https://orgmode.org/manual/Advanced-Export-Configuration.html#Advanced-Export-Configuration).
Following are two different configs that might be suitable for different use-cases. Add one of these snippets in your Emacs init file.
### Only Backlinks
This will display only the backlinks and not the contents.
```emacs-lisp
(defun my/org-roam--backlinks-list (file)
(if (org-roam--org-roam-file-p file)
(--reduce-from
(concat acc (format "- [[file:%s][%s]]\n"
(file-relative-name (car it) org-roam-directory)
(org-roam--get-title-or-slug (car it))))
"" (org-roam-db-query [:select [from] :from links :where (= to $s1)] file))
""))
(defun my/org-export-preprocessor (backend)
(let ((links (my/org-roam--backlinks-list (buffer-file-name))))
(unless (string= links "")
(save-excursion
(goto-char (point-max))
(insert (concat "\n* Backlinks\n") links)))))
(add-hook 'org-export-before-processing-hook 'my/org-export-preprocessor)
```
### Backlinks and Contents
This would insert both backlinks and the contents, just like the org-roam buffer. This might be especially useful if you host a web version of your personal knowledgebase and want to browse the files along with the backlinks from mobile devices.
```emacs-lisp
(defun my/org-roam--backlinks-list-with-content (file)
(with-temp-buffer
(if-let* ((backlinks (org-roam--get-backlinks file))
(grouped-backlinks (--group-by (nth 0 it) backlinks)))
(progn
(insert (format "\n\n* %d Backlinks\n"
(length backlinks)))
(dolist (group grouped-backlinks)
(let ((file-from (car group))
(bls (cdr group)))
(insert (format "** [[file:%s][%s]]\n"
file-from
(org-roam--get-title-or-slug file-from)))
(dolist (backlink bls)
(pcase-let ((`(,file-from _ ,props) backlink))
(insert (s-trim (s-replace "\n" " " (plist-get props :content))))
(insert "\n\n")))))))
(buffer-string)))
(defun my/org-export-preprocessor (backend)
(let ((links (my/org-roam--backlinks-list-with-content (buffer-file-name))))
(unless (string= links "")
(save-excursion
(goto-char (point-max))
(insert (concat "\n* Backlinks\n") links)))))
(add-hook 'org-export-before-processing-hook 'my/org-export-preprocessor)
```

View File

@ -1,2 +0,0 @@
mkdocs-material==4.6.2
pymdown-extensions==6.3

View File

@ -1,161 +0,0 @@
## What is Roam protocol?
Org-roam extending `org-protocol` with 2 protocols: the `roam-file`
and `roam-ref` protocol.
## The `roam-file` protocol
This is a simple protocol that opens the path specified by the `file`
key (e.g. `org-protocol://roam-file?file=/tmp/file.org`). This is used
in the generated graph.
## The `roam-ref` Protocol
This protocol finds or creates a new note with a given `ROAM_KEY` (see
[Anatomy](anatomy.md)):
![roam-ref](images/roam-ref.gif)
To use this, create a Firefox bookmarklet as follows:
```javascript
javascript:location.href =
'org-protocol:/roam-ref?template=r&ref='
+ encodeURIComponent(location.href)
+ '&title='
+ encodeURIComponent(document.title)
```
where `template` is the template key for a template in
`org-roam-capture-ref-templates`. More documentation on the templating
system can be found [here](templating.md).
These templates should contain a `#+ROAM_KEY: ${ref}` in it.
## Setting up Org-roam protocol
To enable org-roam's protocol extensions, you have to add the
following to your init file:
```emacs-lisp
(require 'org-roam-protocol)
```
The instructions for setting up `org-protocol` can be found
[here][org-protocol-inst], but they are reproduced below.
We will also need to create a desktop application for `emacsclient`.
The instructions for various platforms are shown below:
## Linux
Create a desktop application. I place mine in
`~/.local/share/applications/org-protocol.desktop`:
```
[Desktop Entry]
Name=Org-Protocol
Exec=emacsclient %u
Icon=emacs-icon
Type=Application
Terminal=false
MimeType=x-scheme-handler/org-protocol
```
Associate `org-protocol://` links with the desktop application by
running in your shell:
```bash
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
```
To disable the "confirm" prompt in Chrome, you can also make Chrome
show a checkbox to tick, so that the `Org-Protocol Client` app will be used
without confirmation. To do this, run in a shell:
```sh
sudo mkdir -p /etc/opt/chrome/policies/managed/
sudo tee /etc/opt/chrome/policies/managed/external_protocol_dialog.json >/dev/null <<'EOF'
{
"ExternalProtocolDialogShowAlwaysOpenCheckbox": true
}
EOF
sudo chmod 644 /etc/opt/chrome/policies/managed/external_protocol_dialog.json
```
and then restart Chrome (for example, by navigating to <chrome://restart>) to
make the new policy take effect.
See [here](https://www.chromium.org/administrators/linux-quick-start)
for more info on the `/etc/opt/chrome/policies/managed` directory and
[here](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExternalProtocolDialogShowAlwaysOpenCheckbox)
for information on the `ExternalProtocolDialogShowAlwaysOpenCheckbox`
policy.
## Mac OS
One solution is to use
[Platypus](https://github.com/sveinbjornt/Platypus). Here are the
instructions for setting up with Platypus and Chrome:
1. Install and launch Platypus (with [Homebrew](https://brew.sh/)):
```sh
brew cask install platypus
```
2. Create a script `launch_emacs.sh`:
```
#!/usr/bin/env bash
/usr/local/bin/emacsclient --no-wait $1
```
3. Create a Platypus app with the following settings:
```
| Setting | Value |
|--------------------------------+---------------------------|
| App Name | "OrgProtocol" |
| Script Type | "env" · "/usr/bin/env" |
| Script Path | "path/to/launch-emacs.sh" |
| Interface | None |
| Accept dropped items | true |
| Remain running after execution | false |
```
Inside `Settings`:
```
| Setting | Value |
|--------------------------------+----------------|
| Accept dropped files | true |
| Register as URI scheme handler | true |
| Protocol | "org-protocol" |
```
To disable the "confirm" prompt in Chrome, you can also make Chrome
show a checkbox to tick, so that the `OrgProtocol` app will be used
without confirmation. To do this, run in a shell:
```sh
defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -bool true
```
##### Note for Emacs Mac Port
If you're using [Emacs Mac Port](https://github.com/railwaycat/homebrew-emacsmacport), it
registered its `Emacs.app` as the default handler for the URL scheme
`org-protocol`. We have to make our `OrgProtocol.app` the default
handler instead (replace `org.yourusername.OrgProtocol` with your app
identifier):
```
$ defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers -array-add \
'{"LSHandlerPreferredVersions" = { "LSHandlerRoleAll" = "-"; }; LSHandlerRoleAll = "org.yourusername.OrgProtocol"; LSHandlerURLScheme = "org-protocol";}'
```
Then restart your computer.
[org-protocol-inst]: https://orgmode.org/worg/org-contrib/org-protocol.html

View File

@ -1,119 +0,0 @@
Rather than creating blank files on `org-roam-insert` and
`org-roam-find-file`, it is may be desirable to prefill the file with
content. This may include:
- Time of creation
- File it was created from
- Clipboard content
- Any other data you may want to input manually
This requires a complex template insertion system, but fortunately,
Org ships with a powerful one: `org-capture`. However, org-capture was
not designed for such use. Org-roam abuses `org-capture` to some
extent, extending its syntax. To first understand how org-roam's
templating system works, it may be useful to look into org-capture.
## Org-roam Templates
The org-roam capture template extends org-capture's template with 2
additional properties:
1. `:file-name`: This is the file name template used when a new note
is created.
2. `:head`: This is the template that is inserted on initial note
creation.
### Org-roam Template Expansion
Org-roam's template definitions also extend org-capture's template
syntax, to allow prefilling of strings. In many scenarios,
`org-roam--capture` is passed a mapping between variables and strings.
For example, during `org-roam-insert`, a title is prompted for. If the
title doesn't already exist, we would like to create a new file,
without prompting for the title again.
Variables passed are expanded with the `${var}` syntax. For example,
during `org-roam-insert`, `${title}` is prefilled for expansion. Any
variables that do not contain strings, are prompted for values using
`completing-read`.
After doing this expansion, the org-capture's template expansion
system is used to fill up the rest of the template. You may read up
more on this on [org-capture's documentation
page](https://orgmode.org/manual/Template-expansion.html#Template-expansion).
For example, take the template: `"%<%Y%m%d%H%M%S>-${title}"`, with the title
`"Foo"`. The template is first expanded into `%<%Y%m%d%H%M%S>-Foo`. Then
org-capture expands `%<%Y%m%d%H%M%S>` with timestamp: e.g.
`20200213032037-Foo`.
All of the flexibility afforded by emacs and org-mode are
available. For example, if you want to encode a UTC timestamp in the
filename, you can take advantage of org-mode's `%(EXP)` template
expansion to call `format-time-string` directly to provide its third
argument to specify UTC.
``` emacs-lisp
("d" "default" plain (function org-roam--capture-get-point)
"%?"
:file-name "%(format-time-string \"%Y-%m-%d--%H-%M-%SZ--${slug}\" (current-time) t)"
:head "#+TITLE: ${title}\n"
:unnarrowed t)
```
Similarly, if you want to change how titles are transformed into
slugs, you can override `org-roam--title-to-slug`. For example, to use
hyphens instead of underscores:
``` emacs-lisp
(defun org-roam--title-to-slug (title)
"Convert TITLE to a filename-suitable slug. Uses hyphens rather than underscores."
(cl-flet* ((nonspacing-mark-p (char)
(eq 'Mn (get-char-code-property char 'general-category)))
(strip-nonspacing-marks (s)
(apply #'string (seq-remove #'nonspacing-mark-p
(ucs-normalize-NFD-string s))))
(cl-replace (title pair)
(replace-regexp-in-string (car pair) (cdr pair) title)))
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "-") ;; convert anything not alphanumeric
("--*" . "-") ;; remove sequential underscores
("^-" . "") ;; remove starting underscore
("-$" . ""))) ;; remove ending underscore
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
(s-downcase slug))))
```
This templating system is used throughout org-roam templates.
### Template examples
Here I walkthrough the default template, reproduced below.
```
("d" "default" plain (function org-roam--capture-get-point)
"%?"
:file-name "%<%Y%m%d%H%M%S>-${slug}"
:head "#+TITLE: ${title}\n"
:unnarrowed t)
```
1. The template has short key `"d"`. If you have only one template,
org-roam automatically chooses this template for you.
2. The template is given a description of `"default"`.
3. `plain` text is inserted. Other options include Org headings via
`entry`.
4. `(function org-roam--capture-get-point)` should not be changed.
5. `"%?"` is the template inserted on each call to `org-roam--capture`.
This template means don't insert any content, but place the cursor
here.
6. `:file-name` is the file-name template for a new note, if it
doesn't yet exist. This creates a file at path that looks like
`/path/to/org-roam-directory/20200213032037-foo.org`.
7. `:head` contains the initial template to be inserted (once only),
at the beginning of the file. Here, the title global attribute is
inserted.
8. `:unnarrowed t` tells org-capture to show the contents for the
whole file, rather than narrowing to just the entry.
Other options you may want to learn about include `:immediate-finish`.

View File

@ -1,70 +0,0 @@
Org-roam was built to support a workflow that was not possible with
vanilla Org-mode. This flow is modelled after the [Zettelkasten
method][zettelkasten], and many of [Roam Research][roam]'s workflows.
It is crucial to understand that Org-roam does not auto-magically make
note-taking better -- it's changing the note-taking workflow that
does.
To understand more about the methods and madness, the [Note-Taking
Workflow][appendix:ntw] page contains a page of useful references. The
author has also written [a post][jethro-blog-post] about how he uses
Org-roam.
## Activating Org-roam
Org-roam's entry point is the global minor `org-roam-mode`. This sets
up Emacs with several hooks, for keeping the org-roam cache
consistently updated, as well as showing the backlinks buffer.
The cache is a sqlite database named `org-roam.db`, which resides at
the root of the `org-roam-directory`. Activating `org-roam-mode`
builds the cache, which may take a while the first time, but is
generally instantaneous in subsequent runs. To build the cache
manually again, run `M-x org-roam-db-build-cache`.
## Finding a Note
`org-roam-find-file` shows the list of titles for notes that reside in
`org-roam-directory`. Selecting a note title will bring you to the
corresponding note. Entering a title of a note that does not yet exist
will create a new note with that title.
![org-roam-find-file](images/org-roam-find-file.gif)
Note that in the above image, the [ivy](https://github.com/abo-abo/swiper)
completion frontend is used. The default frontend has some usability issues with
non-matching candidates (e.g. when you want to enter a title of a new note,
there is no completion candidate), so either `ivy` or `helm` is recommended.
## Inserting Links
`org-roam-insert` insert links to existing (or new) notes. Entering a
non-existent title will also create a new note with that title.
![org-roam-insert](images/org-roam-insert-filetag.gif)
Good usage of Org-roam requires liberally linking files. This allows
the build-up of a dense knowledge graph.
## The Org-roam Buffer
The Org-roam buffer is often displayed in the side window. It shows
backlinks for the currently active Org-roam note, along with some
surrounding context.
![org-roam-buffer](images/org-roam-buffer.gif)
## Exporting the Graph
Org-roam also uses Graphviz to generate a graph, with notes as nodes,
and links between them as edges. The generated graph can be used to
navigate to the files, but this requires some additional setup
described in the [Roam Protocol][appendix:roam-protocol] page.
![org-roam-graph](images/org-roam-graph.gif)
[zettelkasten]: https://zettelkasten.de/
[appendix:ntw]: notetaking_workflow.md
[appendix:roam-protocol]: roam_protocol.md
[roam]: https://www.roamresearch.com/
[jethro-blog-post]: https://blog.jethro.dev/posts/how_to_take_smart_notes_org/

View File

@ -0,0 +1,366 @@
;;; org-roam-dailies.el --- Daily-notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
;;;
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Copyright © 2020 Leo Vivier <leo.vivier+dev@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Leo Vivier <leo.vivier+dev@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This extension provides functionality for creating daily-notes, or shortly
;; "dailies". Dailies implemented here as a unique node per unique file, where
;; each file named after certain date and stored in `org-roam-dailies-directory'.
;;
;; One can use dailies for various purposes, e.g. journaling, fleeting notes,
;; scratch notes or whatever else you can think of.
;;
;;; Code:
(require 'dash)
(require 'org-roam)
;;; Faces
(defface org-roam-dailies-calendar-note
'((t :inherit (org-link) :underline nil))
"Face for dates with a daily-note in the calendar."
:group 'org-roam-faces)
;;; Options
(defcustom org-roam-dailies-directory "daily/"
"Path to daily-notes.
This path is relative to `org-roam-directory'."
:group 'org-roam
:type 'string)
(defcustom org-roam-dailies-find-file-hook nil
"Hook that is run right after navigating to a daily-note."
:group 'org-roam
:type 'hook)
(defcustom org-roam-dailies-capture-templates
`(("d" "default" entry
"* %?"
:target (file+head "%<%Y-%m-%d>.org"
"#+title: %<%Y-%m-%d>\n")))
"Capture templates for daily-notes in Org-roam.
Note that for daily files to show up in the calendar, they have to be of format
\"org-time-string.org\".
See `org-roam-capture-templates' for the template documentation."
:group 'org-roam
:type '(repeat
(choice (list :tag "Multikey description"
(string :tag "Keys ")
(string :tag "Description"))
(list :tag "Template entry"
(string :tag "Keys ")
(string :tag "Description ")
(choice :tag "Capture Type " :value entry
(const :tag "Org entry" entry)
(const :tag "Plain list item" item)
(const :tag "Checkbox item" checkitem)
(const :tag "Plain text" plain)
(const :tag "Table line" table-line))
(choice :tag "Template "
(string)
(list :tag "File"
(const :format "" file)
(file :tag "Template file"))
(list :tag "Function"
(const :format "" function)
(function :tag "Template function")))
(plist :inline t
;; Give the most common options as checkboxes
:options (((const :format "%v " :target)
(choice :tag "Node location"
(list :tag "File"
(const :format "" file)
(string :tag " File"))
(list :tag "File & Head Content"
(const :format "" file+head)
(string :tag " File")
(string :tag " Head Content"))
(list :tag "File & Outline path"
(const :format "" file+olp)
(string :tag " File")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))
(list :tag "File & Head Content & Outline path"
(const :format "" file+head+olp)
(string :tag " File")
(string :tag " Head Content")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))))
((const :format "%v " :prepend) (const t))
((const :format "%v " :immediate-finish) (const t))
((const :format "%v " :jump-to-captured) (const t))
((const :format "%v " :empty-lines) (const 1))
((const :format "%v " :empty-lines-before) (const 1))
((const :format "%v " :empty-lines-after) (const 1))
((const :format "%v " :clock-in) (const t))
((const :format "%v " :clock-keep) (const t))
((const :format "%v " :clock-resume) (const t))
((const :format "%v " :time-prompt) (const t))
((const :format "%v " :tree-type) (const week))
((const :format "%v " :unnarrowed) (const t))
((const :format "%v " :table-line-pos) (string))
((const :format "%v " :kill-buffer) (const t))))))))
;;; Commands
;;;; Today
;;;###autoload
(defun org-roam-dailies-capture-today (&optional goto keys)
"Create an entry in the daily-note for today.
When GOTO is non-nil, go the note without creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "P")
(org-roam-dailies--capture (current-time) goto keys))
;;;###autoload
(defun org-roam-dailies-goto-today (&optional keys)
"Find the daily-note for today, creating it if necessary.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive)
(org-roam-dailies-capture-today t keys))
;;;; Tomorrow
;;;###autoload
(defun org-roam-dailies-capture-tomorrow (n &optional goto keys)
"Create an entry in the daily-note for tomorrow.
With numeric argument N, use the daily-note N days in the future.
With a `C-u' prefix or when GOTO is non-nil, go the note without
creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies--capture (time-add (* n 86400) (current-time)) goto keys))
;;;###autoload
(defun org-roam-dailies-goto-tomorrow (n &optional keys)
"Find the daily-note for tomorrow, creating it if necessary.
With numeric argument N, use the daily-note N days in the
future.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies-capture-tomorrow n t keys))
;;;; Yesterday
;;;###autoload
(defun org-roam-dailies-capture-yesterday (n &optional goto keys)
"Create an entry in the daily-note for yesteday.
With numeric argument N, use the daily-note N days in the past.
When GOTO is non-nil, go the note without creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies-capture-tomorrow (- n) goto keys))
;;;###autoload
(defun org-roam-dailies-goto-yesterday (n &optional keys)
"Find the daily-note for yesterday, creating it if necessary.
With numeric argument N, use the daily-note N days in the
future.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies-capture-tomorrow (- n) t keys))
;;;; Date
;;;###autoload
(defun org-roam-dailies-capture-date (&optional goto prefer-future keys)
"Create an entry in the daily-note for a date using the calendar.
Prefer past dates, unless PREFER-FUTURE is non-nil.
With a `C-u' prefix or when GOTO is non-nil, go the note without
creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "P")
(let ((time (let ((org-read-date-prefer-future prefer-future))
(org-read-date nil t nil (if goto
"Find daily-note: "
"Capture to daily-note: ")))))
(org-roam-dailies--capture time goto keys)))
;;;###autoload
(defun org-roam-dailies-goto-date (&optional prefer-future keys)
"Find the daily-note for a date using the calendar, creating it if necessary.
Prefer past dates, unless PREFER-FUTURE is non-nil.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive)
(org-roam-dailies-capture-date t prefer-future keys))
;;;; Navigation
(defun org-roam-dailies-goto-next-note (&optional n)
"Find next daily-note.
With numeric argument N, find note N days in the future. If N is
negative, find note N days in the past."
(interactive "p")
(unless (org-roam-dailies--daily-note-p)
(user-error "Not in a daily-note"))
(setq n (or n 1))
(let* ((dailies (org-roam-dailies--list-files))
(position
(cl-position-if (lambda (candidate)
(string= (buffer-file-name (buffer-base-buffer)) candidate))
dailies))
note)
(unless position
(user-error "Can't find current note file - have you saved it yet?"))
(pcase n
((pred (natnump))
(when (eq position (- (length dailies) 1))
(user-error "Already at newest note")))
((pred (integerp))
(when (eq position 0)
(user-error "Already at oldest note"))))
(setq note (nth (+ position n) dailies))
(find-file note)
(run-hooks 'org-roam-dailies-find-file-hook)))
(defun org-roam-dailies-goto-previous-note (&optional n)
"Find previous daily-note.
With numeric argument N, find note N days in the past. If N is
negative, find note N days in the future."
(interactive "p")
(let ((n (if n (- n) -1)))
(org-roam-dailies-goto-next-note n)))
(defun org-roam-dailies--list-files (&rest extra-files)
"List all files in `org-roam-dailies-directory'.
EXTRA-FILES can be used to append extra files to the list."
(let ((dir (expand-file-name org-roam-dailies-directory org-roam-directory))
(regexp (rx-to-string `(and "." (or ,@org-roam-file-extensions)))))
(append (--remove (let ((file (file-name-nondirectory it)))
(when (or (auto-save-file-name-p file)
(backup-file-name-p file)
(string-match "^\\." file))
it))
(directory-files-recursively dir regexp))
extra-files)))
(defun org-roam-dailies--daily-note-p (&optional file)
"Return t if FILE is an Org-roam daily-note, nil otherwise.
If FILE is not specified, use the current buffer's file-path."
(when-let ((path (expand-file-name
(or file
(buffer-file-name (buffer-base-buffer)))))
(directory (expand-file-name org-roam-dailies-directory org-roam-directory)))
(setq path (expand-file-name path))
(save-match-data
(and
(org-roam-file-p path)
(org-roam-descendant-of-p path directory)))))
;;;###autoload
(defun org-roam-dailies-find-directory ()
"Find and open `org-roam-dailies-directory'."
(interactive)
(find-file (expand-file-name org-roam-dailies-directory org-roam-directory)))
;;; Calendar integration
(defun org-roam-dailies-calendar--file-to-date (file)
"Convert FILE to date.
Return (MONTH DAY YEAR) or nil if not an Org time-string."
(ignore-errors
(cl-destructuring-bind (_ _ _ d m y _ _ _)
(org-parse-time-string
(file-name-sans-extension
(file-name-nondirectory file)))
(list m d y))))
(defun org-roam-dailies-calendar-mark-entries ()
"Mark days in the calendar for which a daily-note is present."
(when (file-exists-p (expand-file-name org-roam-dailies-directory org-roam-directory))
(dolist (date (remove nil
(mapcar #'org-roam-dailies-calendar--file-to-date
(org-roam-dailies--list-files))))
(when (calendar-date-is-visible-p date)
(calendar-mark-visible-date date 'org-roam-dailies-calendar-note)))))
(add-hook 'calendar-today-visible-hook #'org-roam-dailies-calendar-mark-entries)
(add-hook 'calendar-today-invisible-hook #'org-roam-dailies-calendar-mark-entries)
;;; Capture implementation
(add-to-list 'org-roam-capture--template-keywords :override-default-time)
(defun org-roam-dailies--capture (time &optional goto keys)
"Capture an entry in a daily-note for TIME, creating it if necessary.
When GOTO is non-nil, go the note without creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(let ((org-roam-directory (expand-file-name org-roam-dailies-directory org-roam-directory))
(org-roam-dailies-directory "./"))
(org-roam-capture- :goto (when goto '(4))
:keys keys
:node (org-roam-node-create)
:templates org-roam-dailies-capture-templates
:props (list :override-default-time time)))
(when goto (run-hooks 'org-roam-dailies-find-file-hook)))
(add-hook 'org-roam-capture-preface-hook #'org-roam-dailies--override-capture-time-h)
(defun org-roam-dailies--override-capture-time-h ()
"Override the `:default-time' with the time from `:override-default-time'."
(prog1 nil
(when (org-roam-capture--get :override-default-time)
(org-capture-put :default-time (org-roam-capture--get :override-default-time)))))
;;; Bindings
(defvar org-roam-dailies-map (make-sparse-keymap)
"Keymap for `org-roam-dailies'.")
(define-prefix-command 'org-roam-dailies-map)
(define-key org-roam-dailies-map (kbd "d") #'org-roam-dailies-goto-today)
(define-key org-roam-dailies-map (kbd "y") #'org-roam-dailies-goto-yesterday)
(define-key org-roam-dailies-map (kbd "t") #'org-roam-dailies-goto-tomorrow)
(define-key org-roam-dailies-map (kbd "n") #'org-roam-dailies-capture-today)
(define-key org-roam-dailies-map (kbd "f") #'org-roam-dailies-goto-next-note)
(define-key org-roam-dailies-map (kbd "b") #'org-roam-dailies-goto-previous-note)
(define-key org-roam-dailies-map (kbd "c") #'org-roam-dailies-goto-date)
(define-key org-roam-dailies-map (kbd "v") #'org-roam-dailies-capture-date)
(define-key org-roam-dailies-map (kbd ".") #'org-roam-dailies-find-directory)
(provide 'org-roam-dailies)
;;; org-roam-dailies.el ends here

View File

@ -0,0 +1,75 @@
;;; org-roam-export.el --- Org-roam org-export tweaks -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This package provides the necessary changes required to make org-export work out-of-the-box.
;;
;; To enable it, run:
;;
;; (require 'org-roam-export)
;;
;; The key issue Org's export-to-html functionality has is that it does not respect the ID property, which
;; Org-roam relies heavily on. This patches the necessary function in ox-html to export ID links correctly,
;; pointing to the correct place.
;;
;;; Code:
(require 'ox-html)
(defun org-roam-export--org-html--reference (datum info &optional named-only)
"Org-roam's patch for `org-html--reference' to support ID link export.
See `org-html--reference' for DATUM, INFO and NAMED-ONLY."
(let* ((type (org-element-type datum))
(user-label
(org-element-property
(pcase type
((or `headline `inlinetask) :CUSTOM_ID)
((or `radio-target `target) :value)
(_ :name))
datum))
(user-label
(or user-label
(when-let ((path (org-element-property :ID datum)))
;; see `org-html-link' for why we use "ID-"
;; (search for "ID-" in ox-html.el)
(concat "ID-" path)))))
(cond
((and user-label
(or (plist-get info :html-prefer-user-labels)
(memq type '(headline inlinetask))))
user-label)
((and named-only
(not (memq type '(headline inlinetask radio-target target)))
(not user-label))
nil)
(t
(org-export-get-reference datum info)))))
(advice-add 'org-html--reference :override #'org-roam-export--org-html--reference)
(provide 'org-roam-export)
;;; org-roam-export.el ends here

View File

@ -0,0 +1,302 @@
;;; org-roam-graph.el --- Basic graphing functionality for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This extension implements capability to build and generate graphs in Org-roam
;; with the help of Graphviz.
;;
;;; Code:
(require 'xml) ;xml-escape-string
(require 'org-roam)
;;; Options
(defcustom org-roam-graph-viewer (executable-find "firefox")
"Method to view the org-roam graph.
It may be one of the following:
- a string representing the path to the executable for viewing the graph.
- a function accepting a single argument: the graph file path.
- nil uses `view-file' to view the graph."
:type '(choice
(string :tag "Path to executable")
(function :tag "Function to display graph" eww-open-file)
(const :tag "view-file"))
:group 'org-roam)
(defcustom org-roam-graph-executable "dot"
"Path to graphing executable, or its name."
:type 'string
:group 'org-roam)
(defcustom org-roam-graph-filetype "svg"
"File type to generate when producing graphs."
:type 'string
:group 'org-roam)
(defcustom org-roam-graph-extra-config nil
"Extra options passed to graphviz.
Example:
'((\"rankdir\" . \"LR\"))"
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-edge-extra-config nil
"Extra edge options passed to graphviz.
Example:
'((\"dir\" . \"back\"))"
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-node-extra-config
'(("id" . (("style" . "bold,rounded,filled")
("fillcolor" . "#EEEEEE")
("color" . "#C9C9C9")
("fontcolor" . "#111111")))
("http" . (("style" . "rounded,filled")
("fillcolor" . "#EEEEEE")
("color" . "#C9C9C9")
("fontcolor" . "#0A97A6")))
("https" . (("style" . "rounded,filled")
("fillcolor" . "#EEEEEE")
("color" . "#C9C9C9")
("fontcolor" . "#0A97A6"))))
"Extra options for graphviz nodes."
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-link-hidden-types
'("file")
"What sort of links to hide from the Org-roam graph."
:type '(repeat string)
:group 'org-roam)
(defcustom org-roam-graph-max-title-length 100
"Maximum length of titles in graph nodes."
:type 'number
:group 'org-roam)
(defcustom org-roam-graph-shorten-titles 'truncate
"Determines how long titles appear in graph nodes.
Recognized values are the symbols `truncate' and `wrap', in which
cases the title will be truncated or wrapped, respectively, if it
is longer than `org-roam-graph-max-title-length'.
All other values including nil will have no effect."
:type '(choice
(const :tag "truncate" truncate)
(const :tag "wrap" wrap)
(const :tag "no" nil))
:group 'org-roam)
(defcustom org-roam-graph-link-builder 'org-roam-org-protocol-link-builder
"Function used to build the Org-roam graph links.
Given a node name, return a string to be used for the link fed to
the graph generation utility."
:type 'function
:group 'org-roam)
(defcustom org-roam-graph-generation-hook nil
"Functions to run after the graph has been generated.
Each function is called with two arguments: the filename
containing the graph generation tool, and the generated graph."
:type 'hook
:group 'org-roam)
(defun org-roam-org-protocol-link-builder (node)
"Default org-roam link builder. Generate an org-protocol link using NODE."
(concat "org-protocol://roam-node?node="
(url-hexify-string (org-roam-node-id node))))
;;; Interactive command
;;;###autoload
(defun org-roam-graph (&optional arg node)
"Build and possibly display a graph for NODE.
ARG may be any of the following values:
- nil show the graph.
- `\\[universal-argument]' show the graph for NODE.
- `\\[universal-argument]' N show the graph for NODE limiting nodes to N steps."
(interactive
(list current-prefix-arg
(and current-prefix-arg
(org-roam-node-at-point 'assert))))
(let ((graph (cl-typecase arg
(null (org-roam-graph--dot nil 'all-nodes))
(cons (org-roam-graph--dot (org-roam-graph--connected-component
(org-roam-node-id node) 0)))
(integer (org-roam-graph--dot (org-roam-graph--connected-component
(org-roam-node-id node) (abs arg)))))))
(org-roam-graph--build graph #'org-roam-graph--open)))
;;; Generation and Build process
(defun org-roam-graph--build (graph &optional callback)
"Generate the GRAPH, and execute CALLBACK when process exits successfully.
CALLBACK is passed the graph file as its sole argument."
(unless (stringp org-roam-graph-executable)
(user-error "`org-roam-graph-executable' is not a string"))
(unless (executable-find org-roam-graph-executable)
(user-error (concat "Cannot find executable \"%s\" to generate the graph. "
"Please adjust `org-roam-graph-executable'")
org-roam-graph-executable))
(let* ((temp-dot (make-temp-file "graph." nil ".dot" graph))
(temp-graph (make-temp-file "graph." nil (concat "." org-roam-graph-filetype))))
(org-roam-message "building graph")
(make-process
:name "*org-roam-graph*"
:buffer " *org-roam-graph*"
:command `(,org-roam-graph-executable ,temp-dot "-T" ,org-roam-graph-filetype "-o" ,temp-graph)
:sentinel (when callback
(lambda (process _event)
(when (= 0 (process-exit-status process))
(progn (funcall callback temp-graph)
(run-hook-with-args 'org-roam-graph-generation-hook temp-dot temp-graph))))))))
(defun org-roam-graph--dot (&optional edges all-nodes)
"Build the graphviz given the EDGES of the graph.
If ALL-NODES, include also nodes without edges."
(let ((org-roam-directory-temp org-roam-directory)
(nodes-table (make-hash-table :test #'equal))
(seen-nodes (list))
(edges (or edges (org-roam-db-query [:select :distinct [source dest type] :from links]))))
(pcase-dolist (`(,id ,file ,title)
(org-roam-db-query [:select [id file title] :from nodes]))
(puthash id (org-roam-node-create :file file :id id :title title) nodes-table))
(with-temp-buffer
(setq-local org-roam-directory org-roam-directory-temp)
(insert "digraph \"org-roam\" {\n")
(dolist (option org-roam-graph-extra-config)
(insert (org-roam-graph--dot-option option) ";\n"))
(insert (format " edge [%s];\n"
(mapconcat (lambda (var)
(org-roam-graph--dot-option var nil "\""))
org-roam-graph-edge-extra-config
",")))
(pcase-dolist (`(,source ,dest ,type) edges)
(unless (member type org-roam-graph-link-hidden-types)
(pcase-dolist (`(,node ,node-type) `((,source "id")
(,dest ,type)))
(unless (member node seen-nodes)
(insert (org-roam-graph--format-node
(or (gethash node nodes-table) node) node-type))
(push node seen-nodes)))
(insert (format " \"%s\" -> \"%s\";\n"
(xml-escape-string source)
(xml-escape-string dest)))))
(when all-nodes
(maphash (lambda (id node)
(unless (member id seen-nodes)
(insert (org-roam-graph--format-node node "id"))))
nodes-table))
(insert "}")
(buffer-string))))
(defun org-roam-graph--connected-component (id distance)
"Return the edges for all nodes reachable from/connected to ID.
DISTANCE is the maximum distance away from the root node."
(let* ((query
(if (= distance 0)
"
WITH RECURSIVE
links_of(source, dest) AS
(SELECT source, dest FROM links UNION
SELECT dest, source FROM links),
connected_component(source) AS
(SELECT dest FROM links_of WHERE source = $s1 UNION
SELECT dest FROM links_of JOIN connected_component USING(source))
SELECT DISTINCT source, dest, type FROM links
WHERE source IN connected_component OR dest IN connected_component;"
"
WITH RECURSIVE
links_of(source, dest) AS
(SELECT source, dest FROM links UNION
SELECT dest, source FROM links),
connected_component(source, trace) AS
(VALUES ($s1 , json_array($s1)) UNION
SELECT lo.dest, json_insert(cc.trace, '$[' || json_array_length(cc.trace) || ']', lo.dest) FROM
connected_component AS cc JOIN links_of AS lo USING(source)
WHERE (
-- Avoid cycles by only visiting each node once.
(SELECT count(*) FROM json_each(cc.trace) WHERE json_each.value == lo.dest) == 0
-- Note: BFS is cut off early here.
AND json_array_length(cc.trace) < $s2)),
nodes(source) as (SELECT DISTINCT source
FROM connected_component GROUP BY source ORDER BY min(json_array_length(trace)))
SELECT DISTINCT source, dest, type FROM links WHERE source IN nodes OR dest IN nodes;")))
(org-roam-db-query query id distance)))
(defun org-roam-graph--dot-option (option &optional wrap-key wrap-val)
"Return dot string of form KEY=VAL for OPTION cons.
If WRAP-KEY is non-nil it wraps the KEY.
If WRAP-VAL is non-nil it wraps the VAL."
(concat wrap-key (car option) wrap-key
"="
wrap-val (cdr option) wrap-val))
(defun org-roam-graph--format-node (node type)
"Return a graphviz NODE with TYPE.
Handles both Org-roam nodes, and string nodes (e.g. urls)."
(let (node-id node-properties)
(if (org-roam-node-p node)
(let* ((title (org-roam-quote-string (org-roam-node-title node)))
(shortened-title
(org-roam-quote-string
(pcase org-roam-graph-shorten-titles
(`truncate (truncate-string-to-width title org-roam-graph-max-title-length nil nil "..."))
(`wrap (org-roam-word-wrap org-roam-graph-max-title-length title))
(_ title)))))
(setq node-id (org-roam-node-id node)
node-properties `(("label" . ,shortened-title)
("URL" . ,(funcall org-roam-graph-link-builder node))
("tooltip" . ,(xml-escape-string title)))))
(setq node-id node
node-properties (append `(("label" . ,(concat type ":" node)))
(when (member type (list "http" "https"))
`(("URL" . ,(xml-escape-string (concat type ":" node))))))))
(format "\"%s\" [%s];\n"
node-id
(mapconcat (lambda (n)
(org-roam-graph--dot-option n nil "\""))
(append (cdr (assoc type org-roam-graph-node-extra-config))
node-properties) ","))))
(defun org-roam-graph--open (file)
"Open FILE using `org-roam-graph-viewer' with `view-file' as a fallback."
(pcase org-roam-graph-viewer
((pred stringp)
(if (executable-find org-roam-graph-viewer)
(condition-case err
(call-process org-roam-graph-viewer nil 0 nil file)
(error (user-error "Failed to open org-roam graph: %s" err)))
(user-error "Executable not found: \"%s\"" org-roam-graph-viewer)))
((pred functionp) (funcall org-roam-graph-viewer file))
('nil (view-file file))
(_ (signal 'wrong-type-argument `((functionp stringp null) ,org-roam-graph-viewer)))))
(provide 'org-roam-graph)
;;; org-roam-graph.el ends here

View File

@ -0,0 +1,96 @@
;;; org-roam-overlay.el --- Link overlay for [id:] links to Org-roam nodes -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This extension allows to render [[id:]] links that don't have an associated
;; descriptor with an overlay that displays the node's current title.
;;
;;; Code:
(require 'org-roam)
(defface org-roam-overlay
'((((class color) (background light))
:background "grey90" :box (:line-width -1 :color "black"))
(((class color) (background dark))
:background "grey10" :box (:line-width -1 :color "white")))
"Face for the Org-roam overlay."
:group 'org-roam-faces)
(defun org-roam-overlay--make (l r &rest props)
"Make an overlay from L to R with PROPS."
(let ((o (make-overlay l (or r l))))
(overlay-put o 'category 'org-roam)
(while props (overlay-put o (pop props) (pop props)))
o))
(defun org-roam-overlay-make-link-overlay (link)
"Create overlay for LINK."
(save-excursion
(save-match-data
(let* ((type (org-element-property :type link))
(id (org-element-property :path link))
(pos (org-element-property :end link))
(desc-p (org-element-property :contents-begin link))
node)
(when (and (string-equal type "id")
(setq node (org-roam-node-from-id id))
(not desc-p))
(org-roam-overlay--make
pos pos
'after-string (format "%s "
(propertize (org-roam-node-title node)
'face 'org-roam-overlay))))))))
(defun org-roam-overlay-enable ()
"Enable Org-roam overlays."
(org-roam-db-map-links
(list #'org-roam-overlay-make-link-overlay)))
(defun org-roam-overlay-disable ()
"Disable Org-roam overlays."
(remove-overlays nil nil 'category 'org-roam))
(defun org-roam-overlay-redisplay ()
"Redisplay Org-roam overlays."
(org-roam-overlay-disable)
(org-roam-overlay-enable))
(define-minor-mode org-roam-overlay-mode
"Overlays for Org-roam ID links.
Org-roam overlay mode is a minor mode. When enabled,
overlay displaying the node's title is displayed."
:lighter " org-roam-overlay"
(if org-roam-overlay-mode
(progn
(org-roam-overlay-enable)
(add-hook 'after-save-hook #'org-roam-overlay-redisplay nil t))
(org-roam-overlay-disable)
(remove-hook 'after-save-hook #'org-roam-overlay-redisplay t)))
(provide 'org-roam-overlay)
;;; org-roam-overlay.el ends here

View File

@ -0,0 +1,174 @@
;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This extension extends `org-protocol', adding custom Org-roam handlers to it
;; to provide the next new protocols:
;;
;; 1. "roam-node": This protocol simply opens the node given by the node ID
;; 2. "roam-ref": This protocol creates or opens the node with the given REF
;;
;; You can find detailed instructions on how to setup the protocol in the
;; documentation for Org-roam.
;;
;;; Code:
(require 'org-protocol)
(require 'ol) ;; for org-link-decode
(require 'org-roam)
;;; Options
(defcustom org-roam-protocol-store-links nil
"Whether to store links when capturing websites with `org-roam-protocol'."
:type 'boolean
:group 'org-roam)
(defcustom org-roam-capture-ref-templates
'(("r" "ref" plain "%?"
:target (file+head "${slug}.org"
"#+title: ${title}")
:unnarrowed t))
"The Org-roam templates used during a capture from the roam-ref protocol.
See `org-roam-capture-templates' for the template documentation."
:group 'org-roam
:type '(repeat
(choice (list :tag "Multikey description"
(string :tag "Keys ")
(string :tag "Description"))
(list :tag "Template entry"
(string :tag "Keys ")
(string :tag "Description ")
(choice :tag "Capture Type " :value entry
(const :tag "Org entry" entry)
(const :tag "Plain list item" item)
(const :tag "Checkbox item" checkitem)
(const :tag "Plain text" plain)
(const :tag "Table line" table-line))
(choice :tag "Template "
(string)
(list :tag "File"
(const :format "" file)
(file :tag "Template file"))
(list :tag "Function"
(const :format "" function)
(function :tag "Template function")))
(plist :inline t
;; Give the most common options as checkboxes
:options (((const :format "%v " :target)
(choice :tag "Node location"
(list :tag "File"
(const :format "" file)
(string :tag " File"))
(list :tag "File & Head Content"
(const :format "" file+head)
(string :tag " File")
(string :tag " Head Content"))
(list :tag "File & Outline path"
(const :format "" file+olp)
(string :tag " File")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))
(list :tag "File & Head Content & Outline path"
(const :format "" file+head+olp)
(string :tag " File")
(string :tag " Head Content")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))))
((const :format "%v " :prepend) (const t))
((const :format "%v " :immediate-finish) (const t))
((const :format "%v " :jump-to-captured) (const t))
((const :format "%v " :empty-lines) (const 1))
((const :format "%v " :empty-lines-before) (const 1))
((const :format "%v " :empty-lines-after) (const 1))
((const :format "%v " :clock-in) (const t))
((const :format "%v " :clock-keep) (const t))
((const :format "%v " :clock-resume) (const t))
((const :format "%v " :time-prompt) (const t))
((const :format "%v " :tree-type) (const week))
((const :format "%v " :unnarrowed) (const t))
((const :format "%v " :table-line-pos) (string))
((const :format "%v " :kill-buffer) (const t))))))))
;;; Handlers
(defun org-roam-protocol-open-ref (info)
"Process an org-protocol://roam-ref?ref= style url with INFO.
It opens or creates a note with the given ref.
javascript:location.href = \\='org-protocol://roam-ref?template=r&ref=\\='+ \\
encodeURIComponent(location.href) + \\='&title=\\=' + \\
encodeURIComponent(document.title) + \\='&body=\\=' + \\
encodeURIComponent(window.getSelection())"
(unless (plist-get info :ref)
(user-error "No ref key provided"))
(org-roam-plist-map! (lambda (k v)
(org-link-decode
(if (equal k :ref)
(org-protocol-sanitize-uri v)
v))) info)
(when org-roam-protocol-store-links
(push (list (plist-get info :ref)
(plist-get info :title)) org-stored-links))
(org-link-store-props :type (and (string-match org-link-plain-re
(plist-get info :ref))
(match-string 1 (plist-get info :ref)))
:link (plist-get info :ref)
:annotation (org-link-make-string (plist-get info :ref)
(or (plist-get info :title)
(plist-get info :ref)))
:initial (or (plist-get info :body) ""))
(raise-frame)
(let ((org-capture-link-is-already-stored t))
(org-roam-capture-
:keys (plist-get info :template)
:node (org-roam-node-create :title (plist-get info :title))
:info (list :ref (plist-get info :ref)
:body (plist-get info :body))
:templates org-roam-capture-ref-templates))
nil)
(defun org-roam-protocol-open-node (info)
"This handler simply opens the file with emacsclient.
INFO is a plist containing additional information passed by the protocol URL.
It should contain the FILE key, pointing to the path of the file to open.
Example protocol string:
org-protocol://roam-node?node=uuid"
(when-let ((node (plist-get info :node)))
(raise-frame)
(org-roam-node-visit (org-roam-populate (org-roam-node-create :id node)) nil 'force))
nil)
(push '("org-roam-ref" :protocol "roam-ref" :function org-roam-protocol-open-ref)
org-protocol-protocol-alist)
(push '("org-roam-node" :protocol "roam-node" :function org-roam-protocol-open-node)
org-protocol-protocol-alist)
(provide 'org-roam-protocol)
;;; org-roam-protocol.el ends here

11
github-eldev Executable file
View File

@ -0,0 +1,11 @@
#! /bin/sh
set -e
ELDEV_BIN_DIR=~/.local/bin
# `$GITHUB_PATH' is a magic file which contents is translated to environment variable `$PATH'.
echo "$ELDEV_BIN_DIR" >> $GITHUB_PATH
mkdir -p $ELDEV_BIN_DIR
curl -fsSL https://raw.githubusercontent.com/doublep/eldev/f111d19cda305e5e8fcb70a5675b87173041cb68/bin/eldev > $ELDEV_BIN_DIR/eldev
chmod a+x $ELDEV_BIN_DIR/eldev

1079
makem.sh

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +0,0 @@
site_name: "Org-roam"
repo_url: https://github.com/jethrokuan/org-roam/
edit_uri: edit/master/doc/
copyright: "Copyright (C) 2020 Jethro Kuan and contributors"
docs_dir: doc
extra:
social:
- type: 'slack'
link: 'https://join.slack.com/t/orgroam/shared_invite/zt-clh0g0tx-j8xg1kVxnrWdKt16gmSGPQ'
nav:
- Home: index.md
- A Tour of Org-roam: tour.md
- Installation: installation.md
- Configuration: configuration.md
- Anatomy of an Org-roam file: anatomy.md
- The Templating System: templating.md
- Ecosystem: ecosystem.md
- Similar Packages: comparison.md
- "Appendix: Note-taking Workflow": notetaking_workflow.md
- "Appendix: Roam Protocol": roam_protocol.md
- "Appendix: Org Export": org_export.md
markdown_extensions:
- admonition
- pymdownx.betterem:
smart_enable: all
- pymdownx.caret
- pymdownx.critic
- pymdownx.details
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.superfences
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
theme:
name: 'material'
palette:
primary: 'deep purple'
accent: 'deep purple'

View File

@ -1,260 +0,0 @@
;;; org-roam-buffer.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This library provides the org-roam-buffer functionality for org-roam
;;; Code:
;;;; Library Requires
(eval-when-compile (require 'subr-x))
(require 'cl-lib)
(require 'dash)
(require 's)
(defvar org-roam-directory)
(defvar org-link-frame-setup)
(defvar org-return-follows-link)
(defvar org-roam-backlinks-mode)
(defvar org-roam-last-window)
(declare-function org-roam-db--ensure-built "org-roam-db")
(declare-function org-roam--extract-ref "org-roam")
(declare-function org-roam--get-title-or-slug "org-roam")
(declare-function org-roam--get-backlinks "org-roam")
(declare-function org-roam-backlinks-mode "org-roam")
(defcustom org-roam-buffer-position 'right
"Position of `org-roam' buffer.
Valid values are
* left,
* right,
* top,
* bottom."
:type '(choice (const left)
(const right)
(const top)
(const bottom))
:group 'org-roam)
(defcustom org-roam-buffer-width 0.33
"Width of `org-roam' buffer.
Has an effect if and only if `org-roam-buffer-position' is `left' or `right'."
:type 'number
:group 'org-roam)
(defcustom org-roam-buffer-height 0.27
"Height of `org-roam' buffer.
Has an effect if and only if `org-roam-buffer-position' is `top' or `bottom'."
:type 'number
:group 'org-roam)
(defcustom org-roam-buffer "*org-roam*"
"Org-roam buffer name."
:type 'string
:group 'org-roam)
(defcustom org-roam-buffer-prepare-hook '(org-roam-buffer--insert-title
org-roam-buffer--insert-backlinks
org-roam-buffer--insert-citelinks)
"Hook run in the `org-roam-buffer' before it is displayed."
:type 'hook
:group 'org-roam)
(defcustom org-roam-buffer-no-delete-other-windows nil
"The `no-delete-other-windows' parameter of the `org-roam-buffer' window.
When non-nil, the window will not be closed when deleting other windows."
:type 'boolean
:group 'org-roam)
(defvar org-roam-buffer--current nil
"Currently displayed file in `org-roam' buffer.")
(defun org-roam-buffer--insert-title ()
"Insert the org-roam-buffer title."
(insert (propertize (org-roam--get-title-or-slug
(buffer-file-name org-roam-buffer--current))
'font-lock-face
'org-document-title)))
(defun org-roam-buffer--insert-citelinks ()
"Insert citation backlinks for the current buffer."
(if-let* ((roam-key (with-temp-buffer
(insert-buffer-substring org-roam-buffer--current)
(org-roam--extract-ref)))
(key-backlinks (org-roam--get-backlinks (s-chop-prefix "cite:" roam-key)))
(grouped-backlinks (--group-by (nth 0 it) key-backlinks)))
(progn
(insert (format "\n\n* %d Cite backlinks\n"
(length key-backlinks)))
(dolist (group grouped-backlinks)
(let ((file-from (car group))
(bls (cdr group)))
(insert (format "** [[file:%s][%s]]\n"
file-from
(org-roam--get-title-or-slug file-from)))
(dolist (backlink bls)
(pcase-let ((`(,file-from _ ,props) backlink))
(insert (propertize
(s-trim (s-replace "\n" " "
(plist-get props :content)))
'help-echo "mouse-1: visit backlinked note"
'file-from file-from
'file-from-point (plist-get props :point)))
(insert "\n\n"))))))
(insert "\n\n* No cite backlinks!")))
(defun org-roam-buffer--insert-backlinks ()
"Insert the org-roam-buffer backlinks string for the current buffer."
(if-let* ((file-path (buffer-file-name org-roam-buffer--current))
(backlinks (org-roam--get-backlinks file-path))
(grouped-backlinks (--group-by (nth 0 it) backlinks)))
(progn
(insert (format "\n\n* %d Backlinks\n"
(length backlinks)))
(dolist (group grouped-backlinks)
(let ((file-from (car group))
(bls (cdr group)))
(insert (format "** [[file:%s][%s]]\n"
file-from
(org-roam--get-title-or-slug file-from)))
(dolist (backlink bls)
(pcase-let ((`(,file-from _ ,props) backlink))
(insert (propertize
(s-trim (s-replace "\n" " "
(plist-get props :content)))
'help-echo "mouse-1: visit backlinked note"
'file-from file-from
'file-from-point (plist-get props :point)))
(insert "\n\n"))))))
(insert "\n\n* No backlinks!")))
(defun org-roam-buffer-update ()
"Update the `org-roam-buffer'."
(org-roam-db--ensure-built)
(let* ((source-org-roam-directory org-roam-directory))
(with-current-buffer org-roam-buffer
;; When dir-locals.el is used to override org-roam-directory,
;; org-roam-buffer should have a different local org-roam-directory and
;; default-directory, as relative links are relative from the overridden
;; org-roam-directory.
(setq-local org-roam-directory source-org-roam-directory)
(setq-local default-directory source-org-roam-directory)
;; Locally overwrite the file opening function to re-use the
;; last window org-roam was called from
(setq-local org-link-frame-setup
(cons '(file . org-roam--find-file) org-link-frame-setup))
(let ((inhibit-read-only t))
(erase-buffer)
(unless (eq major-mode 'org-mode)
(org-mode))
(unless org-roam-backlinks-mode
(org-roam-backlinks-mode))
(make-local-variable 'org-return-follows-link)
(setq org-return-follows-link t)
(run-hooks 'org-roam-buffer-prepare-hook)
(read-only-mode 1)))))
(cl-defun org-roam-buffer--update-maybe (&key redisplay)
"Reconstructs `org-roam-buffer'.
This needs to be quick or infrequent, because this is run at
`post-command-hook'. If REDISPLAY, force an update of
`org-roam-buffer'."
(let ((buffer (window-buffer)))
(when (and (or redisplay
(not (eq org-roam-buffer--current buffer)))
(eq 'visible (org-roam-buffer--visibility))
(buffer-local-value 'buffer-file-truename buffer))
(setq org-roam-buffer--current buffer)
(org-roam-buffer-update))))
;;;; Toggling the org-roam buffer
(define-inline org-roam-buffer--visibility ()
"Return whether the current visibility state of the org-roam buffer.
Valid states are 'visible, 'exists and 'none."
(declare (side-effect-free t))
(inline-quote
(cond
((get-buffer-window org-roam-buffer) 'visible)
((get-buffer org-roam-buffer) 'exists)
(t 'none))))
(defun org-roam-buffer--set-width (width)
"Set the width of `org-roam-buffer' to `WIDTH'."
(unless (one-window-p)
(let ((window-size-fixed)
(w (max width window-min-width)))
(cond
((> (window-width) w)
(shrink-window-horizontally (- (window-width) w)))
((< (window-width) w)
(enlarge-window-horizontally (- w (window-width))))))))
(defun org-roam-buffer--set-height (height)
"Set the height of `org-roam-buffer' to `HEIGHT'."
(unless (one-window-p)
(let ((window-size-fixed)
(h (max height window-min-height)))
(cond
((> (window-height) h)
(shrink-window (- (window-height) h)))
((< (window-height) h)
(enlarge-window (- h (window-height))))))))
(defun org-roam-buffer--get-create ()
"Set up the `org-roam' buffer at `org-roam-buffer-position'."
(let ((window (get-buffer-window))
(position
(if (member org-roam-buffer-position '(right left top bottom))
org-roam-buffer-position
(let ((text-quoting-style 'grave))
(lwarn '(org-roam) :error
"Invalid org-roam-buffer-position: %s. Defaulting to \\='right"
org-roam-buffer-position))
'right)))
(-> (get-buffer-create org-roam-buffer)
(display-buffer-in-side-window
`((side . ,position)
(window-parameters . ((no-delete-other-windows . ,org-roam-buffer-no-delete-other-windows)))))
(select-window))
(pcase position
((or 'right 'left)
(org-roam-buffer--set-width (round (* (frame-width) org-roam-buffer-width))))
((or 'top 'bottom)
(org-roam-buffer--set-height (round (* (frame-height) org-roam-buffer-height)))))
(select-window window)))
(defun org-roam-buffer-toggle-display ()
"Toggle display of the `org-roam-buffer'."
(interactive)
(setq org-roam-last-window (get-buffer-window))
(pcase (org-roam-buffer--visibility)
('visible (delete-window (get-buffer-window org-roam-buffer)))
((or 'exists 'none) (org-roam-buffer--get-create))))
(provide 'org-roam-buffer)
;;; org-roam-buffer.el ends here

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
;;; org-roam-compat.el --- Compatibility Code -*- coding: utf-8; lexical-binding: t -*-
;;; org-roam-compat.el --- Backward compatibility code -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1"))
;; This file is NOT part of GNU Emacs.
@ -27,69 +27,214 @@
;;; Commentary:
;;
;; This file contains code needed for backward compatibility with older Emacsen
;; and previous versions of org-roam.
;; This file is dedicated to maintain backward compatibility with older older
;; Emacsen and Org-roam versions.
;;
;;; Code:
;;;; Library Requires
(require 'org-roam)
;;; Backports
;; REVIEW Remove when 26.x support is dropped. This is exact the same as
;; `directory-files-recursively' from Emacs 26, but with FOLLOW-SYMLINKS
;; parameter from Emacs 27.
(defun org-roam--directory-files-recursively (dir regexp
&optional include-directories predicate
follow-symlinks)
"Return list of all files under directory DIR whose names match REGEXP.
This function works recursively. Files are returned in \"depth
first\" order, and files from each directory are sorted in
alphabetical order. Each file name appears in the returned list
in its absolute form.
By default, the returned list excludes directories, but if
optional argument INCLUDE-DIRECTORIES is non-nil, they are
included.
PREDICATE can be either nil (which means that all subdirectories
of DIR are descended into), t (which means that subdirectories that
can't be read are ignored), or a function (which is called with
the name of each subdirectory, and should return non-nil if the
subdirectory is to be descended into).
If FOLLOW-SYMLINKS is non-nil, symbolic links that point to
directories are followed. Note that this can lead to infinite
recursion."
(let* ((result nil)
(files nil)
(dir (directory-file-name dir))
;; When DIR is "/", remote file names like "/method:" could
;; also be offered. We shall suppress them.
(tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir)))))
(dolist (file (sort (file-name-all-completions "" dir)
'string<))
(unless (member file '("./" "../"))
(if (directory-name-p file)
(let* ((leaf (substring file 0 (1- (length file))))
(full-file (concat dir "/" leaf)))
;; Don't follow symlinks to other directories.
(when (and (or (not (file-symlink-p full-file))
(and (file-symlink-p full-file)
follow-symlinks))
;; Allow filtering subdirectories.
(or (eq predicate nil)
(eq predicate t)
(funcall predicate full-file)))
(let ((sub-files
(if (eq predicate t)
(condition-case nil
(org-roam--directory-files-recursively
full-file regexp include-directories
predicate follow-symlinks)
(file-error nil))
(org-roam--directory-files-recursively
full-file regexp include-directories
predicate follow-symlinks))))
(setq result (nconc result sub-files))))
(when (and include-directories
(string-match regexp leaf))
(setq result (nconc result (list full-file)))))
(when (string-match regexp file)
(push (concat dir "/" file) files)))))
(nconc result (nreverse files))))
;;; Compatibility hacks and patches
(advice-add #'org-id-add-location :around #'org-roam--handle-absent-org-id-locations-file-a)
(defun org-roam--handle-absent-org-id-locations-file-a (fn &rest args)
"Gracefully handle errors related to absence of `org-id-locations-file'.
FN is `org-id-add-location' that comes from advice and ARGS are
passed to it."
(condition-case err
(apply fn args)
;; `org-id' makes the assumption that `org-id-locations-file' will be stored in `user-emacs-directory'
;; which always exist if you have Emacs, so it uses `with-temp-file' to write to the file. However, the
;; users *do* change the path to this file and `with-temp-file' unable to create the file, if the path to
;; it consists of directories that don't exist. We'll have to handle this ourselves.
(error
(advice-remove 'org-id-add-location #'org-roam--handle-absent-org-id-locations-file-a)
(if (file-exists-p (file-truename org-id-locations-file))
(signal (car err) (cdr err))
;; Pre-allocate the hash table to avoid weird access related errors during the regeneration.
(or org-id-locations (setq org-id-locations (make-hash-table :test 'equal)))
;; If permissions allow that, try to create the user specified directory path to
;; `org-id-locations-file' ourselves.
(condition-case _err
(progn (org-roam-message (concat "`org-id-locations-file' (%s) doesn't exist. "
"Trying to regenerate it (this may take a while)...")
org-id-locations-file)
(make-directory (file-name-directory (file-truename org-id-locations-file)))
(org-roam-update-org-id-locations)
(apply fn args))
;; In case of failure (lack of permissions), we'll patch it to at least handle the current session
;; without errors.
(file-error (org-roam-message "Failed to regenerate `org-id-locations-file'")
(lwarn 'org-roam :error "
--------
WARNING: `org-id-locations-file' (%s) doesn't exist!
Org-roam is unable to create it for you.
--------
This happens when Emacs doesn't have permissions to create the
path to your `org-id-locations-file'. Org-roam will now fallback
storing the file in your current `org-roam-directory', but the
warning will keep popup with each new session.
To stop this warning from popping up, set `org-id-locations-file'
to the location you want and ensure that the path exists on your
filesystem, then run M-x `org-roam-update-org-id-locations'.
Note: While Org-roam doesn't depend on `org-id-locations-file' to
lookup IDs for the nodes that are stored in the database, it
still tries to keep it updated so IDs work across other files in
Org-mode, so the IDs used in your `org-roam-directory' would be
able to cross-reference outside of `org-roam-directory'. It also
allows to keep linking with \"id:\" links within the current
`org-roam-directory' to headings and files that are excluded from
identification (e.g. with \"ROAM_EXCLUDE\" property) as Org-roam
nodes." org-id-locations-file)
(setq org-id-locations-file
(expand-file-name ".orgids" (file-truename org-roam-directory)))
(apply fn args)))))))
;;;; Deprecated :if-new capture template keyword
(with-eval-after-load 'org-roam-capture
(add-to-list 'org-roam-capture--template-keywords :if-new)
(let ((inhibit-warning-p t)) ; REVIEW Set this to nil close to next major release
(advice-add 'org-roam-capture--get-target :around #'org-roam-capture--get-if-new-target-a)
(defun org-roam-capture--get-if-new-target-a (fn &rest args)
"Get the current capture target using deprecated :if-new property."
(if-let ((target (org-roam-capture--get :if-new)))
(prog1 target
(unless inhibit-warning-p
(lwarn 'org-roam-capture :warning
(mapconcat
#'identity
["`:if-new' property is deprecated in favor of `:target'."
"This warning will popup once per each session. In order to get"
"rid of it, rename all the references to the `:if-new' property"
"in your capture templates to `:target'."]
"\n"))
;; Don't irritate the user too much. Displaying the warning once per session should be enough.
(setq inhibit-warning-p t)))
(apply fn args)))))
;;; Obsolete aliases (remove after next major release)
;;;; Functions
(define-obsolete-function-alias 'org-roam--capture-get-point 'org-roam-capture--get-point
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-build-cache 'org-roam-db-build-cache
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-sql 'org-roam-db-query
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--get-db 'org-roam-db--get
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--db-clear 'org-roam-db--clear
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-show-graph 'org-roam-graph-show
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--maybe-update-buffer
'org-roam-buffer--update-maybe "org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--current-visibility
'org-roam-buffer--visibility "org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-update 'org-roam-buffer-update
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--set-width 'org-roam-buffer--set-width
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--set-height 'org-roam-buffer--set-height
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam--set-up-buffer 'org-roam-buffer--get-create
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-today 'org-roam-dailies-today
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-tomorrow 'org-roam-dailies-tomorrow
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-yesterday 'org-roam-dailies-yesterday
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-date 'org-roam-dailies-date
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-graph-show 'org-roam-graph
"org-roam 1.0.0")
(define-obsolete-function-alias 'org-roam-graph-build 'org-roam-graph
"org-roam 1.0.0")
(define-obsolete-function-alias
'org-roam-setup
'org-roam-db-autosync-enable "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-teardown
'org-roam-db-autosync-disable "org-roam 2.0")
;;;; Variables
(define-obsolete-variable-alias 'org-roam-graphviz-extra-options
'org-roam-graph-extra-config "org-roam 1.0.0")
(define-obsolete-variable-alias 'org-roam-grapher-extra-options
'org-roam-graph-extra-config "org-roam 1.0.0")
(make-obsolete-variable 'org-roam-graph-node-shape 'org-roam-graph-node-extra-config "org-roam 1.0.0")
(defcustom org-roam-graph-node-shape "ellipse"
"Shape of graph nodes."
:type 'string
:group 'org-roam)
(define-obsolete-variable-alias 'org-roam--db-connection
'org-roam-db--connection "org-roam 1.0.0")
(define-obsolete-variable-alias 'org-roam--current-buffer
'org-roam-buffer--current "org-roam 1.0.0")
(define-obsolete-variable-alias 'org-roam-date-title-format
'org-roam-dailies-capture-templates "org-roam 1.0.0")
(define-obsolete-variable-alias 'org-roam-date-filename-format
'org-roam-dailies-capture-templates "org-roam 1.0.0")
(define-obsolete-variable-alias
'org-roam-current-node
'org-roam-buffer-current-node "org-roam 2.0")
(define-obsolete-variable-alias
'org-roam-current-directory
'org-roam-buffer-current-directory "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-buffer-render
'org-roam-buffer-render-contents "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-buffer
'org-roam-buffer-display-dedicated "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-visit-thing
'org-roam-buffer-visit-thing "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-today
'org-roam-dailies-goto-today "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-yesterday
'org-roam-dailies-goto-yesterday "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-tomorrow
'org-roam-dailies-goto-tomorrow "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-next-note
'org-roam-dailies-goto-next-note "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-previous-note
'org-roam-dailies-goto-previous-note "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-dailies-find-date
'org-roam-dailies-goto-date "org-roam 2.0")
(define-obsolete-function-alias
'org-roam-add-property
'org-roam-property-add "org-roam 2.1")
(define-obsolete-function-alias
'org-roam-remove-property
'org-roam-property-remove "org-roam 2.1")
(define-obsolete-variable-alias
'org-roam-mode-section-functions
'org-roam-mode-sections "org-roam 2.2.0")
;;; Obsolete functions
(make-obsolete 'org-roam-get-keyword 'org-collect-keywords "org-roam 2.0")
(provide 'org-roam-compat)

View File

@ -1,119 +0,0 @@
;;; org-roam-completion.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This library provides completion for org-roam.
;;; Code:
;;;; Library Requires
(require 'cl-lib)
(require 's)
(defvar helm-pattern)
(declare-function helm "ext:helm")
(declare-function helm-make-source "ext:helm-source" (name class &rest args) t)
(defcustom org-roam-completion-system 'default
"The completion system to be used by `org-roam'."
:type '(radio
(const :tag "Default" default)
(const :tag "Ido" ido)
(const :tag "Ivy" ivy)
(const :tag "Helm" helm)
(function :tag "Custom function"))
:group 'org-roam)
(defcustom org-roam-completion-fuzzy-match nil
"Whether to fuzzy match Org-roam's completion candidates."
:type 'boolean
:group 'org-roam)
(defun org-roam-completion--helm-candidate-transformer (candidates _source)
"Transforms CANDIDATES for Helm-based completing read.
SOURCE is not used."
(let ((prefix (propertize "[?] "
'face 'helm-ff-prefix)))
(cons (propertize helm-pattern
'display (concat prefix helm-pattern))
candidates)))
(cl-defun org-roam-completion--completing-read (prompt choices &key
require-match initial-input
action)
"Present a PROMPT with CHOICES and optional INITIAL-INPUT.
If REQUIRE-MATCH is t, the user must select one of the CHOICES.
Return user choice."
(let (res)
(setq res
(cond
((eq org-roam-completion-system 'ido)
(let ((candidates (mapcar #'car choices)))
(ido-completing-read prompt candidates nil require-match initial-input)))
((eq org-roam-completion-system 'default)
(completing-read prompt choices nil require-match initial-input))
((eq org-roam-completion-system 'ivy)
(if (fboundp 'ivy-read)
(ivy-read prompt choices
:initial-input initial-input
:require-match require-match
:action (prog1 action
(setq action nil))
:caller 'org-roam--completing-read
:re-builder (if org-roam-completion-fuzzy-match 'ivy--regex-fuzzy
'regexp-quote))
(user-error "Please install ivy from \
https://github.com/abo-abo/swiper")))
((eq org-roam-completion-system 'helm)
(unless (and (fboundp 'helm)
(fboundp 'helm-make-source))
(user-error "Please install helm from \
https://github.com/emacs-helm/helm"))
(let ((source (helm-make-source prompt 'helm-source-sync
:candidates (mapcar #'car choices)
:filtered-candidate-transformer
(and (not require-match)
#'org-roam-completion--helm-candidate-transformer)
:fuzzy-match org-roam-completion-fuzzy-match))
(buf (concat "*org-roam "
(s-downcase (s-chop-suffix ":" (s-trim prompt)))
"*")))
(or (helm :sources source
:action (if action
(prog1 action
(setq action nil))
#'identity)
:prompt prompt
:input initial-input
:buffer buf)
(keyboard-quit))))))
(if action
(funcall action res)
res)))
(provide 'org-roam-completion)
;;; org-roam-completion.el ends here

View File

@ -1,81 +0,0 @@
;;; org-roam-dialies.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
;;;
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This library provides functionality for creating daily notes. This is a
;; concept borrowed from Roam Research.
;;
;;; Code:
;;; Library Requires
(require 'org-capture)
(require 'org-roam-capture)
(defvar org-roam-dailies-capture-templates
'(("d" "daily" plain (function org-roam-capture--get-point)
""
:immediate-finish t
:file-name "%<%Y-%m-%d>"
:head "#+TITLE: %<%Y-%m-%d>"))
"Capture templates for daily notes in Org-roam.")
;; Declarations
(declare-function org-roam--file-path-from-id "org-roam")
(defun org-roam-dailies--file-for-time (time)
"Create and find file for TIME."
(let ((org-roam-capture-templates org-roam-dailies-capture-templates)
(org-roam-capture--info (list (cons 'time time)))
(org-roam-capture--context 'dailies))
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h)
(org-roam--capture)))
(defun org-roam-dailies-today ()
"Create and find the daily note for today."
(interactive)
(org-roam-dailies--file-for-time (current-time)))
(defun org-roam-dailies-tomorrow (n)
"Create and find the daily note for tomorrow.
With numeric argument N, use N days in the future."
(interactive "p")
(org-roam-dailies--file-for-time (time-add (* n 86400) (current-time))))
(defun org-roam-dailies-yesterday (n)
"Create and find the file for yesterday.
With numeric argument N, use N days in the past."
(interactive "p")
(org-roam-tomorrow (- n)))
(defun org-roam-dailies-date ()
"Create the file for any date using the calendar interface."
(interactive)
(let ((time (org-read-date nil 'to-time nil "Date: ")))
(org-roam-dailies--file-for-time time)))
(provide 'org-roam-dailies)
;;; org-roam-dailies.el ends here

View File

@ -1,12 +1,12 @@
;;; org-roam-db.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
;;; org-roam-db.el --- Org-roam database API -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; Version: 2.3.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.
@ -27,53 +27,96 @@
;;; Commentary:
;;
;; This library is provides the underlying database api to org-roam
;; This module provides the underlying database API to Org-roam.
;;
;;; Code:
;;;; Library Requires
(eval-when-compile (require 'subr-x))
(require 'emacsql)
(require 'emacsql-sqlite)
(require 'org-roam-macs)
(require 'org-roam)
(require 'url-parse)
(require 'ol)
(defvar org-outline-path-cache)
(defvar org-roam-directory)
(defvar org-roam-verbose)
(declare-function org-roam--extract-titles "org-roam")
(declare-function org-roam--extract-ref "org-roam")
(declare-function org-roam--extract-links "org-roam")
(declare-function org-roam--list-files "org-roam")
(declare-function org-roam-buffer--update-maybe "org-roam-buffer")
;;;; Options
(defcustom org-roam-db-location nil
"Location of the Org-roam database.
If this is non-nil, the Org-roam sqlite database is saved here.
;;; Options
(defcustom org-roam-db-location (locate-user-emacs-file "org-roam.db")
"The path to file where the Org-roam database is stored.
It is the user's responsibility to set this correctly, especially
when used with multiple Org-roam instances."
:type 'string
:group 'org-roam)
(defconst org-roam-db--version 2)
(defconst org-roam-db--sqlite-available-p
(with-demoted-errors "Org-roam initialization: %S"
(emacsql-sqlite-ensure-binary)
t))
(defcustom org-roam-db-gc-threshold gc-cons-threshold
"The value to temporarily set the `gc-cons-threshold' threshold to.
During `org-roam-db-sync', Emacs can pause multiple times to
perform garbage collection because of the large number of
temporary structures generated (e.g. parsed ASTs).
`gc-cons-threshold' is temporarily set to
`org-roam-db-gc-threshold' during this operation, and increasing
`gc-cons-threshold' will help reduce the number of GC operations,
at the cost of memory usage. Tweaking this value may lead to
better overall performance.
For example, to reduce the number of GCs to the minimum, on
machines with large memory one may set it to
`most-positive-fixnum'."
:type 'int
:group 'org-roam)
(defcustom org-roam-db-node-include-function (lambda () t)
"A custom function to check if the point contains a valid node.
This function is called each time a node (both file and headline)
is about to be saved into the Org-roam database.
If the function returns nil, Org-roam will skip the node. This
function is useful for excluding certain nodes from the Org-roam
database."
:type 'function
:group 'org-roam)
(defcustom org-roam-db-update-on-save t
"If t, update the Org-roam database upon saving the file.
Disable this if your files are large and updating the database is
slow."
:type 'boolean
:group 'org-roam)
(defcustom org-roam-db-extra-links-elements '(node-property keyword)
"The list of Org element types to include for parsing by Org-roam.
By default, when parsing Org's AST, links within keywords and
property drawers are not parsed as links. Sometimes however, it
is desirable to parse and cache these links (e.g. hiding links in
a property drawer)."
:package-version '(org-roam . "2.2.0")
:group 'org-roam
:type '(set
(const :tag "keywords" keyword)
(const :tag "property drawers" node-property)))
(defcustom org-roam-db-extra-links-exclude-keys '((node-property . ("ROAM_REFS"))
(keyword . ("transclude")))
"Keys to ignore when mapping over links.
The car of the association list is the Org element type (e.g.
keyword). The cdr is a list of case-insensitive strings to
exclude from being treated as links.
For example, we use this to prevent self-referential links in
ROAM_REFS."
:package-version '(org-roam . "2.2.0")
:group 'org-roam
:type '(alist))
;;; Variables
(defconst org-roam-db-version 20)
(defvar org-roam-db--connection (make-hash-table :test #'equal)
"Database connection to Org-roam database.")
;;;; Core Functions
(defun org-roam-db--get ()
"Return the sqlite db file."
(interactive "P")
(or org-roam-db-location
(expand-file-name "org-roam.db" org-roam-directory)))
;;; Core Functions
(defun org-roam-db--get-connection ()
"Return the database connection, if any."
(gethash (file-truename org-roam-directory)
(gethash (expand-file-name (file-name-as-directory org-roam-directory))
org-roam-db--connection))
(defun org-roam-db ()
@ -82,76 +125,122 @@ Initializes and stores the database, and the database connection.
Performs a database upgrade when required."
(unless (and (org-roam-db--get-connection)
(emacsql-live-p (org-roam-db--get-connection)))
(let* ((db-file (org-roam-db--get))
(init-db (not (file-exists-p db-file))))
(make-directory (file-name-directory db-file) t)
(let ((conn (emacsql-sqlite db-file)))
(set-process-query-on-exit-flag (emacsql-process conn) nil)
(puthash (file-truename org-roam-directory)
(let ((init-db (not (file-exists-p org-roam-db-location))))
(make-directory (file-name-directory org-roam-db-location) t)
(let ((conn (emacsql-sqlite-open org-roam-db-location)))
(puthash (expand-file-name (file-name-as-directory org-roam-directory))
conn
org-roam-db--connection)
(when init-db
(org-roam-db--init conn))
(let* ((version (caar (emacsql conn "PRAGMA user_version")))
(version (org-roam-db--maybe-update conn version)))
(version (org-roam-db--upgrade-maybe conn version)))
(cond
((> version org-roam-db--version)
((> version org-roam-db-version)
(emacsql-close conn)
(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"))
((< version org-roam-db--version)
((< version org-roam-db-version)
(emacsql-close conn)
(error "BUG: The Org-roam database scheme changed %s"
"and there is no upgrade path")))))))
(org-roam-db--get-connection))
;;;; Entrypoint: (org-roam-db-query)
;;; Entrypoint: (org-roam-db-query)
(define-error 'emacsql-constraint "SQL constraint violation")
(defun org-roam-db-query (sql &rest args)
"Run SQL query on Org-roam database with ARGS.
SQL can be either the emacsql vector representation, or a string."
(if (stringp sql)
(emacsql (org-roam-db) (apply #'format sql args))
(apply #'emacsql (org-roam-db) sql args)))
(apply #'emacsql (org-roam-db) sql args))
;;;; Schemata
(defun org-roam-db-query! (handler sql &rest args)
"Run SQL query on Org-roam database with ARGS.
SQL can be either the emacsql vector representation, or a string.
The query is expected to be able to fail, in this situation, run HANDLER."
(condition-case err
(org-roam-db-query sql args)
(emacsql-constraint
(funcall handler err))))
;;; Schemata
(defconst org-roam-db--table-schemata
'((files
[(file :unique :primary-key)
title
(hash :not-null)
(last-modified :not-null)])
(atime :not-null)
(mtime :not-null)])
(links
[(from :not-null)
(to :not-null)
(type :not-null)
(properties :not-null)])
(nodes
([(id :not-null :primary-key)
(file :not-null)
(level :not-null)
(pos :not-null)
todo
priority
(scheduled text)
(deadline text)
title
properties
olp]
(:foreign-key [file] :references files [file] :on-delete :cascade)))
(titles
[(file :not-null)
titles])
(aliases
([(node-id :not-null)
alias]
(:foreign-key [node-id] :references nodes [id] :on-delete :cascade)))
(citations
([(node-id :not-null)
(cite-key :not-null)
(pos :not-null)
properties]
(:foreign-key [node-id] :references nodes [id] :on-delete :cascade)))
(refs
[(ref :unique :not-null)
(file :not-null)])))
([(node-id :not-null)
(ref :not-null)
(type :not-null)]
(:foreign-key [node-id] :references nodes [id] :on-delete :cascade)))
(tags
([(node-id :not-null)
tag]
(:foreign-key [node-id] :references nodes [id] :on-delete :cascade)))
(links
([(pos :not-null)
(source :not-null)
(dest :not-null)
(type :not-null)
(properties :not-null)]
(:foreign-key [source] :references nodes [id] :on-delete :cascade)))))
(defconst org-roam-db--table-indices
'((alias-node-id aliases [node-id])
(refs-node-id refs [node-id])
(tags-node-id tags [node-id])))
(defun org-roam-db--init (db)
"Initialize database DB with the correct schema and user version."
(emacsql-with-transaction db
(pcase-dolist (`(,table . ,schema) org-roam-db--table-schemata)
(pcase-dolist (`(,table ,schema) org-roam-db--table-schemata)
(emacsql db [:create-table $i1 $S2] table schema))
(emacsql db (format "PRAGMA user_version = %s" org-roam-db--version))))
(pcase-dolist (`(,index-name ,table ,columns) org-roam-db--table-indices)
(emacsql db [:create-index $i1 :on $i2 $S3] index-name table columns))
(emacsql db (format "PRAGMA user_version = %s" org-roam-db-version))))
(defun org-roam-db--maybe-update (db version)
(defun org-roam-db--upgrade-maybe (db version)
"Upgrades the database schema for DB, if VERSION is old."
(emacsql-with-transaction db
'ignore
(when (= version 1)
(progn
(warn "No good way to perform a DB upgrade, rebuilding from scratch...")
(delete-file (org-roam-db--get))
(org-roam-db-build-cache)))
version))
(if (< version org-roam-db-version)
(progn
(org-roam-message (format "Upgrading the Org-roam database from version %d to version %d"
version org-roam-db-version))
(org-roam-db-sync t))))
version)
(defun org-roam-db--close (&optional db)
"Closes the database connection for database DB.
@ -167,242 +256,473 @@ the current `org-roam-directory'."
(dolist (conn (hash-table-values org-roam-db--connection))
(org-roam-db--close conn)))
;;;; Database API
;;;;; Initialization
(defun org-roam-db--initialized-p ()
"Whether the cache has been initialized."
(and (file-exists-p (org-roam-db--get))
(> (caar (org-roam-db-query [:select (funcall count) :from titles]))
0)))
(defun org-roam-db--ensure-built ()
"Ensures that Org-roam cache is built."
(unless (org-roam-db--initialized-p)
(error "[Org-roam] your cache isn't built yet! Please run org-roam-db-build-cache")))
;;;;; Clearing
(defun org-roam-db--clear ()
"Clears all entries in the caches."
;;; Database API
;;;; Clearing
(defun org-roam-db-clear-all ()
"Clears all entries in the Org-roam cache."
(interactive)
(when (file-exists-p (org-roam-db--get))
(org-roam-db-query [:delete :from files])
(org-roam-db-query [:delete :from titles])
(org-roam-db-query [:delete :from links])
(org-roam-db-query [:delete :from refs])))
(when (file-exists-p org-roam-db-location)
(dolist (table (mapcar #'car org-roam-db--table-schemata))
(org-roam-db-query `[:delete :from ,table]))))
(defun org-roam-db-clear-file (&optional file)
"Remove any related links to the FILE.
This is equivalent to removing the node from the graph.
If FILE is nil, clear the current buffer."
(setq file (or file (buffer-file-name (buffer-base-buffer))))
(org-roam-db-query [:delete :from files
:where (= file $s1)]
file))
(defun org-roam-db--clear-file (&optional filepath)
"Remove any related links to the file at FILEPATH.
This is equivalent to removing the node from the graph."
(let* ((path (or filepath
(buffer-file-name)))
(file (file-truename path)))
(org-roam-db-query [:delete :from files
:where (= file $s1)]
file)
(org-roam-db-query [:delete :from links
:where (= from $s1)]
file)
(org-roam-db-query [:delete :from titles
:where (= file $s1)]
file)
(org-roam-db-query [:delete :from refs
:where (= file $s1)]
file)))
;;;; Updating tables
;;;;; Insertion
(defun org-roam-db--insert-links (links)
"Insert LINKS into the Org-roam cache."
(org-roam-db-query
[:insert :into links
:values $v1]
links))
(defun org-roam-db--file-title ()
"In current Org buffer, get the title.
If there is no title, return the file name relative to
`org-roam-directory'."
(org-link-display-format
(or (string-join (cdr (assoc "TITLE" (org-collect-keywords '("title")))) " ")
(file-name-sans-extension (file-relative-name
(buffer-file-name (buffer-base-buffer))
org-roam-directory)))))
(defun org-roam-db--insert-titles (file titles)
"Insert TITLES for a FILE into the Org-roam cache."
(org-roam-db-query
[:insert :into titles
:values $v1]
(list (vector file titles))))
(defun org-roam-db-insert-file (&optional hash)
"Update the files table for the current buffer.
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))
(file-title (org-roam-db--file-title))
(attr (file-attributes file))
(atime (file-attribute-access-time attr))
(mtime (file-attribute-modification-time attr))
(hash (or hash (org-roam-db--file-hash file))))
(org-roam-db-query
[:insert :into files
:values $v1]
(list (vector file file-title hash atime mtime)))))
(defun org-roam-db--insert-ref (file ref)
"Insert REF for FILE into the Org-roam cache."
(org-roam-db-query
[:insert :into refs
:values $v1]
(list (vector ref file))))
(defun org-roam-db-get-scheduled-time ()
"Return the scheduled time at point in ISO8601 format."
(when-let ((time (org-get-scheduled-time (point))))
(format-time-string "%FT%T" time)))
;;;;; Fetching
(defun org-roam-db-get-deadline-time ()
"Return the deadline time at point in ISO8601 format."
(when-let ((time (org-get-deadline-time (point))))
(format-time-string "%FT%T" time)))
(defun org-roam-db-node-p ()
"Return t if headline at point is an Org-roam node, else return nil."
(and (org-id-get)
(not (org-entry-get (point) "ROAM_EXCLUDE"))
(funcall org-roam-db-node-include-function)))
(defun org-roam-db-map-nodes (fns)
"Run FNS over all nodes in the current buffer."
(org-with-wide-buffer
(org-map-region
(lambda ()
(when (org-roam-db-node-p)
(dolist (fn fns)
(funcall fn))))
(point-min) (point-max))))
(defun org-roam-db-map-links (fns)
"Run FNS over all links in the current buffer."
(org-with-point-at 1
(while (re-search-forward org-link-any-re nil :no-error)
;; `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.
(backward-char)
(let* ((begin (match-beginning 0))
(element (org-element-context))
(type (org-element-type element))
link)
(cond
;; Links correctly recognized by Org Mode
((eq type 'link)
(setq link element))
;; Links in property drawers and lines starting with #+. Recall that, as for Org Mode v9.4.4, the
;; org-element-type of links within properties drawers is "node-property" and for lines starting with
;; #+ is "keyword".
((and (member type org-roam-db-extra-links-elements)
(not (member-ignore-case (org-element-property :key element)
(cdr (assoc type org-roam-db-extra-links-exclude-keys))))
(setq link (save-excursion
(goto-char begin)
(save-match-data (org-element-link-parser)))))))
(when link
(dolist (fn fns)
(funcall fn link)))))))
(defun org-roam-db-map-citations (info fns)
"Run FNS over all citations in the current buffer.
INFO is the org-element parsed buffer."
(org-element-map info 'citation-reference
(lambda (cite)
(dolist (fn fns)
(funcall fn cite)))))
(defun org-roam-db-insert-file-node ()
"Insert the file-level node into the Org-roam cache."
(org-with-point-at 1
(when (and (= (org-outline-level) 0)
(org-roam-db-node-p))
(when-let ((id (org-id-get)))
(let* ((file (buffer-file-name (buffer-base-buffer)))
(title (org-roam-db--file-title))
(pos (point))
(todo nil)
(priority nil)
(scheduled nil)
(deadline nil)
(level 0)
(tags org-file-tags)
(properties (org-entry-properties))
(olp nil))
(org-roam-db-query!
(lambda (err)
(lwarn 'org-roam :warning "%s for %s (%s) in %s"
(error-message-string err)
title id file))
[:insert :into nodes
:values $v1]
(vector id file level pos todo priority
scheduled deadline title properties olp))
(when tags
(org-roam-db-query
[:insert :into tags
:values $v1]
(mapcar (lambda (tag)
(vector id (substring-no-properties tag)))
tags)))
(org-roam-db-insert-aliases)
(org-roam-db-insert-refs))))))
(cl-defun org-roam-db-insert-node-data ()
"Insert node data for headline at point into the Org-roam cache."
(when-let ((id (org-id-get)))
(let* ((file (buffer-file-name (buffer-base-buffer)))
(heading-components (org-heading-components))
(pos (point))
(todo (nth 2 heading-components))
(priority (nth 3 heading-components))
(level (nth 1 heading-components))
(scheduled (org-roam-db-get-scheduled-time))
(deadline (org-roam-db-get-deadline-time))
(title (or (nth 4 heading-components)
(progn (lwarn 'org-roam :warning "Node in %s:%s:%s has no title, skipping..."
file
(line-number-at-pos)
(1+ (- (point) (line-beginning-position))))
(cl-return-from org-roam-db-insert-node-data))))
(properties (org-entry-properties))
(olp (org-get-outline-path nil 'use-cache))
(title (org-link-display-format title)))
(org-roam-db-query!
(lambda (err)
(lwarn 'org-roam :warning "%s for %s (%s) in %s"
(error-message-string err)
title id file))
[:insert :into nodes
:values $v1]
(vector id file level pos todo priority
scheduled deadline title properties olp)))))
(defun org-roam-db-insert-aliases ()
"Insert aliases for node at point into Org-roam cache."
(when-let* ((node-id (org-id-get))
(aliases (org-entry-get (point) "ROAM_ALIASES"))
(aliases (split-string-and-unquote aliases)))
(org-roam-db-query [:insert :into aliases
:values $v1]
(mapcar (lambda (alias)
(vector node-id alias))
aliases))))
(defun org-roam-db-insert-tags ()
"Insert tags for node at point into Org-roam cache."
(when-let ((node-id (org-id-get))
(tags (org-get-tags)))
(org-roam-db-query [:insert :into tags
:values $v1]
(mapcar (lambda (tag)
(vector node-id (substring-no-properties tag))) tags))))
(defun org-roam-db-insert-refs ()
"Insert refs for node at point into Org-roam cache."
(when-let* ((node-id (org-id-get))
(refs (org-entry-get (point) "ROAM_REFS"))
(refs (split-string-and-unquote refs)))
(let (rows)
(dolist (ref refs)
(save-match-data
(cond (;; @citeKey
(string-prefix-p "@" ref)
(push (vector node-id (substring ref 1) "cite") rows))
(;; [cite:@citeKey]
(string-prefix-p "[cite:" ref)
(condition-case nil
(let ((cite-obj (org-cite-parse-objects ref)))
(org-element-map cite-obj 'citation-reference
(lambda (cite)
(let ((key (org-element-property :key cite)))
(push (vector node-id key "cite") rows)))))
(error
(lwarn '(org-roam) :warning
"%s:%s\tInvalid cite %s, skipping..." (buffer-file-name) (point) ref))))
(;; https://google.com, cite:citeKey
;; 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]
(string-match org-link-any-re (org-link-encode ref '(#x20)))
(setq ref (org-link-encode ref '(#x20)))
(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)
(or (assoc link-type org-ref-cite-types)
(member link-type org-ref-cite-types)))
(dolist (key (org-roam-org-ref-path-to-keys path))
(push (vector node-id key link-type) rows))
(push (vector node-id path link-type) rows))))
(t
(lwarn '(org-roam) :warning
"%s:%s\tInvalid ref %s, skipping..." (buffer-file-name) (point) ref)))))
(when rows
(org-roam-db-query [:insert :into refs
:values $v1]
rows)))))
(defun org-roam-db-insert-link (link)
"Insert link data for LINK at current point into the Org-roam cache."
(save-excursion
(goto-char (org-element-property :begin link))
(let* ((type (org-element-property :type link))
(path (org-element-property :path link))
(option (and (string-match "::\\(.*\\)\\'" path)
(match-string 1 path)))
(path (if (not option) path
(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
(when (and source path)
(if (and (boundp 'org-ref-cite-types)
(or (assoc type org-ref-cite-types)
(member type org-ref-cite-types)))
(org-roam-db-query
[:insert :into citations
:values $v1]
(mapcar (lambda (k) (vector source k (point) properties))
(org-roam-org-ref-path-to-keys path)))
(org-roam-db-query
[:insert :into links
:values $v1]
(vector (point) source path type properties)))))))
(defun org-roam-db-insert-citation (citation)
"Insert data for CITATION at current point into the Org-roam cache."
(save-excursion
(goto-char (org-element-property :begin citation))
(let ((key (org-element-property :key citation))
(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)))))
(when (and source key)
(org-roam-db-query
[:insert :into citations
:values $v1]
(vector source key (point) properties))))))
;;;; Fetching
(defun org-roam-db--get-current-files ()
"Return a hash-table of file to the hash of its file contents."
(let* ((current-files (org-roam-db-query [:select * :from files]))
(ht (make-hash-table :test #'equal)))
(let ((current-files (org-roam-db-query [:select [file hash] :from files]))
(ht (make-hash-table :test #'equal)))
(dolist (row current-files)
(puthash (car row) (cadr row) ht))
ht))
(defun org-roam-db--get-titles (file)
"Return the titles of FILE from the cache."
(caar (org-roam-db-query [:select [titles] :from titles
:where (= file $s1)]
file
:limit 1)))
(defun org-roam-db--file-hash (file-path)
"Compute the hash of FILE-PATH."
(with-temp-buffer
(set-buffer-multibyte nil)
(insert-file-contents-literally file-path)
(secure-hash 'sha1 (current-buffer))))
(defun org-roam-db--connected-component (file)
"Return all files reachable from/connected to FILE, including the file itself.
If the file does not have any connections, nil is returned."
(let* ((query "WITH RECURSIVE
links_of(file, link) AS
(WITH roamlinks AS (SELECT * FROM links WHERE \"type\" = '\"roam\"'),
citelinks AS (SELECT * FROM links
JOIN refs ON links.\"to\" = refs.\"ref\"
AND links.\"type\" = '\"cite\"')
SELECT \"from\", \"to\" FROM roamlinks UNION
SELECT \"to\", \"from\" FROM roamlinks UNION
SELECT \"file\", \"from\" FROM citelinks UNION
SELECT \"from\", \"file\" FROM citelinks),
connected_component(file) AS
(SELECT link FROM links_of WHERE file = $s1
UNION
SELECT link FROM links_of JOIN connected_component USING(file))
SELECT * FROM connected_component;")
(files (mapcar 'car-safe (emacsql (org-roam-db) query file))))
files))
;;;; Synchronization
(defun org-roam-db-update-file (&optional file-path no-require)
"Update Org-roam cache for FILE-PATH.
(defun org-roam-db--links-with-max-distance (file max-distance)
"Return all files reachable from/connected to FILE in at most MAX-DISTANCE steps,
including the file itself. If the file does not have any connections, nil is returned."
(let* ((query "WITH RECURSIVE
links_of(file, link) AS
(WITH roamlinks AS (SELECT * FROM links WHERE \"type\" = '\"roam\"'),
citelinks AS (SELECT * FROM links
JOIN refs ON links.\"to\" = refs.\"ref\"
AND links.\"type\" = '\"cite\"')
SELECT \"from\", \"to\" FROM roamlinks UNION
SELECT \"to\", \"from\" FROM roamlinks UNION
SELECT \"file\", \"from\" FROM citelinks UNION
SELECT \"from\", \"file\" FROM citelinks),
-- Links are traversed in a breadth-first search. In order to calculate the
-- distance of nodes and to avoid following cyclic links, the visited nodes
-- are tracked in 'trace'.
connected_component(file, trace) AS
(VALUES($s1, json_array($s1))
UNION
SELECT lo.link, json_insert(cc.trace, '$[' || json_array_length(cc.trace) || ']', lo.link) FROM
connected_component AS cc JOIN links_of AS lo USING(file)
WHERE (
-- Avoid cycles by only visiting each file once.
(SELECT count(*) FROM json_each(cc.trace) WHERE json_each.value == lo.link) == 0
-- Note: BFS is cut off early here.
AND json_array_length(cc.trace) < ($s2 + 1)))
SELECT DISTINCT file, min(json_array_length(trace)) AS distance
FROM connected_component GROUP BY file ORDER BY distance;")
;; In principle the distance would be available in the second column.
(files (mapcar 'car-safe (emacsql (org-roam-db) query file max-distance))))
files))
If the file does not exist anymore, remove it from the cache.
;;;;; Updating
(defun org-roam-db--update-titles ()
"Update the title of the current buffer into the cache."
(let ((file (file-truename (buffer-file-name))))
(org-roam-db-query [:delete :from titles
:where (= file $s1)]
file)
(org-roam-db--insert-titles file (org-roam--extract-titles))))
If the file exists, update the cache with information.
(defun org-roam-db--update-refs ()
"Update the ref of the current buffer into the cache."
(let ((file (file-truename (buffer-file-name))))
(org-roam-db-query [:delete :from refs
:where (= file $s1)]
file)
(when-let ((ref (org-roam--extract-ref)))
(org-roam-db--insert-ref file ref))))
If NO-REQUIRE, don't require optional libraries. Set NO-REQUIRE
when the libraries are already required at some toplevel, e.g.
in `org-roam-db-sync'."
(setq file-path (or file-path (buffer-file-name (buffer-base-buffer))))
(let ((content-hash (org-roam-db--file-hash file-path))
(db-hash (caar (org-roam-db-query [:select hash :from files
:where (= file $s1)] file-path)))
info)
(unless (string= content-hash db-hash)
(unless no-require
(org-roam-require '(org-ref oc)))
(org-roam-with-file file-path nil
(emacsql-with-transaction (org-roam-db)
(org-with-wide-buffer
(org-set-regexps-and-options 'tags-only)
;; Org doesn't use this anymore, so we probably should stop too.
;; (org-refresh-category-properties)
(org-roam-db-clear-file)
(org-roam-db-insert-file content-hash)
(org-roam-db-insert-file-node)
(setq org-outline-path-cache nil)
(org-roam-db-map-nodes
(list #'org-roam-db-insert-node-data
#'org-roam-db-insert-aliases
#'org-roam-db-insert-tags
#'org-roam-db-insert-refs))
(setq org-outline-path-cache nil)
(setq info (org-element-parse-buffer))
(org-roam-db-map-links
(list #'org-roam-db-insert-link))
(when (fboundp 'org-cite-insert)
(require 'oc) ;ensure feature is loaded
(org-roam-db-map-citations
info
(list #'org-roam-db-insert-citation)))))))))
(defun org-roam-db--update-cache-links ()
"Update the file links of the current buffer in the cache."
(let ((file (file-truename (buffer-file-name))))
(org-roam-db-query [:delete :from links
:where (= from $s1)]
file)
(when-let ((links (org-roam--extract-links)))
(org-roam-db--insert-links links))))
(defun org-roam-db--update-file (&optional file-path)
"Update Org-roam cache for FILE-PATH."
(let (buf)
(if file-path
(setq buf (find-file-noselect file-path))
(setq buf (current-buffer)))
(with-current-buffer buf
(save-excursion
(org-roam-db--update-titles)
(org-roam-db--update-refs)
(org-roam-db--update-cache-links)
(org-roam-buffer--update-maybe :redisplay t)))))
;;;;; org-roam-db-build-cache
(defun org-roam-db-build-cache ()
"Build the cache for `org-roam-directory'."
(interactive)
;;;###autoload
(defun org-roam-db-sync (&optional force)
"Synchronize the cache state with the current Org files on-disk.
If FORCE, force a rebuild of the cache from scratch."
(interactive "P")
(org-roam-db--close) ;; Force a reconnect
(when force (delete-file org-roam-db-location))
(org-roam-db) ;; To initialize the database, no-op if already initialized
(let* ((org-roam-files (org-roam--list-files org-roam-directory))
(org-roam-require '(org-ref oc))
(let* ((gc-cons-threshold org-roam-db-gc-threshold)
(org-agenda-files nil)
(org-roam-files (org-roam-list-files))
(current-files (org-roam-db--get-current-files))
(time (current-time))
all-files all-links all-titles all-refs)
(modified-files nil))
(dolist (file org-roam-files)
(org-roam--with-temp-buffer
(insert-file-contents file)
(let ((contents-hash (secure-hash 'sha1 (current-buffer))))
(unless (string= (gethash file current-files)
contents-hash)
(org-roam-db--clear-file file)
(setq all-files
(cons (vector file contents-hash time) all-files))
(when-let (links (org-roam--extract-links file))
(setq all-links (append links all-links)))
(let ((titles (org-roam--extract-titles)))
(setq all-titles (cons (vector file titles) all-titles)))
(when-let ((ref (org-roam--extract-ref)))
(setq all-refs (cons (vector ref file) all-refs))))
(remhash file current-files))))
(dolist (file (hash-table-keys current-files))
;; These files are no longer around, remove from cache...
(org-roam-db--clear-file file))
(when all-files
(org-roam-db-query
[:insert :into files
:values $v1]
all-files))
(when all-links
(org-roam-db-query
[:insert :into links
:values $v1]
all-links))
(when all-titles
(org-roam-db-query
[:insert :into titles
:values $v1]
all-titles))
(when all-refs
(org-roam-db-query
[:insert :into refs
:values $v1]
all-refs))
(let ((stats (list :files (length all-files)
:links (length all-links)
:titles (length all-titles)
:refs (length all-refs)
:deleted (length (hash-table-keys current-files)))))
(when org-roam-verbose
(message "files: %s, links: %s, titles: %s, refs: %s, deleted: %s"
(plist-get stats :files)
(plist-get stats :links)
(plist-get stats :titles)
(plist-get stats :refs)
(plist-get stats :deleted)))
stats)))
(let ((contents-hash (org-roam-db--file-hash file)))
(unless (string= (gethash file current-files)
contents-hash)
(push file modified-files)))
(remhash file current-files))
(emacsql-with-transaction (org-roam-db)
(org-roam-dolist-with-progress (file (hash-table-keys current-files))
"Clearing removed files..."
(org-roam-db-clear-file file))
(org-roam-dolist-with-progress (file modified-files)
"Processing modified files..."
(condition-case err
(org-roam-db-update-file file 'no-require)
(error
(org-roam-db-clear-file file)
(lwarn 'org-roam :error "Failed to process %s with error %s, skipping..."
file (error-message-string err))))))))
;;;###autoload
(define-minor-mode org-roam-db-autosync-mode
"Global minor mode to keep your Org-roam session automatically synchronized.
Through the session this will continue to setup your
buffers (that are Org-roam file visiting), keep track of the
related changes, maintain cache consistency and incrementally
update the currently active database.
If you need to manually trigger resync of the currently active
database, see `org-roam-db-sync' command."
:group 'org-roam
:global t
:init-value nil
(let ((enabled org-roam-db-autosync-mode))
(cond
(enabled
(add-hook 'find-file-hook #'org-roam-db-autosync--setup-file-h)
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
(advice-add #'rename-file :after #'org-roam-db-autosync--rename-file-a)
(advice-add #'delete-file :before #'org-roam-db-autosync--delete-file-a)
(org-roam-db-sync))
(t
(remove-hook 'find-file-hook #'org-roam-db-autosync--setup-file-h)
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
(advice-remove #'rename-file #'org-roam-db-autosync--rename-file-a)
(advice-remove #'delete-file #'org-roam-db-autosync--delete-file-a)
(org-roam-db--close-all)
;; Disable local hooks for all org-roam buffers
(dolist (buf (org-roam-buffer-list))
(with-current-buffer buf
(remove-hook 'after-save-hook #'org-roam-db-autosync--try-update-on-save-h t)))))))
;;;###autoload
(defun org-roam-db-autosync-enable ()
"Activate `org-roam-db-autosync-mode'."
(org-roam-db-autosync-mode +1))
(defun org-roam-db-autosync-disable ()
"Deactivate `org-roam-db-autosync-mode'."
(org-roam-db-autosync-mode -1))
(defun org-roam-db-autosync-toggle ()
"Toggle `org-roam-db-autosync-mode' enabled/disabled."
(org-roam-db-autosync-mode 'toggle))
(defun org-roam-db-autosync--delete-file-a (file &optional _trash)
"Maintain cache consistency when file deletes.
FILE is removed from the database."
(when (and (not (auto-save-file-name-p file))
(not (backup-file-name-p file))
(org-roam-file-p file))
(org-roam-db-clear-file (expand-file-name file))))
(defun org-roam-db-autosync--rename-file-a (old-file new-file-or-dir &rest _args)
"Maintain cache consistency of file rename.
OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
(let ((new-file (if (directory-name-p new-file-or-dir)
(expand-file-name (file-name-nondirectory old-file) new-file-or-dir)
new-file-or-dir)))
(setq new-file (expand-file-name new-file))
(setq old-file (expand-file-name old-file))
(when (and (not (auto-save-file-name-p old-file))
(not (auto-save-file-name-p new-file))
(not (backup-file-name-p old-file))
(not (backup-file-name-p new-file))
(org-roam-file-p old-file))
(org-roam-db-clear-file old-file))
(when (org-roam-file-p new-file)
(org-roam-db-update-file new-file))))
(defun org-roam-db-autosync--setup-file-h ()
"Setup the current buffer if it visits an Org-roam file."
(when (org-roam-file-p) (run-hooks 'org-roam-find-file-hook)))
(add-hook 'org-roam-find-file-hook #'org-roam-db-autosync--setup-update-on-save-h)
(defun org-roam-db-autosync--setup-update-on-save-h ()
"Setup the current buffer to update the DB after saving the current file."
(add-hook 'after-save-hook #'org-roam-db-autosync--try-update-on-save-h nil t))
(defun org-roam-db-autosync--try-update-on-save-h ()
"If appropriate, update the database for the current file after saving buffer."
(when org-roam-db-update-on-save (org-roam-db-update-file)))
;;; Diagnostics
(defun org-roam-db-diagnose-node ()
"Print information about node at point."
(interactive)
(prin1 (org-roam-node-at-point)))
(provide 'org-roam-db)

View File

@ -1,268 +0,0 @@
;;; org-roam-graph.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This library provides graphing functionality for org-roam.
;;
;;; Code:
(require 'xml) ;xml-escape-string
(require 's) ;s-truncate, s-replace
(require 'org-roam-macs)
(require 'org-roam-db)
;;;; Declarations
(defvar org-roam-directory)
(declare-function org-roam--org-roam-file-p "org-roam")
(declare-function org-roam--path-to-slug "org-roam")
;;;; Options
(defcustom org-roam-graph-viewer (executable-find "firefox")
"Method to view the org-roam graph.
It may be one of the following:
- a string representing the path to the executable for viewing the graph.
- a function accepting a single argument: the graph file path.
- nil uses `view-file' to view the graph."
:type '(choice
(string :tag "Path to executable")
(function :tag "Function to display graph" eww-open-file)
(const :tag "view-file"))
:group 'org-roam)
(defcustom org-roam-graph-executable (executable-find "dot")
"Path to graphing executable."
:type 'string
:group 'org-roam)
(defcustom org-roam-graph-extra-config nil
"Extra options passed to graphviz.
Example:
'((\"rankdir\" . \"LR\"))"
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-node-extra-config nil
"Extra options for graphviz nodes.
Example:
'((\"color\" . \"skyblue\"))"
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-edge-extra-config nil
"Extra options for graphviz edges.
Example:
'((\"dir\" . \"back\"))"
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-edge-cites-extra-config '(("color" . "red"))
"Extra options for graphviz edges for citation links.
Example:
'((\"dir\" . \"back\"))"
:type '(alist)
:group 'org-roam)
(defcustom org-roam-graph-max-title-length 100
"Maximum length of titles in graph nodes."
:type 'number
:group 'org-roam)
(defcustom org-roam-graph-exclude-matcher nil
"Matcher for excluding nodes from the generated graph.
Any nodes and links for file paths matching this string is
excluded from the graph.
If value is a string, the string is the only matcher.
If value is a list, all file paths matching any of the strings
are excluded."
:type '(choice
(string :tag "Matcher")
(list :tag "Matchers"))
:group 'org-roam)
;;;; Functions
(defun org-roam-graph--expand-matcher (col &optional negate where)
"Return the exclusion regexp from `org-roam-graph-exclude-matcher'.
COL is the symbol to be matched against. if NEGATE, add :not to sql query.
set WHERE to true if WHERE query already exists."
(let ((matchers (pcase org-roam-graph-exclude-matcher
('nil nil)
((pred stringp) `(,(concat "%" org-roam-graph-exclude-matcher "%")))
((pred listp) (mapcar (lambda (m)
(concat "%" m "%"))
org-roam-graph-exclude-matcher))
(_ (error "Invalid org-roam-graph-exclude-matcher"))))
res)
(dolist (match matchers)
(if where
(push :and res)
(push :where res)
(setq where t))
(push col res)
(when negate
(push :not res))
(push :like res)
(push match res))
(nreverse res)))
(defun org-roam-graph--dot-option (option &optional wrap-key wrap-val)
"Return dot string of form KEY=VAL for OPTION cons.
If WRAP-KEY is non-nil it wraps the KEY.
If WRAP-VAL is non-nil it wraps the VAL."
(concat wrap-key (car option) wrap-key
"="
wrap-val (cdr option) wrap-val))
(defun org-roam-graph--dot (node-query)
"Build the graphviz dot string for NODE-QUERY.
The Org-roam database titles table is read, to obtain the list of titles.
The links table is then read to obtain all directed links, and formatted
into a digraph."
(org-roam-db--ensure-built)
(org-roam--with-temp-buffer
(let* ((nodes (org-roam-db-query node-query))
(edges-query
`[:with selected :as [:select [file] :from ,node-query]
:select :distinct [to from] :from links
:where (and (in to selected) (in from selected))])
(edges-cites-query
`[:with selected :as [:select [file] :from ,node-query]
:select :distinct [file from]
:from links :inner :join refs :on (and (= links:to refs:ref)
(= links:type "cite"))
:where (and (in file selected) (in from selected))])
(edges (org-roam-db-query edges-query))
(edges-cites (org-roam-db-query edges-cites-query)))
(insert "digraph \"org-roam\" {\n")
(dolist (option org-roam-graph-extra-config)
(insert (org-roam-graph--dot-option option) ";\n"))
(dolist (attribute '("node" "edge"))
(insert (format " %s [%s];\n" attribute
(mapconcat #'org-roam-graph--dot-option
(symbol-value
(intern (concat "org-roam-graph-" attribute "-extra-config")))
","))))
(dolist (node nodes)
(let* ((file (xml-escape-string (car node)))
(title (or (caadr node)
(org-roam--path-to-slug file)))
(shortened-title (s-truncate org-roam-graph-max-title-length title))
(node-properties
`(("label" . ,(s-replace "\"" "\\\"" shortened-title))
("URL" . ,(concat "org-protocol://roam-file?file=" (url-hexify-string file)))
("tooltip" . ,(xml-escape-string title)))))
(insert
(format " \"%s\" [%s];\n" file
(mapconcat (lambda (n)
(org-roam-graph--dot-option n nil "\""))
node-properties ",")))))
(dolist (edge edges)
(insert (apply #'format `(" \"%s\" -> \"%s\";\n"
,@(mapcar #'xml-escape-string edge)))))
(insert (format " edge [%s];\n"
(mapconcat #'org-roam-graph--dot-option
org-roam-graph-edge-cites-extra-config ",")))
(dolist (edge edges-cites)
(insert (apply #'format `(" \"%s\" -> \"%s\";\n"
,@(mapcar #'xml-escape-string edge)))))
(insert "}")
(buffer-string))))
(defun org-roam-graph--build (&optional node-query)
"Generate a graph showing the relations between nodes in NODE-QUERY."
(unless org-roam-graph-executable
(user-error "Can't find %s executable. Please check if it is in your path"
org-roam-graph-executable))
(let* ((node-query (or node-query
`[:select [file titles]
:from titles
,@(org-roam-graph--expand-matcher 'file t)]))
(graph (org-roam-graph--dot node-query))
(temp-dot (make-temp-file "graph." nil ".dot" graph))
(temp-graph (make-temp-file "graph." nil ".svg")))
(call-process org-roam-graph-executable nil 0 nil
temp-dot "-Tsvg" "-o" temp-graph)
temp-graph))
(defun org-roam-graph--open (file)
"Open FILE using `org-roam-graph-viewer' with `view-file' as a fallback."
(pcase org-roam-graph-viewer
((pred stringp)
(if (executable-find org-roam-graph-viewer)
(condition-case err
(call-process org-roam-graph-viewer nil 0 nil file)
((error (user-error "Failed to open org-roam graph: %s" err))))
(user-error "Executable not found: \"%s\"" org-roam-graph-viewer)))
((pred functionp) (funcall org-roam-graph-viewer file))
('nil (view-file file))
(_ (signal 'wrong-type-argument `((functionp stringp null) ,org-roam-graph-viewer)))))
(defun org-roam-graph--build-connected-component (file &optional max-distance)
"Build a graph of nodes connected to FILE.
If MAX-DISTANCE is non-nil, limit nodes to MAX-DISTANCE steps."
(let* ((file (file-truename file))
(files (or (if (and max-distance (>= max-distance 0))
(org-roam-db--links-with-max-distance file max-distance)
(org-roam-db--connected-component file))
(list file)))
(query `[:select [file titles]
:from titles
:where (in file [,@files])]))
(org-roam-graph--build query)))
;;;; Commands
;;;###autoload
(defun org-roam-graph (&optional arg file node-query)
"Build and possibly display a graph for FILE from NODE-QUERY.
If FILE is nil, default to current buffer's file name.
ARG may be any of the following values:
- nil show the graph.
- `\\[universal-argument]' show the graph for FILE.
- `\\[universal-argument]' N show the graph for FILE limiting nodes to N steps.
- `\\[universal-argument] \\[universal-argument]' build the graph.
- `\\[universal-argument]' - build the graph for FILE.
- `\\[universal-argument]' -N build the graph for FILE limiting nodes to N steps."
(interactive "P")
(let ((file (or file (buffer-file-name))))
(unless file
(user-error "Cannot build graph for nil file. Is current buffer visiting a file?"))
(unless (org-roam--org-roam-file-p file)
(user-error "\"%s\" is not an org-roam file" file))
(pcase arg
('nil (org-roam-graph--open (org-roam-graph--build node-query)))
('(4) (org-roam-graph--open (org-roam-graph--build-connected-component file)))
((pred integerp) (let ((graph (org-roam-graph--build-connected-component (buffer-file-name) (abs arg))))
(when (>= arg 0)
(org-roam-graph--open graph))))
('(16) (org-roam-graph--build node-query))
('- (org-roam-graph--build-connected-component file))
(_ (user-error "Unrecognized ARG: %s" arg)))))
(provide 'org-roam-graph)
;;; org-roam-graph.el ends here

94
org-roam-id.el Normal file
View File

@ -0,0 +1,94 @@
;;; org-roam-id.el --- ID-related utilities for Org-roam -*- lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.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 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This module provides ID-related facilities using the Org-roam database.
;;
;;; Code:
(require 'org-id)
(defun org-roam-id-at-point ()
"Return the ID at point, if any.
Recursively traverses up the headline tree to find the
first encapsulating ID."
(org-with-wide-buffer
(org-back-to-heading-or-point-min t)
(while (and (not (org-roam-db-node-p))
(not (bobp)))
(org-roam-up-heading-or-point-min))
(when (org-roam-db-node-p)
(org-id-get))))
(defun org-roam-id-find (id &optional markerp)
"Return the location of the entry with the id ID using the Org-roam db.
The return value is a cons cell (file-name . position), or nil
if there is no entry with that ID.
With optional argument MARKERP, return the position as a new marker."
(cond
((symbolp id) (setq id (symbol-name id)))
((numberp id) (setq id (number-to-string id))))
(let ((node (org-roam-populate (org-roam-node-create :id id))))
(when-let ((file (org-roam-node-file node)))
(if markerp
(let ((buffer (or (find-buffer-visiting file)
(find-file-noselect file))))
(with-current-buffer buffer
(move-marker (make-marker) (org-roam-node-point node) buffer)))
(cons (org-roam-node-file node)
(org-roam-node-point node))))))
(defalias 'org-roam-id-open 'org-id-open
"Obsolete alias - use `org-id-open' directly.")
(advice-add 'org-id-find :before-until #'org-roam-id-find)
;;;###autoload
(defun org-roam-update-org-id-locations (&rest directories)
"Scan Org-roam files to update `org-id' related state.
This is like `org-id-update-id-locations', but will automatically
use the currently bound `org-directory' and `org-roam-directory'
along with DIRECTORIES (if any), where the lookup for files in
these directories will be always recursive.
Note: Org-roam doesn't have hard dependency on
`org-id-locations-file' to lookup IDs for nodes that are stored
in the database, but it still tries to properly integrates with
`org-id'. This allows the user to cross-reference IDs outside of
the current `org-roam-directory', and also link with \"id:\"
links to headings/files within the current `org-roam-directory'
that are excluded from identification in Org-roam as
`org-roam-node's, e.g. with \"ROAM_EXCLUDE\" property."
(interactive)
(cl-loop for dir in (cons org-roam-directory directories)
for org-roam-directory = dir
nconc (org-roam-list-files) into files
finally (org-id-update-id-locations files org-roam-verbose)))
(provide 'org-roam-id)
;;; org-roam-id.el ends here

53
org-roam-log.el Normal file
View File

@ -0,0 +1,53 @@
;;; org-roam-log.el --- Integrations with Org-log -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2022-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.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 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This module provides integrations with Org-log.
;;
;;; Code:
(require 'org-roam)
(defcustom org-roam-log-setup-hook nil
"Hook run when a log for an Org-roam file is setup."
:group 'org-roam
:type 'hook)
(defun org-roam-log-p ()
"Return t if the log buffer is for an Org-roam file, nil otherwise."
(and org-log-note-marker
(org-roam-file-p (buffer-file-name (marker-buffer org-log-note-marker)))))
(defun org-roam-log--setup ()
"Run hooks in `org-roam-log-setup-hook'."
(run-hooks 'org-roam-log-setup-hook))
(add-hook 'org-roam-log-setup-hook #'org-roam--register-completion-functions-h)
(add-hook 'org-log-buffer-setup-hook #'org-roam-log--setup)
(provide 'org-roam-log)
;;; org-roam-log.el ends here

View File

@ -1,48 +0,0 @@
;;; org-roam-macs.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This library implements macros used throughout org-roam
;;
;;
;;; Code:
;;;; Library Requires
(defmacro org-roam--with-temp-buffer (&rest body)
"Execute BODY within a temp buffer.
Like `with-temp-buffer', but propagates `org-roam-directory'."
(declare (indent 0) (debug t))
(let ((current-org-roam-directory (make-symbol "current-org-roam-directory")))
`(let ((,current-org-roam-directory org-roam-directory))
(with-temp-buffer
(let ((org-roam-directory ,current-org-roam-directory))
,@body)))))
(provide 'org-roam-macs)
;;; org-roam-macs.el ends here

168
org-roam-migrate.el Normal file
View File

@ -0,0 +1,168 @@
;;; org-roam-migrate.el --- Migration utilities from v1 to v2 -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.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 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This is a special library provided for the v1 users of this package. It's
;; purpose is to ease the transition from v1 to v2, by providing migration
;; utilities to convert from v1 notes to v2 nodes.
;;
;;; Code:
(require 'org-roam)
;;; Migration wizard (v1 -> v2)
;;;###autoload
(defun org-roam-migrate-wizard ()
"Migrate all notes from to be compatible with Org-roam v2.
1. Convert all notes from v1 format to v2.
2. Rebuild the cache.
3. Replace all file links with ID links."
(interactive)
(when (yes-or-no-p "Org-roam will now convert all your notes from v1 to v2.
This will take a while. Are you sure you want to do this?")
;; Back up notes
(let ((backup-dir (expand-file-name "org-roam.bak"
(file-name-directory (directory-file-name org-roam-directory)))))
(message "Backing up files to %s" backup-dir)
(copy-directory org-roam-directory backup-dir))
;; Upgrade database to v2
(org-roam-db-sync 'force)
;; Convert v1 to v2
(dolist (f (org-roam-list-files))
(org-roam-with-file f nil
(org-roam-migrate-v1-to-v2)))
;; Rebuild cache
(org-roam-db-sync 'force)
;;Replace all file links with ID links
(dolist (f (org-roam-list-files))
(org-roam-with-file f nil
(org-roam-migrate-replace-file-links-with-id)
(save-buffer)))))
(defun org-roam-migrate-v1-to-v2 ()
"Convert the current buffer to v2 format."
;; Create file level ID
(org-with-point-at 1
(org-id-get-create))
;; Replace roam_key into properties drawer roam_ref
(when-let* ((refs (mapcan #'split-string-and-unquote
(cdar (org-collect-keywords '("roam_key"))))))
(let ((case-fold-search t))
(org-with-point-at 1
(dolist (ref refs)
(org-roam-ref-add ref))
(while (re-search-forward "^#\\+roam_key:" (point-max) t)
(beginning-of-line)
(kill-line 1)))))
;; Replace roam_alias into properties drawer roam_aliases
(when-let* ((aliases (mapcan #'split-string-and-unquote
(cdar (org-collect-keywords '("roam_alias"))))))
(dolist (alias aliases)
(org-roam-alias-add alias)))
(let ((case-fold-search t))
(org-with-point-at 1
(while (re-search-forward "^#\\+roam_alias:" (point-max) t)
(beginning-of-line)
(kill-line 1))))
;; Replace #+roam_tags into #+filetags
(org-with-point-at 1
(let* ((roam-tags (org-roam-migrate-get-prop-list "ROAM_TAGS"))
(file-tags (cl-mapcan (lambda (value)
(cl-mapcan
(lambda (k) (org-split-string k ":"))
(split-string value)))
(org-roam-migrate-get-prop-list "FILETAGS")))
(tags (append roam-tags file-tags))
(tags (seq-map (lambda (tag)
(replace-regexp-in-string
"[^[:alnum:]_@#%]"
"_"
tag)) tags))
(tags (seq-uniq tags)))
(when tags
(org-roam-migrate-prop-set "filetags" (org-make-tag-string tags))))
(let ((case-fold-search t))
(org-with-point-at 1
(while (re-search-forward "^#\\+roam_tags:" (point-max) t)
(beginning-of-line)
(kill-line 1)))))
(save-buffer))
(defun org-roam-migrate-get-prop-list (keyword)
"Return prop list for KEYWORD."
(let ((re (format "^#\\+%s:[ \t]*\\([^\n]+\\)" (upcase keyword)))
lst)
(goto-char (point-min))
(while (re-search-forward re 2048 t)
(setq lst (append lst (split-string-and-unquote
(buffer-substring-no-properties
(match-beginning 1) (match-end 1))))))
lst))
(defun org-roam-migrate-prop-set (name value)
"Set a file property called NAME to VALUE in buffer file.
If the property is already set, replace its value."
(setq name (downcase name))
(org-with-point-at 1
(let ((case-fold-search t))
(if (re-search-forward (concat "^#\\+" name ":\\(.*\\)")
(point-max) t)
(replace-match (concat "#+" name ": " value) 'fixedcase)
(while (and (not (eobp))
(looking-at "^[#:]"))
(if (save-excursion (end-of-line) (eobp))
(progn
(end-of-line)
(insert "\n"))
(forward-line)
(beginning-of-line)))
(insert "#+" name ": " value "\n")))))
(defun org-roam-migrate-replace-file-links-with-id ()
"Replace all file: links with ID links in current buffer."
(org-with-point-at 1
(while (re-search-forward org-link-bracket-re nil t)
(let* ((mdata (match-data))
(path (match-string 1))
(desc (match-string 2)))
(when (string-prefix-p "file:" path)
(setq path (expand-file-name (substring path 5)))
(when-let ((node-id (caar (org-roam-db-query [:select [id] :from nodes
:where (= file $s1)
:and (= level 0)] path))))
(set-match-data mdata)
(replace-match (org-link-make-string (concat "id:" node-id)
desc) nil t)))))))
(provide 'org-roam-migrate)
;;; org-roam-migrate.el ends here

711
org-roam-mode.el Normal file
View File

@ -0,0 +1,711 @@
;;; org-roam-mode.el --- Major mode for special Org-roam buffers -*- lexical-binding: t -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.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 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This module implements `org-roam-mode', which is a major mode that used by
;; special Org-roam buffers to display various content in a section-like manner
;; about the nodes and relevant to them information (e.g. backlinks) with which
;; the user can interact with.
;;
;;; Code:
(require 'org-roam)
;;;; Declarations
(defvar org-ref-buffer-hacked)
;;; Options
(defcustom org-roam-mode-sections (list #'org-roam-backlinks-section
#'org-roam-reflinks-section)
"A list of sections for the `org-roam-mode' based buffers.
Each section is a function that is passed the `org-roam-node'
for which the section will be constructed as the first
argument. Normally this node is `org-roam-buffer-current-node'.
The function may also accept other optional arguments. Each item
in the list is either:
1. A function, which is called only with the `org-roam-node' as the argument
2. A list, containing the function and the optional arguments.
For example, one can add
(org-roam-backlinks-section :unique t)
to the list to pass :unique t to the section-rendering function."
:group 'org-roam
:type `(repeat (choice (symbol :tag "Function")
(list :tag "Function with arguments"
(symbol :tag "Function")
(repeat :tag "Arguments" :inline t (sexp :tag "Arg"))))))
(defcustom org-roam-buffer-postrender-functions (list)
"Functions to run after the Org-roam buffer is rendered.
Each function accepts no arguments, and is run with the Org-roam
buffer as the current buffer."
:group 'org-roam
:type 'hook)
(defcustom org-roam-preview-function #'org-roam-preview-default-function
"The preview function to use to populate the Org-roam buffer.
The function takes no arguments, but the point is temporarily set
to the exact location of the backlink."
:group 'org-roam
:type 'function)
(defcustom org-roam-preview-postprocess-functions (list #'org-roam-strip-comments)
"A list of functions to postprocess the preview content.
Each function takes a single argument, the string for the preview
content, and returns the post-processed string. The functions are
applied in order of appearance in the list."
:group 'org-roam
:type 'hook)
;;; Faces
(defface org-roam-header-line
`((((class color) (background light))
,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "DarkGoldenrod4"
:weight bold)
(((class color) (background dark))
,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "LightGoldenrod2"
:weight bold))
"Face for the `header-line' in some Org-roam modes."
:group 'org-roam-faces)
(defface org-roam-title
'((t :weight bold))
"Face for Org-roam titles."
:group 'org-roam-faces)
(defface org-roam-olp
'((((class color) (background light)) :foreground "grey60")
(((class color) (background dark)) :foreground "grey40"))
"Face for the OLP of the node."
:group 'org-roam-faces)
(defface org-roam-preview-heading
`((((class color) (background light))
,@(and (>= emacs-major-version 27) '(:extend t))
:background "grey80"
:foreground "grey30")
(((class color) (background dark))
,@(and (>= emacs-major-version 27) '(:extend t))
:background "grey25"
:foreground "grey70"))
"Face for preview headings."
:group 'org-roam-faces)
(defface org-roam-preview-heading-highlight
`((((class color) (background light))
,@(and (>= emacs-major-version 27) '(:extend t))
:background "grey75"
:foreground "grey30")
(((class color) (background dark))
,@(and (>= emacs-major-version 27) '(:extend t))
:background "grey35"
:foreground "grey70"))
"Face for current preview headings."
:group 'org-roam-faces)
(defface org-roam-preview-heading-selection
`((((class color) (background light))
,@(and (>= emacs-major-version 27) '(:extend t))
:inherit org-roam-preview-heading-highlight
:foreground "salmon4")
(((class color) (background dark))
,@(and (>= emacs-major-version 27) '(:extend t))
:inherit org-roam-preview-heading-highlight
:foreground "LightSalmon3"))
"Face for selected preview headings."
:group 'org-roam-faces)
(defface org-roam-preview-region
`((t :inherit bold
,@(and (>= emacs-major-version 27)
(list :extend (ignore-errors (face-attribute 'region :extend))))))
"Face used by `org-roam-highlight-preview-region-using-face'.
This face is overlaid over text that uses other hunk faces,
and those normally set the foreground and background colors.
The `:foreground' and especially the `:background' properties
should be avoided here. Setting the latter would cause the
loss of information. Good properties to set here are `:weight'
and `:slant'."
:group 'org-roam-faces)
(defface org-roam-dim
'((((class color) (background light)) :foreground "grey60")
(((class color) (background dark)) :foreground "grey40"))
"Face for the dimmer part of the widgets."
:group 'org-roam-faces)
;;; Major mode
(defvar org-roam-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map magit-section-mode-map)
(define-key map [C-return] 'org-roam-buffer-visit-thing)
(define-key map (kbd "C-m") 'org-roam-buffer-visit-thing)
(define-key map [remap revert-buffer] 'org-roam-buffer-refresh)
map)
"Parent keymap for all keymaps of modes derived from `org-roam-mode'.")
(define-derived-mode org-roam-mode magit-section-mode "Org-roam"
"Major mode for displaying relevant information about Org-roam nodes.
This mode is used by special Org-roam buffers, such as persistent
`org-roam-buffer' and dedicated Org-roam buffers
\(`org-roam-buffer-display-dedicated'), which render the
information in a section-like manner (see
`org-roam-mode-sections'), with which the user can
interact with."
:group 'org-roam
(face-remap-add-relative 'header-line 'org-roam-header-line))
;;; Buffers
(defvar org-roam-buffer-current-node nil
"The node for which an `org-roam-mode' based buffer displays its contents.
This set both, locally and globally. Normally the local value is
only set in the `org-roam-mode' based buffers, while the global
value shows the current node in the persistent `org-roam-buffer'.")
(put 'org-roam-buffer-current-node 'permanent-local t)
(defvar org-roam-buffer-current-directory nil
"The `org-roam-directory' value of `org-roam-buffer-current-node'.
Set both, locally and globally in the same way as
`org-roam-buffer-current-node'.")
(put 'org-roam-buffer-current-directory 'permanent-local t)
;;;; Library
(defun org-roam-buffer-visit-thing ()
"This is a placeholder command.
Where applicable, section-specific keymaps bind another command
which visits the thing at point."
(interactive)
(user-error "There is no thing at point that could be visited"))
(defun org-roam-buffer-file-at-point (&optional assert)
"Return the file at point in the current `org-roam-mode' based buffer.
If ASSERT, throw an error."
(if-let ((file (magit-section-case
(org-roam-node-section (org-roam-node-file (oref it node)))
(org-roam-grep-section (oref it file))
(org-roam-preview-section (oref it file))
(t (cl-assert (derived-mode-p 'org-roam-mode))))))
file
(when assert
(user-error "No file at point"))))
(defun org-roam-buffer-refresh ()
"Refresh the contents of the currently selected Org-roam buffer."
(interactive)
(cl-assert (derived-mode-p 'org-roam-mode))
(save-excursion (org-roam-buffer-render-contents)))
(defun org-roam-buffer-render-contents ()
"Recompute and render the contents of an Org-roam buffer.
Assumes that the current buffer is an `org-roam-mode' based
buffer."
(let ((inhibit-read-only t))
(erase-buffer)
(org-roam-mode)
(setq-local default-directory org-roam-buffer-current-directory)
(setq-local org-roam-directory org-roam-buffer-current-directory)
(org-roam-buffer-set-header-line-format
(org-roam-node-title org-roam-buffer-current-node))
(magit-insert-section (org-roam)
(magit-insert-heading)
(dolist (section org-roam-mode-sections)
(pcase section
((pred functionp)
(funcall section org-roam-buffer-current-node))
(`(,fn . ,args)
(apply fn (cons org-roam-buffer-current-node args)))
(_
(user-error "Invalid `org-roam-mode-sections' specification")))))
(run-hooks 'org-roam-buffer-postrender-functions)
(goto-char 0)))
(defun org-roam-buffer-set-header-line-format (string)
"Set the header-line using STRING.
If the `face' property of any part of STRING is already set, then
that takes precedence. Also pad the left side of STRING so that
it aligns with the text area."
(setq-local header-line-format
(concat (propertize " " 'display '(space :align-to 0))
string)))
;;;; Dedicated buffer
;;;###autoload
(defun org-roam-buffer-display-dedicated (node)
"Launch NODE dedicated Org-roam buffer.
Unlike the persistent `org-roam-buffer', the contents of this
buffer won't be automatically changed and will be held in place.
In interactive calls prompt to select NODE, unless called with
`universal-argument', in which case NODE will be set to
`org-roam-node-at-point'."
(interactive
(list (if current-prefix-arg
(org-roam-node-at-point 'assert)
(org-roam-node-read nil nil nil 'require-match))))
(let ((buffer (get-buffer-create (org-roam-buffer--dedicated-name node))))
(with-current-buffer buffer
(setq-local org-roam-buffer-current-node node)
(setq-local org-roam-buffer-current-directory org-roam-directory)
(org-roam-buffer-render-contents))
(display-buffer buffer)))
(defun org-roam-buffer--dedicated-name (node)
"Construct buffer name for NODE dedicated Org-roam buffer."
(let ((title (org-roam-node-title node))
(filename (file-relative-name (org-roam-node-file node) org-roam-directory)))
(format "*org-roam: %s<%s>*" title filename)))
(defun org-roam-buffer-dedicated-p (&optional buffer)
"Return t if an Org-roam BUFFER is a node dedicated one.
See `org-roam-buffer-display-dedicated' for more details.
If BUFFER is nil, default it to `current-buffer'."
(or buffer (setq buffer (current-buffer)))
(string-match-p (concat "^" (regexp-quote "*org-roam: "))
(buffer-name buffer)))
;;;; Persistent buffer
(defvar org-roam-buffer "*org-roam*"
"The persistent Org-roam buffer name. Must be surround with \"*\".
The content inside of this buffer will be automatically updated
to the nearest node at point that comes from the current buffer.
To toggle its display use `org-roam-buffer-toggle' command.")
(defun org-roam-buffer-toggle ()
"Toggle display of the persistent `org-roam-buffer'."
(interactive)
(pcase (org-roam-buffer--visibility)
('visible
(progn
(quit-window nil (get-buffer-window org-roam-buffer))
(remove-hook 'post-command-hook #'org-roam-buffer--redisplay-h)))
((or 'exists 'none)
(progn
(display-buffer (get-buffer-create org-roam-buffer))
(org-roam-buffer-persistent-redisplay)))))
(define-inline org-roam-buffer--visibility ()
"Return the current visibility state of the persistent `org-roam-buffer'.
Valid states are `visible', `exists' and `none'."
(declare (side-effect-free t))
(inline-quote
(cond
((get-buffer-window org-roam-buffer) 'visible)
((get-buffer org-roam-buffer) 'exists)
(t 'none))))
(defun org-roam-buffer-persistent-redisplay ()
"Recompute contents of the persistent `org-roam-buffer'.
Has no effect when there's no `org-roam-node-at-point'."
(when-let ((node (org-roam-node-at-point)))
(unless (equal node org-roam-buffer-current-node)
(setq org-roam-buffer-current-node node
org-roam-buffer-current-directory org-roam-directory)
(with-current-buffer (get-buffer-create org-roam-buffer)
(org-roam-buffer-render-contents)
(add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t)))))
(defun org-roam-buffer--persistent-cleanup-h ()
"Clean-up global state that's dedicated for the persistent `org-roam-buffer'."
(setq-default org-roam-buffer-current-node nil
org-roam-buffer-current-directory nil))
(add-hook 'org-roam-find-file-hook #'org-roam-buffer--setup-redisplay-h)
(defun org-roam-buffer--setup-redisplay-h ()
"Setup automatic redisplay of the persistent `org-roam-buffer'."
(add-hook 'post-command-hook #'org-roam-buffer--redisplay-h nil t))
(defun org-roam-buffer--redisplay-h ()
"Reconstruct the persistent `org-roam-buffer'.
This needs to be quick or infrequent, because this designed to
run at `post-command-hook'."
(and (get-buffer-window org-roam-buffer)
(org-roam-buffer-persistent-redisplay)))
;;; Sections
;;;; Node
(defvar org-roam-node-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map org-roam-mode-map)
(define-key map [remap org-roam-buffer-visit-thing] 'org-roam-node-visit)
map)
"Keymap for `org-roam-node-section's.")
(defclass org-roam-node-section (magit-section)
((keymap :initform 'org-roam-node-map)
(node :initform nil))
"A `magit-section' used by `org-roam-mode' to outline NODE in its own heading.")
(cl-defun org-roam-node-insert-section (&key source-node point properties)
"Insert section for a link from SOURCE-NODE to some other node.
The other node is normally `org-roam-buffer-current-node'.
SOURCE-NODE is an `org-roam-node' that links or references with
the other node.
POINT is a character position where the link is located in
SOURCE-NODE's file.
PROPERTIES (a plist) contains additional information about the
link.
Despite the name, this function actually inserts 2 sections at
the same time:
1. `org-roam-node-section' for a heading that describes
SOURCE-NODE. Acts as a parent section of the following one.
2. `org-roam-preview-section' for a preview content that comes
from SOURCE-NODE's file for the link (that references the
other node) at POINT. Acts a child section of the previous
one."
(magit-insert-section section (org-roam-node-section)
(let ((outline (if-let ((outline (plist-get properties :outline)))
(mapconcat #'org-link-display-format outline " > ")
"Top")))
(insert (concat (propertize (org-roam-node-title source-node)
'font-lock-face 'org-roam-title)
(format " (%s)"
(propertize outline 'font-lock-face 'org-roam-olp)))))
(magit-insert-heading)
(oset section node source-node)
(magit-insert-section section (org-roam-preview-section)
(insert (org-roam-fontify-like-in-org-mode
(org-roam-preview-get-contents (org-roam-node-file source-node) point))
"\n")
(oset section file (org-roam-node-file source-node))
(oset section point point)
(insert ?\n))))
;;;; Preview
(defvar org-roam-preview-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map org-roam-mode-map)
(define-key map [remap org-roam-buffer-visit-thing] 'org-roam-preview-visit)
map)
"Keymap for `org-roam-preview-section's.")
(defclass org-roam-preview-section (magit-section)
((keymap :initform 'org-roam-preview-map)
(file :initform nil)
(point :initform nil))
"A `magit-section' used by `org-roam-mode' to contain preview content.
The preview content comes from FILE, and the link as at POINT.")
(defun org-roam-preview-visit (file point &optional other-window)
"Visit FILE at POINT and return the visited buffer.
With OTHER-WINDOW non-nil do so in another window.
In interactive calls OTHER-WINDOW is set with
`universal-argument'."
(interactive (list (org-roam-buffer-file-at-point 'assert)
(oref (magit-current-section) point)
current-prefix-arg))
(let ((buf (find-file-noselect file))
(display-buffer-fn (if other-window
#'switch-to-buffer-other-window
#'pop-to-buffer-same-window)))
(funcall display-buffer-fn buf)
(with-current-buffer buf
(widen)
(goto-char point))
(when (org-invisible-p) (org-fold-show-context))
buf))
(defun org-roam-preview-default-function ()
"Return the preview content at point.
This function returns the all contents under the current
headline, up to the next headline."
(let ((beg (save-excursion
(org-roam-end-of-meta-data t)
(point)))
(end (save-excursion
(org-next-visible-heading 1)
(point))))
(string-trim (buffer-substring-no-properties beg end))))
(defun org-roam-preview-get-contents (file pt)
"Get preview content for FILE at PT."
(save-excursion
(org-roam-with-temp-buffer file
(org-with-wide-buffer
(goto-char pt)
(let ((s (funcall org-roam-preview-function)))
(dolist (fn org-roam-preview-postprocess-functions)
(setq s (funcall fn s)))
s)))))
;;;; Backlinks
(cl-defstruct (org-roam-backlink (:constructor org-roam-backlink-create)
(:copier nil))
source-node target-node
point properties)
(cl-defmethod org-roam-populate ((backlink org-roam-backlink))
"Populate BACKLINK from database."
(setf (org-roam-backlink-source-node backlink)
(org-roam-populate (org-roam-backlink-source-node backlink))
(org-roam-backlink-target-node backlink)
(org-roam-populate (org-roam-backlink-target-node backlink)))
backlink)
(cl-defun org-roam-backlinks-get (node &key unique)
"Return the backlinks for NODE.
When UNIQUE is nil, show all positions where references are found.
When UNIQUE is t, limit to unique sources."
(let* ((sql (if unique
[:select :distinct [source dest pos properties]
:from links
:where (= dest $s1)
:and (= type "id")
:group :by source
:having (funcall min pos)]
[:select [source dest pos properties]
:from links
:where (= dest $s1)
:and (= type "id")]))
(backlinks (org-roam-db-query sql (org-roam-node-id node))))
(cl-loop for backlink in backlinks
collect (pcase-let ((`(,source-id ,dest-id ,pos ,properties) backlink))
(org-roam-populate
(org-roam-backlink-create
:source-node (org-roam-node-create :id source-id)
:target-node (org-roam-node-create :id dest-id)
:point pos
:properties properties))))))
(defun org-roam-backlinks-sort (a b)
"Default sorting function for backlinks A and B.
Sorts by title."
(string< (org-roam-node-title (org-roam-backlink-source-node a))
(org-roam-node-title (org-roam-backlink-source-node b))))
(cl-defun org-roam-backlinks-section (node &key (unique nil) (show-backlink-p nil)
(section-heading "Backlinks:"))
"The backlinks section for NODE.
When UNIQUE is nil, show all positions where references are found.
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))))
(magit-insert-section (org-roam-backlinks)
(magit-insert-heading section-heading)
(dolist (backlink backlinks)
(when (or (null show-backlink-p)
(and (not (null show-backlink-p))
(funcall show-backlink-p 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))))
;;;; Reflinks
(cl-defstruct (org-roam-reflink (:constructor org-roam-reflink-create)
(:copier nil))
source-node ref
point properties)
(cl-defmethod org-roam-populate ((reflink org-roam-reflink))
"Populate REFLINK from database."
(setf (org-roam-reflink-source-node reflink)
(org-roam-populate (org-roam-reflink-source-node reflink)))
reflink)
(defun org-roam-reflinks-get (node)
"Return the reflinks for NODE."
(let ((refs (org-roam-db-query [:select :distinct [refs:ref links:source links:pos links:properties]
:from refs
:left-join links
:where (= refs:node-id $s1)
:and (= links:dest refs:ref)
:union
:select :distinct [refs:ref citations:node-id
citations:pos citations:properties]
:from refs
:left-join citations
:where (= refs:node-id $s1)
:and (= citations:cite-key refs:ref)]
(org-roam-node-id node)))
links)
(pcase-dolist (`(,ref ,source-id ,pos ,properties) refs)
(push (org-roam-populate
(org-roam-reflink-create
:source-node (org-roam-node-create :id source-id)
:ref ref
:point pos
:properties properties)) links))
links))
(defun org-roam-reflinks-sort (a b)
"Default sorting function for reflinks A and B.
Sorts by title."
(string< (org-roam-node-title (org-roam-reflink-source-node a))
(org-roam-node-title (org-roam-reflink-source-node b))))
(defun org-roam-reflinks-section (node)
"The reflinks section for NODE."
(when-let ((refs (org-roam-node-refs node))
(reflinks (seq-sort #'org-roam-reflinks-sort (org-roam-reflinks-get node))))
(magit-insert-section (org-roam-reflinks)
(magit-insert-heading "Reflinks:")
(dolist (reflink reflinks)
(org-roam-node-insert-section
:source-node (org-roam-reflink-source-node reflink)
:point (org-roam-reflink-point reflink)
:properties (org-roam-reflink-properties reflink)))
(insert ?\n))))
;;;; Grep
(defvar org-roam-grep-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map org-roam-mode-map)
(define-key map [remap org-roam-buffer-visit-thing] 'org-roam-grep-visit)
map)
"Keymap for Org-roam grep result sections.")
(defclass org-roam-grep-section (magit-section)
((keymap :initform 'org-roam-grep-map)
(file :initform nil)
(row :initform nil)
(col :initform nil))
"A `magit-section' used by `org-roam-mode' to contain grep output.")
(defun org-roam-grep-visit (file &optional other-window row col)
"Visit FILE at row ROW (if any) and column COL (if any). Return the buffer.
With OTHER-WINDOW non-nil (in interactive calls set with
`universal-argument') display the buffer in another window
instead."
(interactive (list (org-roam-buffer-file-at-point t)
current-prefix-arg
(oref (magit-current-section) row)
(oref (magit-current-section) col)))
(let ((buf (find-file-noselect file))
(display-buffer-fn (if other-window
#'switch-to-buffer-other-window
#'pop-to-buffer-same-window)))
(funcall display-buffer-fn buf)
(with-current-buffer buf
(widen)
(goto-char (point-min))
(when row
(forward-line (1- row)))
(when col
(forward-char (1- col))))
(when (org-invisible-p) (org-fold-show-context))
buf))
;;;; Unlinked references
(defvar org-roam-unlinked-references-result-re
(rx (group (one-or-more anything))
":"
(group (one-or-more digit))
":"
(group (one-or-more digit))
":"
(group (zero-or-more anything)))
"Regex for the return result of a ripgrep query.")
(defun org-roam-unlinked-references-preview-line (file row)
"Return the preview line from FILE.
This is the ROW within FILE."
(with-temp-buffer
(insert-file-contents file)
(forward-line (1- row))
(buffer-substring-no-properties
(save-excursion
(beginning-of-line)
(point))
(save-excursion
(end-of-line)
(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)
"The unlinked references section for NODE.
References from FILE are excluded."
(when (and (executable-find "rg")
(org-roam-node-title node)
(not (string-match "PCRE2 is not available"
(shell-command-to-string "rg --pcre2-version"))))
(let* ((titles (cons (org-roam-node-title node)
(org-roam-node-aliases node)))
(rg-command (org-roam-unlinked-references--rg-command titles))
(results (split-string (shell-command-to-string rg-command) "\n"))
f row col match)
(magit-insert-section (unlinked-references)
(magit-insert-heading "Unlinked References:")
(dolist (line results)
(save-match-data
(when (string-match org-roam-unlinked-references-result-re line)
(setq f (match-string 1 line)
row (string-to-number (match-string 2 line))
col (string-to-number (match-string 3 line))
match (match-string 4 line))
(when (and match
(not (file-equal-p (org-roam-node-file node) f))
(member (downcase match) (mapcar #'downcase titles)))
(magit-insert-section section (org-roam-grep-section)
(oset section file f)
(oset section row row)
(oset section col col)
(insert (propertize (format "%s:%s:%s"
(truncate-string-to-width (file-name-base f) 15 nil nil t)
row col) 'font-lock-face 'org-roam-dim)
" "
(org-roam-fontify-like-in-org-mode
(org-roam-unlinked-references-preview-line f row))
"\n"))))))
(insert ?\n)))))
(provide 'org-roam-mode)
;;; org-roam-mode.el ends here

1150
org-roam-node.el Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +0,0 @@
;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t -*-
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (org "9.3"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; We extend org-protocol, adding custom Org-roam handlers. The setup
;; instructions for `org-protocol' can be found in org-protocol.el.
;;
;; We define 2 protocols:
;;
;; 1. "roam-file": This protocol simply opens the file given by the FILE key
;; 2. "roam-ref": This protocol creates or opens a note with the given REF
;;
;;; Code:
(require 'org-protocol)
(require 'org-roam)
;;;; Functions
(defun org-roam-protocol-open-ref (info)
"Process an org-protocol://roam-ref?ref= style url with INFO.
It opens or creates a note with the given ref.
javascript:location.href = \\='org-protocol://roam-ref?template=r&ref=\\='+ \\
encodeURIComponent(location.href) + \\='&title=\\=' \\
encodeURIComponent(document.title) + \\='&body=\\=' + \\
encodeURIComponent(window.getSelection())"
(when-let* ((alist (org-roam--plist-to-alist info))
(decoded-alist (mapcar (lambda (k.v)
(let ((key (car k.v))
(val (cdr k.v)))
(cons key (org-link-decode val)))) alist)))
(unless (assoc 'ref decoded-alist)
(error "No ref key provided"))
(when-let ((title (cdr (assoc 'title decoded-alist))))
(push (cons 'slug (org-roam--title-to-slug title)) decoded-alist))
(let* ((org-roam-capture-templates org-roam-capture-ref-templates)
(org-roam-capture--context 'ref)
(org-roam-capture--info decoded-alist)
(template (cdr (assoc 'template decoded-alist))))
(raise-frame)
(org-roam--capture nil template)
(message "Item captured.")))
nil)
(defun org-roam-protocol-open-file (info)
"This handler simply opens the file with emacsclient.
INFO is an alist containing additional information passed by the protocol URL.
It should contain the FILE key, pointing to the path of the file to open.
Example protocol string:
org-protocol://roam-file?file=/path/to/file.org"
(when-let ((file (plist-get info :file)))
(raise-frame)
(find-file file))
nil)
(push '("org-roam-ref" :protocol "roam-ref" :function org-roam-protocol-open-ref)
org-protocol-protocol-alist)
(push '("org-roam-file" :protocol "roam-file" :function org-roam-protocol-open-file)
org-protocol-protocol-alist)
(provide 'org-roam-protocol)
;;; org-roam-protocol.el ends here

458
org-roam-utils.el Normal file
View File

@ -0,0 +1,458 @@
;;; org-roam-utils.el --- Utilities for Org-roam -*- lexical-binding: t; -*-
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.3.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6"))
;; This file is NOT part of GNU Emacs.
;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This library provides definitions for utilities that used throughout the
;; whole package.
;;
;;; Code:
(require 'org-roam)
(defun org-roam-require (libs)
"Require LIBS."
(dolist (lib libs)
(require lib nil 'noerror)))
;;; String utilities
;; TODO Refactor this.
(defun org-roam-replace-string (old new s)
"Replace OLD with NEW in S."
(declare (pure t) (side-effect-free t))
(replace-regexp-in-string (regexp-quote old) new s t t))
(defun org-roam-quote-string (s)
"Quotes string S."
(->> s
(org-roam-replace-string "\\" "\\\\")
(org-roam-replace-string "\"" "\\\"")))
(defun org-roam-word-wrap (len s)
"If S is longer than LEN, wrap the words with newlines."
(declare (side-effect-free t))
(save-match-data
(with-temp-buffer
(insert s)
(let ((fill-column len))
(fill-region (point-min) (point-max)))
(buffer-substring (point-min) (point-max)))))
(defun org-roam-string-equal (s1 s2)
"Return t if S1 and S2 are equal.
Like `string-equal', but case-insensitive."
(and (= (length s1) (length s2))
(or (string-equal s1 s2)
(string-equal (downcase s1) (downcase s2)))))
(defun org-roam-whitespace-content (s)
"Return the whitespace content at the end of S."
(with-temp-buffer
(insert s)
(skip-chars-backward " \t\n")
(buffer-substring-no-properties
(point) (point-max))))
(defun org-roam-strip-comments (s)
"Strip Org comments from string S."
(with-temp-buffer
(insert s)
(goto-char (point-min))
(while (not (eobp))
(if (org-at-comment-p)
(delete-region (line-beginning-position)
(progn (forward-line) (point)))
(forward-line)))
(buffer-string)))
;;; List utilities
(defun org-roam-plist-map! (fn plist)
"Map FN over PLIST, modifying it in-place and returning it.
FN must take two arguments: the key and the value."
(let ((plist-index plist))
(while plist-index
(let ((key (pop plist-index)))
(setf (car plist-index) (funcall fn key (car plist-index))
plist-index (cdr plist-index)))))
plist)
(defmacro org-roam-dolist-with-progress (spec msg &rest body)
"Loop over a list and report progress in the echo area.
Like `dolist-with-progress-reporter', but falls back to `dolist'
if the function does not yet exist.
Evaluate BODY with VAR bound to each car from LIST, in turn.
Then evaluate RESULT to get return value, default nil.
MSG is a progress reporter object or a string. In the latter
case, use this string to create a progress reporter.
SPEC is a list, as per `dolist'."
(declare (indent 2))
(if (fboundp 'dolist-with-progress-reporter)
`(dolist-with-progress-reporter ,spec ,msg ,@body)
`(dolist ,spec ,@body)))
;;; File utilities
(defun org-roam-descendant-of-p (a b)
"Return t if A is descendant of 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)
(replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name a) t t))))
(defmacro org-roam-with-file (file keep-buf-p &rest body)
"Execute BODY within FILE.
If FILE is nil, execute BODY in the current buffer.
Kills the buffer if KEEP-BUF-P is nil, and FILE is not yet visited."
(declare (indent 2) (debug t))
`(let* (new-buf
(auto-mode-alist nil)
(find-file-hook nil)
(buf (or (and (not ,file)
(current-buffer)) ;If FILE is nil, use current buffer
(find-buffer-visiting ,file) ; If FILE is already visited, find buffer
(progn
(setq new-buf t)
(find-file-noselect ,file)))) ; Else, visit FILE and return buffer
res)
(with-current-buffer buf
(unless (derived-mode-p 'org-mode)
(delay-mode-hooks
(let ((org-inhibit-startup t)
(org-agenda-files nil))
(org-mode)
(hack-local-variables))))
(setq res (progn ,@body))
(unless (and new-buf (not ,keep-buf-p))
(save-buffer)))
(if (and new-buf (not ,keep-buf-p))
(when (find-buffer-visiting ,file)
(kill-buffer (find-buffer-visiting ,file))))
res))
;;; Buffer utilities
(defmacro org-roam-with-temp-buffer (file &rest body)
"Execute BODY within a temp buffer.
Like `with-temp-buffer', but propagates `org-roam-directory'.
If FILE, set `default-directory' to FILE's directory and insert its contents."
(declare (indent 1) (debug t))
(let ((current-org-roam-directory (make-symbol "current-org-roam-directory")))
`(let ((,current-org-roam-directory org-roam-directory))
(with-temp-buffer
(let ((org-roam-directory ,current-org-roam-directory))
(delay-mode-hooks (org-mode))
(when ,file
(insert-file-contents ,file)
(setq-local default-directory (file-name-directory ,file)))
,@body)))))
;;; Formatting
(defun org-roam-format-template (template replacer)
"Format TEMPLATE with the function REPLACER.
The templates are of form ${foo} for variable foo, and
${foo=default} for variable foo with default value \"default\".
REPLACER takes an argument of the format variable and the default
value (possibly nil). Adapted from `s-format'."
(let ((saved-match-data (match-data)))
(unwind-protect
(replace-regexp-in-string
"\\${\\([^}]+\\)}"
(lambda (md)
(let ((var (match-string 1 md))
(replacer-match-data (match-data))
default-val)
(when (string-match "\\(.+\\)=\\(.+\\)" var)
(setq default-val (match-string 2 var)
var (match-string 1 var)))
(unwind-protect
(let ((v (progn
(set-match-data saved-match-data)
(funcall replacer var default-val))))
(if v
(format (apply #'propertize "%s" (text-properties-at 0 var)) v)
(signal 'org-roam-format-resolve md)))
(set-match-data replacer-match-data))))
(if (functionp template)
(funcall template)
template)
;; Need literal to make sure it works
t t)
(set-match-data saved-match-data))))
;;; Fontification
(defvar org-ref-buffer-hacked)
(defun org-roam-fontify-like-in-org-mode (s)
"Fontify string S like in Org mode.
Like `org-fontify-like-in-org-mode', but supports `org-ref'."
;; NOTE: pretend that the temporary buffer created by `org-fontify-like-in-org-mode' to
;; fontify a `cite:' reference has been hacked by org-ref, whatever that means;
;;
;; `org-ref-cite-link-face-fn', which is used to supply a face for `cite:' links, calls
;; `hack-dir-local-variables' rationalizing that `bibtex-completion' would throw some warnings
;; otherwise. This doesn't seem to be the case and calling this function just before
;; `org-font-lock-ensure' (alias of `font-lock-ensure') actually instead of fixing the alleged
;; warnings messes the things so badly that `font-lock-ensure' crashes with error and doesn't let
;; org-roam to proceed further. I don't know what's happening there exactly but disabling this hackery
;; fixes the crashing. Fortunately, org-ref provides the `org-ref-buffer-hacked' switch, which we use
;; here to make it believe that the buffer was hacked.
;;
;; This is a workaround for `cite:' links and does not have any effect on other ref types.
;;
;; `org-ref-buffer-hacked' is a buffer-local variable, therefore we inline
;; `org-fontify-like-in-org-mode' here
(with-temp-buffer
(insert s)
(let ((org-ref-buffer-hacked t))
(org-mode)
(setq-local org-fold-core-style 'overlays)
(font-lock-ensure)
(buffer-string))))
;;; Org-mode utilities
;;;; Motions
(defun org-roam-up-heading-or-point-min ()
"Fixed version of Org's `org-up-heading-or-point-min'."
(ignore-errors (org-back-to-heading t))
(let ((p (point)))
(if (< 1 (funcall outline-level))
(progn
(org-up-heading-safe)
(when (= (point) p)
(goto-char (point-min))))
(unless (bobp) (goto-char (point-min))))))
;;;; Keywords
(defun org-roam-get-keyword (name &optional file bound)
"Return keyword property NAME from an org FILE.
FILE defaults to current file.
Only scans up to BOUND bytes of the document."
(unless bound
(setq bound 1024))
(if file
(with-temp-buffer
(insert-file-contents file nil 0 bound)
(org-roam--get-keyword name))
(org-roam--get-keyword name bound)))
(defun org-roam--get-keyword (name &optional bound)
"Return keyword property NAME in current buffer.
If BOUND, scan up to BOUND bytes of the buffer."
(save-excursion
(let ((re (format "^#\\+%s:[ \t]*\\([^\n]+\\)" (upcase name))))
(goto-char (point-min))
(when (re-search-forward re bound t)
(buffer-substring-no-properties (match-beginning 1) (match-end 1))))))
(defun org-roam-end-of-meta-data (&optional full)
"Like `org-end-of-meta-data', but supports file-level metadata.
When FULL is non-nil but not t, skip planning information,
properties, clocking lines and logbook drawers.
When optional argument FULL is t, skip everything above, and also
skip keywords."
(org-back-to-heading-or-point-min t)
(when (org-at-heading-p) (forward-line))
;; Skip planning information.
(when (looking-at-p org-planning-line-re) (forward-line))
;; Skip property drawer.
(when (looking-at org-property-drawer-re)
(goto-char (match-end 0))
(forward-line))
;; When FULL is not nil, skip more.
(when (and full (not (org-at-heading-p)))
(catch 'exit
(let ((end (save-excursion (outline-next-heading) (point)))
(re (concat "[ \t]*$" "\\|" org-clock-line-re)))
(while (not (eobp))
(cond ;; Skip clock lines.
((looking-at-p re) (forward-line))
;; Skip logbook drawer.
((looking-at-p org-logbook-drawer-re)
(if (re-search-forward "^[ \t]*:END:[ \t]*$" end t)
(forward-line)
(throw 'exit t)))
((looking-at-p org-drawer-regexp)
(if (re-search-forward "^[ \t]*:END:[ \t]*$" end t)
(forward-line)
(throw 'exit t)))
;; When FULL is t, skip keywords too.
((and (eq full t)
(looking-at-p org-keyword-regexp))
(forward-line))
(t (throw 'exit t))))))))
(defun org-roam-set-keyword (key value)
"Set keyword KEY to VALUE.
If the property is already set, it's value is replaced."
(org-with-point-at 1
(let ((case-fold-search t))
(if (re-search-forward (concat "^#\\+" key ":\\(.*\\)") (point-max) t)
(if (string-blank-p value)
(kill-whole-line)
(replace-match (concat " " value) 'fixedcase nil nil 1))
(org-roam-end-of-meta-data 'drawers)
(if (save-excursion (end-of-line) (eobp))
(progn
(end-of-line)
(insert "\n"))
(forward-line)
(beginning-of-line))
(insert "#+" key ": " value "\n")))))
(defun org-roam-erase-keyword (keyword)
"Erase the line where the KEYWORD is, setting line from the top of the file."
(let ((case-fold-search t))
(org-with-point-at 1
(when (re-search-forward (concat "^#\\+" keyword ":") nil t)
(beginning-of-line)
(delete-region (point) (line-end-position))
(delete-char 1)))))
;;;; Properties
(defun org-roam-add-property (val prop)
"Add VAL value to PROP property for the node at point.
Both, VAL and PROP are strings."
(org-roam-property-add prop val))
(defun org-roam-remove-property (prop &optional val)
"Remove VAL value from PROP property for the node at point.
Both VAL and PROP are strings.
If VAL is not specified, user is prompted to select a value."
(org-roam-property-remove prop val))
(defun org-roam-property-add (prop val)
"Add VAL value to PROP property for the node at point.
Both, VAL and PROP are strings."
(let* ((p (org-entry-get (point) prop))
(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-property-remove (prop &optional val)
"Remove VAL value from PROP property for the node at point.
Both VAL and PROP are strings.
If VAL is not specified, user is prompted to select a value."
(let* ((p (org-entry-get (point) prop))
(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))
;;; Refs
(defun org-roam-org-ref-path-to-keys (path)
"Return a list of keys given an org-ref cite: PATH.
Accounts for both v2 and v3."
(cond ((fboundp 'org-ref-parse-cite-path)
(mapcar (lambda (cite) (plist-get cite :key))
(plist-get (org-ref-parse-cite-path path) :references)))
((fboundp 'org-ref-split-and-strip-string)
(org-ref-split-and-strip-string path))))
;;; Logs
(defvar org-roam-verbose)
(defun org-roam-message (format-string &rest args)
"Pass FORMAT-STRING and ARGS to `message' when `org-roam-verbose' is t."
(when org-roam-verbose
(apply #'message `(,(concat "(org-roam) " format-string) ,@args))))
;;; Diagnostics
;; TODO Update this to also get commit hash
;;;###autoload
(defun org-roam-version (&optional message)
"Return `org-roam' version.
Interactively, or when MESSAGE is non-nil, show in the echo area."
(interactive)
(let* ((toplib (or load-file-name buffer-file-name))
gitdir topdir version)
(unless (and toplib (equal (file-name-nondirectory toplib) "org-roam-utils.el"))
(setq toplib (locate-library "org-roam-utils.el")))
(setq toplib (and toplib (org-roam--straight-chase-links toplib)))
(when toplib
(setq topdir (file-name-directory toplib)
gitdir (expand-file-name ".git" topdir)))
(when (file-exists-p gitdir)
(setq version
(let ((default-directory topdir))
(shell-command-to-string "git describe --tags --dirty --always"))))
(unless version
(setq version (with-temp-buffer
(insert-file-contents-literally (locate-library "org-roam.el"))
(goto-char (point-min))
(save-match-data
(if (re-search-forward "\\(?:;; Version: \\([^z-a]*?$\\)\\)" nil nil)
(substring-no-properties (match-string 1))
"N/A")))))
(if (or message (called-interactively-p 'interactive))
(message "%s" version)
version)))
(defun org-roam--straight-chase-links (filename)
"Chase links in FILENAME until a name that is not a link.
This is the same as `file-chase-links', except that it also
handles fake symlinks that are created by the package manager
straight.el on Windows.
See <https://github.com/raxod502/straight.el/issues/520>."
(when (and (bound-and-true-p straight-symlink-emulation-mode)
(fboundp 'straight-chase-emulated-symlink))
(when-let ((target (straight-chase-emulated-symlink filename)))
(unless (eq target 'broken)
(setq filename target))))
(file-chase-links filename))
;;;###autoload
(defun org-roam-diagnostics ()
"Collect and print info for `org-roam' issues."
(interactive)
(with-current-buffer (switch-to-buffer-other-window (get-buffer-create "*org-roam diagnostics*"))
(erase-buffer)
(insert (propertize "Copy info below this line into issue:\n" 'face '(:weight bold)))
(insert (format "- Emacs: %s\n" (emacs-version)))
(insert (format "- Framework: %s\n"
(condition-case _
(completing-read "I'm using the following Emacs framework:"
'("Doom" "Spacemacs" "N/A" "I don't know"))
(quit "N/A"))))
(insert (format "- Org: %s\n" (org-version nil 'full)))
(insert (format "- Org-roam: %s" (org-roam-version)))
(insert (format "- sqlite-connector: %s"
(if-let ((conn (org-roam-db--get-connection)))
(eieio-object-class conn)
"not connected")))))
(provide 'org-roam-utils)
;;; org-roam-utils.el ends here

View File

@ -1,12 +1,12 @@
;;; org-roam.el --- Roam Research replica with 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 Jethro Kuan <jethrokuan95@gmail.com>
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 1.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
;; Version: 2.3.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.
@ -27,123 +27,232 @@
;;; Commentary:
;;
;; This library is an attempt at injecting Roam functionality into Org-mode.
;; This is achieved primarily through building caches for forward links,
;; backward links, and file titles.
;; Org-roam is a Roam Research inspired Emacs package and is an addition to
;; Org-mode to have a way to quickly process complex SQL-like queries over a
;; large set of plain text Org-mode files. To achieve this Org-roam provides a
;; database abstraction layer, the capabilities of which include, but are not
;; limited to:
;;
;; - Link graph traversal and visualization.
;; - Instantaneous SQL-like queries on headlines
;; - What are my TODOs, scheduled for X, or due by Y?
;; - Accessing the properties of a node, such as its tags, refs, TODO state or
;; priority.
;;
;; All of these functionality is powered by this layer. Hence, at its core
;; Org-roam's primary goal is to provide a resilient dual representation of
;; what's already available in plain text, while cached in a binary database,
;; that is cheap to maintain, easy to understand, and is as up-to-date as it
;; possibly can. For users who would like to perform arbitrary programmatic
;; queries on their Org files Org-roam also exposes an API to this database
;; abstraction layer.
;;
;; -----------------------------------------------------------------------------
;;
;; In order for the package to correctly work through your interactive session
;; it's mandatory to add somewhere to your configuration the next form:
;;
;; (org-roam-db-autosync-mode)
;;
;; The form can be called both, before or after loading the package, which is up
;; to your preferences. If you call this before the package is loaded, then it
;; will automatically load the package.
;;
;; -----------------------------------------------------------------------------
;;
;; This package also comes with a set of officially supported extensions that
;; provide extra features. You can find them in the "extensions/" subdirectory.
;; These extensions are not automatically loaded with `org-roam`, but they still
;; will be lazy-loaded through their own `autoload's.
;;
;; Org-roam also has other extensions that don't come together with this package.
;; Such extensions are distributed as their own packages, while also
;; authored and maintained by different people on distinct repositories. The
;; majority of them can be found at https://github.com/org-roam and MELPA.
;;
;;; Code:
;;;; Library Requires
(require 'org)
(require 'org-element)
(require 'ob-core) ;for org-babel-parse-header-arguments
(eval-when-compile (require 'subr-x))
(require 'dash)
(require 's)
(require 'f)
(require 'rx)
(require 'seq)
(require 'cl-lib)
;;;; org-roam features
(require 'org-roam-compat)
(require 'org-roam-macs)
(require 'org-roam-db)
(require 'org-roam-buffer)
(require 'org-roam-capture)
(require 'org-roam-graph)
(require 'org-roam-completion)
(require 'org-roam-dailies)
;; To detect cite: links
(require 'org-ref nil t)
(require 'magit-section)
;;;; Customizable Variables
(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 'org)
(require 'org-attach) ; To set `org-attach-id-dir'
(require 'org-id)
(require 'ol)
(require 'org-element)
(require 'org-capture)
(require 'ansi-color) ; to strip ANSI color codes in `org-roam--list-files'
(eval-when-compile
(require 'subr-x))
;;; Options
(defgroup org-roam nil
"Roam Research replica in Org-mode."
"A database abstraction layer for Org-mode."
:group 'org
:prefix "org-roam-"
:link '(url-link :tag "Github" "https://github.com/jethrokuan/org-roam")
:link '(url-link :tag "Online Manual" "https://org-roam.readthedocs.io/"))
:link '(url-link :tag "Github" "https://github.com/org-roam/org-roam")
:link '(url-link :tag "Online Manual" "https://www.orgroam.com/manual.html"))
(defgroup org-roam-faces nil
"Faces used by Org-roam."
:group 'org-roam
:group 'faces)
(defcustom org-roam-directory (expand-file-name "~/org-roam/")
"Default path to Org-roam files.
All Org files, at any level of nesting, are considered part of the Org-roam."
:type 'directory
:group 'org-roam)
(defcustom org-roam-link-title-format "%s"
"The formatter used when inserting Org-roam links that use their title.
Formatter may be a function that takes title as its only argument."
:type '(choice
(string :tag "String Format" "%s")
(function :tag "Custom function"))
:group 'org-roam)
(defcustom org-roam-encrypt-files nil
"Whether to encrypt new files. If true, create files with .org.gpg extension."
:type 'boolean
:group 'org-roam)
(defcustom org-roam-verbose t
"Echo messages that are not errors."
:type 'boolean
:group 'org-roam)
(defcustom org-roam-directory (expand-file-name "~/org-roam/")
"Default path to Org-roam files.
All Org files, at any level of nesting, are considered part of the Org-roam."
:type 'directory
:group 'org-roam)
(defcustom org-roam-find-file-hook nil
"Hook run when an Org-roam file is visited."
:group 'org-roam
:type 'hook)
(defcustom org-roam-post-node-insert-hook nil
"Hook run when an Org-roam node is inserted as an Org link.
Each function takes two arguments: the id of the node, and the link description."
:group 'org-roam
:type 'hook)
(defcustom org-roam-file-extensions '("org")
"Detected file extensions to include in the Org-roam ecosystem.
While the file extensions may be different, the file format needs
to be an `org-mode' file, and it is the user's responsibility to
ensure that."
"List of file extensions to be included by Org-Roam.
While a file extension different from \".org\" may be used, the
file still needs to be an `org-mode' file, and it is the user's
responsibility to ensure that."
:type '(repeat string)
:group 'org-roam)
;;;; Dynamic variables
(defvar org-roam-last-window nil
"Last window `org-roam' was called from.")
(defcustom org-roam-file-exclude-regexp (list org-attach-id-dir)
"Files matching this regular expression or list of regular expressions are excluded from the Org-roam."
:type '(choice
(repeat
(string :tag "Regular expression matching files to ignore"))
(string :tag "Regular expression matching files to ignore")
(const :tag "Include everything" nil))
:group 'org-roam)
;;; Utilities
;;;; General Utilities
(defun org-roam--plist-to-alist (plist)
"Return an alist of the property-value pairs in PLIST."
(let (res)
(while plist
(let ((prop (intern (substring (symbol-name (pop plist)) 1 nil)))
(val (pop plist)))
(push (cons prop val) res)))
res))
(defcustom org-roam-list-files-commands
(if (member system-type '(windows-nt ms-dos cygwin))
nil
'(find fd fdfind rg))
"Commands that will be used to find Org-roam files.
(defun org-roam--aliases-str-to-list (str)
"Function to transform string STR into list of alias titles.
It should be a list of symbols or cons cells representing any of
the following supported file search methods.
This snippet is obtained from ox-hugo:
https://github.com/kaushalmodi/ox-hugo/blob/a80b250987bc770600c424a10b3bca6ff7282e3c/ox-hugo.el#L3131"
(when (stringp str)
(let* ((str (org-trim str))
(str-list (split-string str "\n"))
ret)
(dolist (str-elem str-list)
(let* ((format-str ":dummy '(%s)") ;The :dummy key is discarded in the `lst' var below.
(alist (org-babel-parse-header-arguments (format format-str str-elem)))
(lst (cdr (car alist)))
(str-list2 (mapcar (lambda (elem)
(cond
((symbolp elem)
(symbol-name elem))
(t
elem)))
lst)))
(setq ret (append ret str-list2))))
ret)))
The commands will be tried in order until an executable for a
command is found. The Elisp implementation is used if no command
in the list is found.
;;;; File functions and predicates
(defun org-roam--touch-file (path)
"Touches an empty file at PATH."
(make-directory (file-name-directory path) t)
(f-touch path))
`find'
Use find as the file search method.
Example command:
find /path/to/dir -type f \
\( -name \"*.org\" -o -name \"*.org.gpg\" -name \"*.org.age\" \)
`fd'
Use fd as the file search method.
Example command:
fd /path/to/dir/ --type file -e \".org\" -e \".org.gpg\" -e \".org.age\"
`fdfind'
Same as `fd'. It's an alias that used in some OSes (e.g. Debian, Ubuntu)
`rg'
Use ripgrep as the file search method.
Example command:
rg /path/to/dir/ --files -g \"*.org\" -g \"*.org.gpg\" -g \"*.org.age\"
By default, `executable-find' will be used to look up the path to
the executable. If a custom path is required, it can be specified
together with the method symbol as a cons cell. For example:
\\='(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
(defun org-roam-file-p (&optional file)
"Return t if FILE is an Org-roam file, nil otherwise.
If FILE is not specified, use the current buffer's file-path.
FILE is an Org-roam file if:
- It's located somewhere under `org-roam-directory'
- It has a matching file extension (`org-roam-file-extensions')
- It doesn't match excluded regexp (`org-roam-file-exclude-regexp')"
(when (or file (buffer-file-name (buffer-base-buffer)))
(let* ((path (or file (buffer-file-name (buffer-base-buffer))))
(relative-path (file-relative-name path org-roam-directory))
(ext (org-roam--file-name-extension path))
(ext (if (or (string= ext "gpg")
(string= ext "age"))
(org-roam--file-name-extension (file-name-sans-extension path))
ext))
(org-roam-dir-p (org-roam-descendant-of-p path org-roam-directory))
(valid-file-ext-p (member ext org-roam-file-extensions))
(match-exclude-regexp-p
(cond
((not org-roam-file-exclude-regexp) nil)
((stringp org-roam-file-exclude-regexp)
(string-match-p org-roam-file-exclude-regexp relative-path))
((listp org-roam-file-exclude-regexp)
(let (is-match)
(dolist (exclude-re org-roam-file-exclude-regexp)
(setq is-match (or is-match (string-match-p exclude-re relative-path))))
is-match)))))
(save-match-data
(and
path
org-roam-dir-p
valid-file-ext-p
(not match-exclude-regexp-p))))))
;;;###autoload
(defun org-roam-list-files ()
"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
part of Org-Roam."
(org-roam--list-files (expand-file-name org-roam-directory)))
(defun org-roam-buffer-p (&optional buffer)
"Return t if BUFFER is for an Org-roam file.
If BUFFER is not specified, use the current buffer."
(let ((buffer (or buffer (current-buffer)))
path)
(with-current-buffer buffer
(and (derived-mode-p 'org-mode)
(setq path (buffer-file-name (buffer-base-buffer)))
(org-roam-file-p path)))))
(defun org-roam-buffer-list ()
"Return a list of buffers that are Org-roam files."
(--filter (org-roam-buffer-p it)
(buffer-list)))
(defun org-roam--file-name-extension (filename)
"Return file name extension for FILENAME.
@ -154,500 +263,99 @@ Like `file-name-extension', but does not strip version number."
(not (eq 0 (match-beginning 0))))
(substring file (+ (match-beginning 0) 1))))))
(defun org-roam--org-file-p (path)
"Check if PATH is pointing to an org file."
(let ((ext (org-roam--file-name-extension path)))
(when (string= ext "gpg") ; Handle encrypted files
(setq ext (org-roam--file-name-extension (file-name-sans-extension path))))
(member ext org-roam-file-extensions)))
(defun org-roam--org-roam-file-p (&optional file)
"Return t if FILE is part of Org-roam system, nil otherwise.
If FILE is not specified, use the current buffer's file-path."
(if-let ((path (or file
(buffer-file-name))))
(save-match-data
(org-roam--org-file-p path)
(f-descendant-of-p (file-truename path)
(file-truename org-roam-directory)))))
(defun org-roam--list-files (dir)
"Return all Org-roam files located within DIR, at any nesting level.
Ignores hidden files and directories."
(let ((regex (concat "\\.\\(?:"(mapconcat #'regexp-quote org-roam-file-extensions "\\|" )"\\)\\(?:\\.gpg\\)?\\'"))
result)
(dolist (file (directory-files-recursively dir regex) result)
(when (and (file-readable-p file) (org-roam--org-file-p file))
(push file result)))))
"Return all Org-roam files located recursively within DIR.
Use external shell commands if defined in `org-roam-list-files-commands'."
(let (path exe)
(cl-dolist (cmd org-roam-list-files-commands)
(pcase cmd
(`(,e . ,path)
(setq path (executable-find path)
exe (symbol-name e)))
((pred symbolp)
(setq path (executable-find (symbol-name cmd))
exe (symbol-name cmd)))
(wrong-type
(signal 'wrong-type-argument
`((consp symbolp)
,wrong-type))))
(when path (cl-return)))
(if-let* ((files (when path
(let ((fn (intern (concat "org-roam--list-files-" exe))))
(unless (fboundp fn) (user-error "%s is not an implemented search method" fn))
(funcall fn path (format "\"%s\"" dir)))))
(files (seq-filter #'org-roam-file-p files))
(files (mapcar #'expand-file-name files))) ; canonicalize names
files
(org-roam--list-files-elisp dir))))
(defun org-roam--list-all-files ()
"Return a list of all Org-roam files within `org-roam-directory'."
(org-roam--list-files (file-truename org-roam-directory)))
(defun org-roam--shell-command-files (cmd)
"Run CMD in the shell and return a list of files.
If no files are found, an empty list is returned."
(--> cmd
(shell-command-to-string it)
(ansi-color-filter-apply it)
(split-string it "\n")
(seq-filter (lambda (s)
(not (or (null s) (string= "" s)))) it)))
;;;; Org extraction functions
(defun org-roam--extract-global-props (props)
"Extract PROPS from the current org buffer.
The search terminates when the first property is encountered."
(let ((buf (org-element-parse-buffer))
res)
(dolist (prop props)
(let ((p (org-element-map buf 'keyword
(lambda (kw)
(when (string= (org-element-property :key kw) prop)
(org-element-property :value kw)))
:first-match t)))
(push (cons prop p) res)))
res))
(defun org-roam--list-files-search-globs (exts)
"Given EXTS, return a list of search globs.
E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
(cl-loop for e in exts
append (list (format "\"*.%s\"" e)
(format "\"*.%s.gpg\"" e)
(format "\"*.%s.age\"" e))))
(defun org-roam--extract-links (&optional file-path)
"Extracts all link items within the current buffer.
Link items are of the form:
(defun org-roam--list-files-find (executable dir)
"Return all Org-roam files under DIR, using \"find\", provided as EXECUTABLE."
(let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions))
(names (string-join (mapcar (lambda (glob) (concat "-name " glob)) globs) " -o "))
(command (string-join `(,executable "-L" ,dir "-type f \\(" ,names "\\)") " ")))
(org-roam--shell-command-files command)))
[from to type properties]
(defun org-roam--list-files-fd (executable dir)
"Return all Org-roam files under DIR, using \"fd\", provided as EXECUTABLE."
(let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions))
(extensions (string-join (mapcar (lambda (glob) (concat "-e " (substring glob 2 -1))) globs) " "))
(command (string-join `(,executable "-L" "--type file" ,extensions "." ,dir) " ")))
(org-roam--shell-command-files command)))
This is the format that emacsql expects when inserting into the database.
FILE-FROM is typically the buffer file path, but this may not exist, for example
in temp buffers. In cases where this occurs, we do know the file path, and pass
it as FILE-PATH."
(let ((file-path (or file-path
(file-truename (buffer-file-name)))))
(org-element-map (org-element-parse-buffer) 'link
(lambda (link)
(let* ((type (org-element-property :type link))
(path (org-element-property :path link))
(start (org-element-property :begin link))
(link-type (cond ((and (string= type "file")
(org-roam--org-file-p path))
"roam")
((and
(require 'org-ref nil t)
(-contains? org-ref-cite-types type))
"cite")
(t nil))))
(when link-type
(goto-char start)
(let* ((element (org-element-at-point))
(begin (or (org-element-property :content-begin element)
(org-element-property :begin element)))
(content (or (org-element-property :raw-value element)
(buffer-substring
begin
(or (org-element-property :content-end element)
(org-element-property :end element)))))
(content (string-trim content)))
(vector file-path
(cond ((string= link-type "roam")
(file-truename (expand-file-name path (file-name-directory file-path))))
((string= link-type "cite")
path))
link-type
(list :content content :point begin)))))))))
(defalias 'org-roam--list-files-fdfind #'org-roam--list-files-fd)
(defun org-roam--extract-titles ()
"Extract the titles from current buffer.
Titles are obtained via the #+TITLE property, or aliases
specified via the #+ROAM_ALIAS property."
(let* ((props (org-roam--extract-global-props '("TITLE" "ROAM_ALIAS")))
(aliases (cdr (assoc "ROAM_ALIAS" props)))
(title (cdr (assoc "TITLE" props)))
(alias-list (org-roam--aliases-str-to-list aliases)))
(if title
(cons title alias-list)
alias-list)))
(defun org-roam--list-files-rg (executable dir)
"Return all Org-roam files under DIR, using \"rg\", provided as EXECUTABLE."
(let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions))
(command (string-join `(
,executable "-L" ,dir "--files"
,@(mapcar (lambda (glob) (concat "-g " glob)) globs)) " ")))
(org-roam--shell-command-files command)))
(defun org-roam--extract-ref ()
"Extract the ref from current buffer."
(cdr (assoc "ROAM_KEY" (org-roam--extract-global-props '("ROAM_KEY")))))
;;;; Title/Path/Slug conversion
(defun org-roam--path-to-slug (path)
"Return a slug from PATH."
(-> path
(file-relative-name (file-truename org-roam-directory))
(file-name-sans-extension)))
(declare-function org-roam--directory-files-recursively "org-roam-compat")
(defun org-roam--get-title-or-slug (path)
"Convert `PATH' to the file title, if it exists. Else, return the path."
(or (car (org-roam-db--get-titles path))
(org-roam--path-to-slug path)))
(defun org-roam--list-files-elisp (dir)
"Return all Org-roam files under DIR, using Elisp based implementation."
(let ((regex (concat "\\.\\(?:"(mapconcat
#'regexp-quote org-roam-file-extensions
"\\|" )"\\)\\(?:\\.gpg\\|\\.age\\)?\\'"))
result)
(dolist (file (org-roam--directory-files-recursively dir regex nil nil t) result)
(when (and (file-readable-p file)
(org-roam-file-p file))
(push file result)))))
(defun org-roam--title-to-slug (title)
"Convert TITLE to a filename-suitable slug."
(cl-flet* ((nonspacing-mark-p (char)
(eq 'Mn (get-char-code-property char 'general-category)))
(strip-nonspacing-marks (s)
(apply #'string (seq-remove #'nonspacing-mark-p
(ucs-normalize-NFD-string s))))
(cl-replace (title pair)
(replace-regexp-in-string (car pair) (cdr pair) title)))
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
("__*" . "_") ;; remove sequential underscores
("^_" . "") ;; remove starting underscore
("_$" . ""))) ;; remove ending underscore
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
(s-downcase slug))))
;;; Interactive Commands
;;;; org-roam-insert
(defun org-roam--format-link-title (title)
"Return the link title, given the file TITLE."
(if (functionp org-roam-link-title-format)
(funcall org-roam-link-title-format title)
(format org-roam-link-title-format title)))
(defun org-roam--format-link (target &optional description)
"Formats an org link for a given file TARGET and link DESCRIPTION."
(let* ((here (ignore-errors
(-> (or (buffer-base-buffer)
(current-buffer))
(buffer-file-name)
(file-truename)
(file-name-directory)))))
(org-link-make-string
(concat "file:" (if here
(file-relative-name target here)
target))
description)))
(defun org-roam-insert (prefix &optional filter-fn)
"Find an Org-roam file, and insert a relative org link to it at point.
If PREFIX, downcase the title before insertion.
FILTER-FN is the name of a function to apply on the candidates
which takes as its argument an alist of path-completions. See
`org-roam--get-title-path-completions' for details."
(interactive "P")
(let* ((region (and (region-active-p)
;; following may lose active region, so save it
(cons (region-beginning) (region-end))))
(region-text (when region
(buffer-substring-no-properties
(car region) (cdr region))))
(completions (--> (org-roam--get-title-path-completions)
(if filter-fn
(funcall filter-fn it)
it)))
(title (org-roam-completion--completing-read "File: " completions
:initial-input region-text))
(region-or-title (or region-text title))
(target-file-path (cdr (assoc title completions)))
(link-description (org-roam--format-link-title (if prefix
(downcase region-or-title)
region-or-title))))
(if (and target-file-path
(file-exists-p target-file-path))
(progn
(when region ;; Remove previously selected text.
(delete-region (car region) (cdr region)))
(insert (org-roam--format-link target-file-path link-description)))
(when (org-roam-capture--in-process-p)
(user-error "Nested Org-roam capture processes not supported"))
(let ((org-roam-capture--info (list (cons 'title title)
(cons 'slug (org-roam--title-to-slug title))))
(org-roam-capture--context 'title))
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--insert-link-h)
(setq org-roam-capture-additional-template-props (list :region region
:link-description link-description
:capture-fn 'org-roam-insert))
(org-roam--capture)))))
;;;; org-roam-find-file
(defun org-roam--get-title-path-completions ()
"Return a list of cons pairs for titles to absolute path of Org-roam files."
(let* ((rows (org-roam-db-query [:select [file titles] :from titles]))
res)
(dolist (row rows)
(let ((file-path (car row))
(titles (cadr row)))
(if titles
(dolist (title titles)
(push (cons title file-path) res))
(push (cons (org-roam--path-to-slug file-path)
file-path) res))))
res))
(defun org-roam-find-file (&optional initial-prompt filter-fn)
"Find and open an Org-roam file.
INITIAL-PROMPT is the initial title prompt.
FILTER-FN is the name of a function to apply on the candidates
which takes as its argument an alist of path-completions. See
`org-roam--get-title-path-completions' for details."
(interactive)
(let* ((completions (--> (org-roam--get-title-path-completions)
(if filter-fn
(funcall filter-fn it)
it)))
(title (org-roam-completion--completing-read "File: " completions
:initial-input initial-prompt))
(file-path (cdr (assoc title completions))))
(if file-path
(find-file file-path)
(if (org-roam-capture--in-process-p)
(user-error "Org-roam capture in process")
(let ((org-roam-capture--info (list (cons 'title title)
(cons 'slug (org-roam--title-to-slug title))))
(org-roam-capture--context 'title))
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h)
(org-roam--capture))))))
;;;; org-roam-find-directory
(defun org-roam-find-directory ()
"Find and open `org-roam-directory'."
(interactive)
(find-file org-roam-directory))
;;;; org-roam-find-ref
(defun org-roam--get-ref-path-completions ()
"Return a list of cons pairs for refs to absolute path of Org-roam files."
(let ((rows (org-roam-db-query [:select [ref file] :from refs])))
(mapcar (lambda (row)
(cons (car row)
(cadr row))) rows)))
(defun org-roam-find-ref (&optional info)
"Find and open an Org-roam file from a ref.
INFO is an alist containing additional information."
(interactive)
(let* ((completions (org-roam--get-ref-path-completions))
(ref (or (cdr (assoc 'ref info))
(org-roam-completion--completing-read "Ref: "
completions
:require-match t))))
(find-file (cdr (assoc ref completions)))))
;;;; org-roam-switch-to-buffer
(defun org-roam--get-roam-buffers ()
"Return a list of buffers that are Org-roam files."
(--filter (and (with-current-buffer it (derived-mode-p 'org-mode))
(buffer-file-name it)
(org-roam--org-roam-file-p (buffer-file-name it)))
(buffer-list)))
(defun org-roam-switch-to-buffer ()
"Switch to an existing Org-roam buffer."
(interactive)
(let* ((roam-buffers (org-roam--get-roam-buffers))
(names-and-buffers (mapcar (lambda (buffer)
(cons (or (org-roam--get-title-or-slug
(buffer-file-name buffer))
(buffer-name buffer))
buffer))
roam-buffers)))
(unless roam-buffers
(user-error "No roam buffers"))
(when-let ((name (org-roam-completion--completing-read "Buffer: " names-and-buffers
:require-match t)))
(switch-to-buffer (cdr (assoc name names-and-buffers))))))
(defun org-roam--file-path-from-id (id)
"The file path for an Org-roam file, with identifier ID."
(file-truename
(expand-file-name
(if org-roam-encrypt-files
(concat id ".org.gpg")
(concat id ".org"))
org-roam-directory)))
;;; The org-roam buffer
;;;; org-roam-link-face
(defface org-roam-link
'((t :inherit org-link))
"Face for org-roam link."
:group 'org-roam-faces)
(defface org-roam-backlink
'((t :inherit org-block))
"Face for org-roam backlinks in backlinks buffer"
:group 'org-roam-faces)
(defun org-roam--roam-link-face (path)
"Conditional face for org file links.
Applies `org-roam-link-face' if PATH corresponds to a Roam file."
(if (org-roam--org-roam-file-p path)
'org-roam-link
'org-link))
;;;; org-roam-backlinks-mode
(defvar org-roam-backlinks-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [mouse-1] 'org-open-at-point)
(define-key map (kbd "RET") 'org-open-at-point)
map)
"Keymap for `org-roam-backlinks-mode'.")
(define-minor-mode org-roam-backlinks-mode
"Minor mode for the `org-roam-buffer'.
\\{org-roam-backlinks-mode-map}"
:lighter " Backlinks"
:keymap org-roam-backlinks-mode-map
(if org-roam-backlinks-mode
(add-hook 'org-open-at-point-functions
'org-roam-open-at-point nil 'local)
(remove-hook 'org-open-at-point-functions
'org-roam-open-at-point 'local)))
(defun org-roam-open-at-point ()
"Open an Org-roam link or visit the text previewed at point.
When point is on an Org-roam link, open the link in the Org-roam window.
When point is on the Org-roam preview text, open the link in the Org-roam
window, and navigate to the point.
This function hooks into `org-open-at-point' via `org-open-at-point-functions'."
(cond
;; Org-roam link
((let* ((context (org-element-context))
(type (org-element-property :type context))
(path (org-element-property :path context)))
(when (and (eq (org-element-type context) 'link)
(string= "file" type)
(org-roam--org-roam-file-p (file-truename path)))
(org-roam--find-file path)
(org-show-context)
t)))
;; Org-roam preview text
((when-let ((file-from (get-text-property (point) 'file-from))
(p (get-text-property (point) 'file-from-point)))
(org-roam--find-file file-from)
(goto-char p)
(org-show-context)
t))
;; If called via `org-open-at-point', fall back to default behavior.
(t nil)))
(defun org-roam--find-file (file)
"Open FILE in the window `org-roam' was called from."
(if (and org-roam-last-window (window-valid-p org-roam-last-window))
(progn (with-selected-window org-roam-last-window
(find-file file))
(select-window org-roam-last-window))
(find-file file)))
(defun org-roam--get-backlinks (target)
"Return the backlinks for TARGET.
TARGET may be a file, for Org-roam file links, or a citation key,
for Org-ref cite links."
(org-roam-db-query [:select [from, to, properties] :from links
:where (= to $s1)
:order-by (asc from)]
target))
(defun org-roam-store-link ()
"Store a link to an `org-roam' file."
(when (org-before-first-heading-p)
(when-let ((title (cdr (assoc "TITLE" (org-roam--extract-global-props '("TITLE"))))))
(org-link-store-props
:type "file"
:link (format "file:%s" (abbreviate-file-name buffer-file-name))
:description title))))
;;;###autoload
(defalias 'org-roam 'org-roam-buffer-toggle-display)
;;; The global minor org-roam-mode
(defvar org-roam-mode-map
(make-sparse-keymap)
"Keymap for mode `org-roam-mode'.")
;;;###autoload
(define-minor-mode org-roam-mode
"Minor mode for Org-roam.
This mode sets up several hooks, to ensure that the cache is updated on file
changes, renames and deletes. It is also in charge of graceful termination of
the database connection.
When called interactively, toggle `org-roam-mode'. with prefix
ARG, enable `org-roam-mode' if ARG is positive, otherwise disable
it.
When called from Lisp, enable `org-roam-mode' if ARG is omitted,
nil, or positive. If ARG is `toggle', toggle `org-roam-mode'.
Otherwise, behave as if called interactively."
:lighter " Org-roam"
:keymap org-roam-mode-map
:group 'org-roam
:require 'org-roam
:global t
(cond
(org-roam-mode
(org-roam-db-build-cache)
(add-hook 'find-file-hook #'org-roam--find-file-hook-function)
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
(advice-add 'rename-file :after #'org-roam--rename-file-advice)
(advice-add 'delete-file :before #'org-roam--delete-file-advice))
(t
(remove-hook 'find-file-hook #'org-roam--find-file-hook-function)
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
(advice-remove 'rename-file #'org-roam--rename-file-advice)
(advice-remove 'delete-file #'org-roam--delete-file-advice)
(org-roam-db--close-all)
;; Disable local hooks for all org-roam buffers
(dolist (buf (org-roam--get-roam-buffers))
(with-current-buffer buf
(org-link-set-parameters "file" :face 'org-link)
(remove-hook 'post-command-hook #'org-roam-buffer--update-maybe t)
(remove-hook 'after-save-hook #'org-roam-db--update-file t))))))
(defun org-roam--find-file-hook-function ()
"Called by `find-file-hook' when mode `org-roam-mode' is on."
(when (org-roam--org-roam-file-p)
(setq org-roam-last-window (get-buffer-window))
(add-hook 'post-command-hook #'org-roam-buffer--update-maybe nil t)
(add-hook 'after-save-hook #'org-roam-db--update-file nil t)
(org-link-set-parameters "file" :face 'org-roam--roam-link-face :store #'org-roam-store-link)
(org-roam-buffer--update-maybe :redisplay t)))
(defun org-roam--delete-file-advice (file &optional _trash)
"Advice for maintaining cache consistency when FILE is deleted."
(when (and (not (auto-save-file-name-p file))
(org-roam--org-roam-file-p file))
(org-roam-db--clear-file (file-truename file))))
(defun org-roam--rename-file-advice (file new-file &rest _args)
"Rename backlinks of FILE to refer to NEW-FILE."
(when (and (not (auto-save-file-name-p file))
(not (auto-save-file-name-p new-file))
(org-roam--org-roam-file-p new-file))
(org-roam-db--ensure-built)
(let* ((files-to-rename (org-roam-db-query [:select :distinct [from]
:from links
:where (= to $s1)
:and (= type $s2)]
file
"roam"))
(path (file-truename file))
(new-path (file-truename new-file))
(slug (org-roam--get-title-or-slug file))
(old-title (org-roam--format-link-title slug))
(new-slug (or (car (org-roam-db--get-titles path))
(org-roam--path-to-slug new-path)))
(new-title (org-roam--format-link-title new-slug)))
(org-roam-db--clear-file file)
(dolist (file-from files-to-rename)
(let* ((file-from (car file-from))
(file-from (if (string-equal (file-truename file-from)
path)
new-path
file-from))
(file-dir (file-name-directory file-from))
(relative-path (file-relative-name new-path file-dir))
(old-relative-path (file-relative-name path file-dir))
(slug-regex (regexp-quote (format "[[file:%s][%s]]" old-relative-path old-title)))
(named-regex (concat
(regexp-quote (format "[[file:%s][" old-relative-path))
"\\(.*\\)"
(regexp-quote "]]"))))
(with-temp-file file-from
(insert-file-contents file-from)
(while (re-search-forward slug-regex nil t)
(replace-match (format "[[file:%s][%s]]" relative-path new-title)))
(goto-char (point-min))
(while (re-search-forward named-regex nil t)
(replace-match (format "[[file:%s][\\1]]" relative-path))))
(org-roam-db--update-file file-from)))
(org-roam-db--update-file new-path))))
;;; -
;;; Package bootstrap
(provide 'org-roam)
;;; org-roam.el ends here
;; Local Variables:
;; outline-regexp: ";;;+ "
;; End:
(cl-eval-when (load eval)
(require 'org-roam-compat)
(require 'org-roam-utils)
(require 'org-roam-db)
(require 'org-roam-node)
(require 'org-roam-id)
(require 'org-roam-capture)
(require 'org-roam-mode)
(require 'org-roam-log)
(require 'org-roam-migrate))
;;; org-roam.el ends here

View File

@ -1,2 +0,0 @@
#+ROAM_ALIAS: "a1" "a 2"
#+TITLE: t1

View File

@ -1,3 +1,6 @@
#+TITLE: Bar
:PROPERTIES:
:ID: 440795d0-70c1-4165-993d-aebd5eef7a24
:END:
#+title: Bar
This is file bar. Bar links to [[file:nested/bar.org][Nested Bar]].
[[id:884b2341-b7fe-434d-848c-5282c0727861][Foo]]

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

@ -1,8 +1,4 @@
#+TITLE: Foo
This is the foo file. It contains a link to [[file:bar.org][Bar]].
To make the tests more robust, here are some arbitrary links:
- [[https:google.com][Google]]
- [[mailto:foo@john.com][mail to foo]]
:PROPERTIES:
:ID: 884b2341-b7fe-434d-848c-5282c0727861
:END:
#+title: Foo

View File

View File

@ -1,3 +0,0 @@
#+TITLE: Nested Bar
This file is nested, 1 level deeper. It links to both [[file:../foo.org][Foo]] and [[file:foo.org][Nested Foo]].

View File

@ -1,3 +0,0 @@
#+TITLE: Nested Foo
This file has no links.

View File

@ -1,3 +0,0 @@
no title in this file :O
links to itself, with no title: [[file:no-title.org][no-title]]

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,7 @@
:PROPERTIES:
:ID: 53fadc75-f48e-461e-be06-44a1e88b2abe
:ROAM_EXCLUDE: t
:END:
#+TITLE: Excluded by Org-roam
This node is excluded by declaring ~ROAM_EXCLUDE: t~.

View File

@ -1,3 +0,0 @@
#+TITLE: Unlinked
Nothing links here :(

View File

@ -1 +0,0 @@
#+ROAM_KEY: https://google.com/

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

@ -0,0 +1,63 @@
;;; test-org-roam-capture.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-capture--fill-template"
(it "fills template without newline"
(expect
(org-roam-capture--fill-template "foo")
:to-equal "foo"))
(it "fills template ensuring newline"
(expect
(org-roam-capture--fill-template "foo" 'ensure-newline)
:to-equal "foo\n"))
(it "fills template with newline"
(expect
(org-roam-capture--fill-template "foo\n")
:to-equal "foo\n"))
(it "fills template with two newlines"
(expect
(org-roam-capture--fill-template "foo\n\n")
:to-equal "foo\n\n")
(expect
(org-roam-capture--fill-template "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"
(expect
(org-roam-capture--fill-template (lambda () "foo"))
:to-equal "foo")))
(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

@ -0,0 +1,64 @@
;;; test-org-roam-utils.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-whitespace-content"
(it "extracts whitespace correctly"
(expect
(org-roam-whitespace-content "foo")
:to-equal "")
(expect
(org-roam-whitespace-content "foo\n")
:to-equal "\n")
(expect
(org-roam-whitespace-content "foo\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)
;;; test-org-roam-utils.el ends here

View File

@ -1,9 +1,9 @@
;;; test-org-roam.el --- Tests for org-roam -*- lexical-binding: t; -*-
;;; test-org-roam.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup) (with-simulated-input))
;; 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
@ -19,291 +19,63 @@
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
;;;; Requirements
(require 'buttercup)
(require 'with-simulated-input)
(require 'org-roam)
(require 'dash)
(defun org-roam-test-abs-path (file-path)
"Get absolute FILE-PATH from `org-roam-directory'."
(file-truename (expand-file-name file-path org-roam-directory)))
(defvar root-directory default-directory)
(defun org-roam-test-find-new-file (path)
"PATH."
(let ((path (org-roam-test-abs-path path)))
(make-directory (file-name-directory path) t)
(find-file path)))
(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)
(defvar org-roam-test-directory (file-truename (concat default-directory "tests/roam-files"))
"Directory containing org-roam test org files.")
(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)
(defun org-roam-test-init ()
"."
(org-roam-db--close)
(let ((original-dir org-roam-test-directory)
(new-dir (expand-file-name (make-temp-name "org-roam") temporary-file-directory)))
(copy-directory original-dir new-dir)
(setq org-roam-directory new-dir)
(org-roam-mode +1)))
(setq org-roam-file-exclude-regexp (regexp-quote "family.org"))
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal nil)))
;;; Tests
(describe "org-roam-db-build-cache"
(it "initializes correctly"
(org-roam-test-init)
(org-roam-db-build-cache)
(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)))
;; Cache
(expect (caar (org-roam-db-query [:select (funcall count) :from files])) :to-be 8)
(expect (caar (org-roam-db-query [:select (funcall count) :from links])) :to-be 5)
(expect (caar (org-roam-db-query [:select (funcall count) :from titles])) :to-be 8)
(expect (caar (org-roam-db-query [:select (funcall count) :from titles
:where titles :is-null])) :to-be 2)
(expect (caar (org-roam-db-query [:select (funcall count) :from refs])) :to-be 1)
;; TODO Test files
;; Links
(expect (caar (org-roam-db-query [:select (funcall count) :from links
:where (= from $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 1)
(expect (caar (org-roam-db-query [:select (funcall count) :from links
:where (= from $s1)]
(org-roam-test-abs-path "nested/bar.org"))) :to-be 2)
;; Links -- File-to
(expect (caar (org-roam-db-query [:select (funcall count) :from links
:where (= to $s1)]
(org-roam-test-abs-path "nested/foo.org"))) :to-be 1)
(expect (caar (org-roam-db-query [:select (funcall count) :from links
:where (= to $s1)]
(org-roam-test-abs-path "nested/bar.org"))) :to-be 1)
(expect (caar (org-roam-db-query [:select (funcall count) :from links
:where (= to $s1)]
(org-roam-test-abs-path "unlinked.org"))) :to-be 0)
;; TODO Test titles
(expect (org-roam-db-query [:select * :from titles])
:to-have-same-items-as
(list (list (org-roam-test-abs-path "alias.org")
(list "t1" "a1" "a 2"))
(list (org-roam-test-abs-path "bar.org")
(list "Bar"))
(list (org-roam-test-abs-path "foo.org")
(list "Foo"))
(list (org-roam-test-abs-path "nested/bar.org")
(list "Nested Bar"))
(list (org-roam-test-abs-path "nested/foo.org")
(list "Nested Foo"))
(list (org-roam-test-abs-path "no-title.org") nil)
(list (org-roam-test-abs-path "web_ref.org") nil)
(list (org-roam-test-abs-path "unlinked.org")
(list "Unlinked"))))
(expect (org-roam-db-query [:select * :from refs])
:to-have-same-items-as
(list (list "https://google.com/" (org-roam-test-abs-path "web_ref.org"))))
;; Expect rebuilds to be really quick (nothing changed)
(expect (org-roam-db-build-cache)
:to-equal
(list :files 0 :links 0 :titles 0 :refs 0 :deleted 0))))
(describe "org-roam-insert"
(describe "org-roam-list-files"
(before-each
(org-roam-test-init)
(org-roam-db--clear)
(org-roam-db-build-cache))
(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))
(it "temp1 -> foo"
(let ((buf (org-roam-test-find-new-file "temp1.org")))
(with-current-buffer buf
(with-simulated-input
"Foo RET"
(org-roam-insert nil))))
(expect (buffer-string) :to-match (regexp-quote "file:foo.org")))
(after-all
(org-roam-db--close)
(delete-file org-roam-db-location))
(it "temp2 -> nested/foo"
(let ((buf (org-roam-test-find-new-file "temp2.org")))
(with-current-buffer buf
(with-simulated-input
"Nested SPC Foo RET"
(org-roam-insert nil))))
(expect (buffer-string) :to-match (regexp-quote "file:nested/foo.org")))
(it "gets files correctly"
(expect (length (org-roam-list-files)) :to-equal 9))
(it "nested/temp3 -> foo"
(let ((buf (org-roam-test-find-new-file "nested/temp3.org")))
(with-current-buffer buf
(with-simulated-input
"Foo RET"
(org-roam-insert nil))))
(expect (buffer-string) :to-match (regexp-quote "file:../foo.org")))
(it "respects org-roam-file-extensions"
(setq org-roam-file-extensions '("md"))
(expect (length (org-roam-list-files)) :to-equal 1)
(setq org-roam-file-extensions '("org" "md"))
(expect (length (org-roam-list-files)) :to-equal 10))
(it "a/b/temp4 -> nested/foo"
(let ((buf (org-roam-test-find-new-file "a/b/temp4.org")))
(with-current-buffer buf
(with-simulated-input
"Nested SPC Foo RET"
(org-roam-insert nil))))
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/foo.org"))))
(it "respects org-roam-file-exclude-regexp"
(setq org-roam-file-exclude-regexp (regexp-quote "foo.org"))
(expect (length (org-roam-list-files)) :to-equal 8)))
(describe "rename file updates cache"
(before-each
(org-roam-test-init)
(org-roam-db--clear)
(org-roam-db-build-cache))
(describe "org-roam--list-files-search-globs"
(it "foo -> new_foo"
(rename-file (org-roam-test-abs-path "foo.org")
(org-roam-test-abs-path "new_foo.org"))
;; Cache should be cleared of old file
(expect (caar (org-roam-db-query [:select (funcall count)
:from titles
:where (= file $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from refs
:where (= file $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from links
:where (= from $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
;; Cache should be updated
(expect (org-roam-db-query [:select [to]
:from links
:where (= from $s1)]
(org-roam-test-abs-path "new_foo.org"))
(it "returns the correct list of globs"
(expect (org-roam--list-files-search-globs org-roam-file-extensions)
:to-have-same-items-as
(list (list (org-roam-test-abs-path "bar.org"))))
(expect (org-roam-db-query [:select [from]
:from links
:where (= to $s1)]
(org-roam-test-abs-path "new_foo.org"))
:to-have-same-items-as
(list (list (org-roam-test-abs-path "nested/bar.org"))))
;; Links are updated
(expect (with-temp-buffer
(insert-file-contents (org-roam-test-abs-path "nested/bar.org"))
(buffer-string))
:to-match
(regexp-quote "[[file:../new_foo.org][Foo]]")))
(it "foo -> foo with spaces"
(rename-file (org-roam-test-abs-path "foo.org")
(org-roam-test-abs-path "foo with spaces.org"))
;; Cache should be cleared of old file
(expect (caar (org-roam-db-query [:select (funcall count)
:from titles
:where (= file $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from refs
:where (= file $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from links
:where (= from $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
;; Cache should be updated
(expect (org-roam-db-query [:select [to]
:from links
:where (= from $s1)]
(org-roam-test-abs-path "foo with spaces.org"))
:to-have-same-items-as
(list (list (org-roam-test-abs-path "bar.org"))))
(expect (org-roam-db-query [:select [from]
:from links
:where (= to $s1)]
(org-roam-test-abs-path "foo with spaces.org"))
:to-have-same-items-as
(list (list (org-roam-test-abs-path "nested/bar.org"))))
;; Links are updated
(expect (with-temp-buffer
(insert-file-contents (org-roam-test-abs-path "nested/bar.org"))
(buffer-string))
:to-match
(regexp-quote "[[file:../foo with spaces.org][Foo]]")))
(it "no-title -> meaningful-title"
(rename-file (org-roam-test-abs-path "no-title.org")
(org-roam-test-abs-path "meaningful-title.org"))
;; File has no forward links
(expect (caar (org-roam-db-query [:select (funcall count)
:from links
:where (= from $s1)]
(org-roam-test-abs-path "no-title.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from links
:where (= from $s1)]
(org-roam-test-abs-path "meaningful-title.org"))) :to-be 1)
;; Links are updated with the appropriate name
(expect (with-temp-buffer
(insert-file-contents (org-roam-test-abs-path "meaningful-title.org"))
(buffer-string))
:to-match
(regexp-quote "[[file:meaningful-title.org][meaningful-title]]")))
(it "web_ref -> hello"
(expect (org-roam-db-query
[:select [file] :from refs
:where (= ref $s1)]
"https://google.com/")
:to-equal
(list (list (org-roam-test-abs-path "web_ref.org"))))
(rename-file (org-roam-test-abs-path "web_ref.org")
(org-roam-test-abs-path "hello.org"))
(expect (org-roam-db-query
[:select [file] :from refs
:where (= ref $s1)]
"https://google.com/")
:to-equal (list (list (org-roam-test-abs-path "hello.org"))))
(expect (caar (org-roam-db-query
[:select [ref] :from refs
:where (= file $s1)]
(org-roam-test-abs-path "web_ref.org")))
:to-equal nil)))
(describe "delete file updates cache"
(before-each
(org-roam-test-init)
(org-roam-db--clear)
(org-roam-db-build-cache)
(sleep-for 1))
(it "delete foo"
(delete-file (org-roam-test-abs-path "foo.org"))
(expect (caar (org-roam-db-query [:select (funcall count)
:from titles
:where (= file $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from refs
:where (= file $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0)
(expect (caar (org-roam-db-query [:select (funcall count)
:from links
:where (= from $s1)]
(org-roam-test-abs-path "foo.org"))) :to-be 0))
(it "delete web_ref"
(expect (org-roam-db-query [:select * :from refs])
:to-have-same-items-as
(list (list "https://google.com/" (org-roam-test-abs-path "web_ref.org"))))
(delete-file (org-roam-test-abs-path "web_ref.org"))
(expect (org-roam-db-query [:select * :from refs])
:to-have-same-items-as
(list))))
'("\"*.org\"" "\"*.org.gpg\"" "\"*.org.age\""))))
(provide 'test-org-roam)