mirror of
https://github.com/org-roam/org-roam
synced 2025-08-03 12:27:23 -05:00
Compare commits
153 Commits
Author | SHA1 | Date | |
---|---|---|---|
89dfaef38b | |||
fc8638759b | |||
1958e035fc | |||
1ea7e3077c | |||
7ce95a286b | |||
c172951345 | |||
0786f73669 | |||
df4e903208 | |||
d099204129 | |||
031ee63bee | |||
fed577f805 | |||
2ff616fbd8 | |||
046822b512 | |||
cce9591c1c | |||
db4170a459 | |||
0037daaf3e | |||
888b5d1a67 | |||
ed272eaf56 | |||
551ff3b17e | |||
719594dfc7 | |||
b4b8d8c0ee | |||
0d51698839 | |||
7dc76b708b | |||
f3db974bcc | |||
bb08be4740 | |||
2490afe110 | |||
40b6c10d8a | |||
425d53d56d | |||
64e302c126 | |||
cad3518788 | |||
2a630476b3 | |||
9fd7c87b5b | |||
0b9fcbc97b | |||
e415610b05 | |||
3e186a8552 | |||
0b2218706d | |||
84334b7e16 | |||
3c52d581ae | |||
fdd834d9bf | |||
8e6938a39d | |||
a753ec097d | |||
43a5362ada | |||
a432539121 | |||
1ce760ccc7 | |||
76df9d1f3c | |||
74d714f789 | |||
6644cb27a9 | |||
94b826d759 | |||
edccf9be84 | |||
aa64cc9596 | |||
e93c77f6a5 | |||
2d1c5d78e8 | |||
f8b40a3109 | |||
7fdc7150cc | |||
8667e44187 | |||
2e94f55cc5 | |||
5c06471c3a | |||
b5436f3410 | |||
f7dc81e494 | |||
e73807efe1 | |||
1981dc3617 | |||
7d2f511251 | |||
74422df546 | |||
938c602faa | |||
45a6863e07 | |||
cdad2ee7f6 | |||
256fe73e7a | |||
f9228ce319 | |||
25c476791e | |||
78ee5c6814 | |||
3add6748ae | |||
e418037991 | |||
05f67901c6 | |||
c2e852e102 | |||
4e6f934690 | |||
d95d25615e | |||
7f453f3fff | |||
e435581215 | |||
917a325dd9 | |||
c386761914 | |||
171a8db32f | |||
bbac208fda | |||
fcefc1b1b4 | |||
0cd9b9e6d3 | |||
83a0b3d464 | |||
ed7d4f0a2e | |||
32557afdbf | |||
f144941dfb | |||
01843a6486 | |||
1f51ec91d5 | |||
2657f0b444 | |||
455f139d3e | |||
b2d9543fa2 | |||
c0871c42be | |||
007e76725c | |||
5483e65d5a | |||
b63ff2a7bb | |||
e8b4822a85 | |||
69116a4da4 | |||
3014c63d50 | |||
a073bcff5c | |||
b948cfbe37 | |||
3716817618 | |||
608feed855 | |||
6132155393 | |||
d8985aa245 | |||
61a544cebd | |||
ddaf7ec10e | |||
8318da895d | |||
9eaf91b801 | |||
3bb45afccb | |||
fee008cdfb | |||
36152590ad | |||
a69968fc12 | |||
d71675fb47 | |||
3782e88d50 | |||
b4f14eebae | |||
cce6a05630 | |||
cc3689f30f | |||
b179a5a1a6 | |||
9172001c11 | |||
c51cadfe25 | |||
f6950a9820 | |||
feb9179c9f | |||
f50d6e7376 | |||
65ea325071 | |||
62d311de22 | |||
c8a360afdd | |||
cebe77135a | |||
25d828c32e | |||
fd97c80a26 | |||
97a342fd3f | |||
d20480bb8d | |||
b163c900b8 | |||
0432b00485 | |||
ccfa97ec3a | |||
86e102d990 | |||
eed1df90f5 | |||
905564a7eb | |||
9f7a4a0b02 | |||
aafe4114c2 | |||
3e2716edf3 | |||
445e3594b2 | |||
6f5d65abd9 | |||
817d8036fb | |||
c17310f0de | |||
bf3ebe2121 | |||
47ad646d51 | |||
6263c3a956 | |||
69742c3d51 | |||
5b15159a2c | |||
c0c240b975 | |||
001de3a874 |
@ -4,6 +4,9 @@
|
|||||||
(elisp-lint-ignored-validators . ("byte-compile" "package-lint"))
|
(elisp-lint-ignored-validators . ("byte-compile" "package-lint"))
|
||||||
(elisp-lint-indent-specs . ((describe . 1)
|
(elisp-lint-indent-specs . ((describe . 1)
|
||||||
(it . 1)
|
(it . 1)
|
||||||
|
(thread-first . 0)
|
||||||
|
(cl-flet . 1)
|
||||||
|
(cl-flet* . 1)
|
||||||
(org-element-map . defun)
|
(org-element-map . defun)
|
||||||
(org-roam-dolist-with-progress . 2)
|
(org-roam-dolist-with-progress . 2)
|
||||||
(org-roam-with-temp-buffer . 1)
|
(org-roam-with-temp-buffer . 1)
|
||||||
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1,6 +1,6 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: [jethrokuan, zaeph]
|
github: [jethrokuan]
|
||||||
patreon: # Replace with a single Patreon username
|
patreon: # Replace with a single Patreon username
|
||||||
open_collective: # Replace with a single Open Collective username
|
open_collective: # Replace with a single Open Collective username
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -39,5 +39,3 @@ Example:
|
|||||||
### Environment
|
### Environment
|
||||||
|
|
||||||
<!-- Please M-x org-roam-diagnostics and paste results here -->
|
<!-- Please M-x org-roam-diagnostics and paste results here -->
|
||||||
|
|
||||||
- Org-roam commit: https://github.com/jethrokuan/org-roam/commit/commithashhere
|
|
||||||
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@ -4,7 +4,7 @@ name: "Docs"
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@ -28,7 +28,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -36,7 +36,11 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
emacs_version:
|
emacs_version:
|
||||||
- 27.1
|
# REVIEW: we do not yet have the bootstrapping in place to test
|
||||||
|
# versions of emacs without built-in sqlite (pre 29.1)
|
||||||
|
# - 27.2
|
||||||
|
# - 28.2
|
||||||
|
- 29.4
|
||||||
- snapshot
|
- snapshot
|
||||||
steps:
|
steps:
|
||||||
- uses: purcell/setup-emacs@master
|
- uses: purcell/setup-emacs@master
|
||||||
@ -46,7 +50,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Eldev
|
- name: Install Eldev
|
||||||
run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
|
run: curl -fsSL https://raw.github.com/org-roam/org-roam/master/github-eldev | sh
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: make prepare
|
run: make prepare
|
||||||
|
93
.github/workflows/tidy-issues.yml
vendored
Normal file
93
.github/workflows/tidy-issues.yml
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
name: 'Manage stale/dormant issues and PRs'
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 1 * * *' # Daily at 1 AM UTC
|
||||||
|
workflow_dispatch: # Allow this to be run manually
|
||||||
|
inputs:
|
||||||
|
dry_run:
|
||||||
|
description: 'Dry run: Show what would happen without making changes'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Handle stale issues/PRs
|
||||||
|
- name: Mark/close stale issues and PRs
|
||||||
|
uses: actions/stale@v9
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Dry run setting
|
||||||
|
debug-only: ${{ github.event.inputs.dry_run == 'true' }}
|
||||||
|
|
||||||
|
# Messages
|
||||||
|
stale-issue-message: |
|
||||||
|
📅 **Stale Issue Notice**
|
||||||
|
|
||||||
|
This issue has been automatically marked as stale because it has not had recent activity for **6 months**.
|
||||||
|
|
||||||
|
**⏰ This issue will be closed in 2 weeks** if no further activity occurs.
|
||||||
|
|
||||||
|
**To keep this issue open:**
|
||||||
|
- Comment on this issue
|
||||||
|
- Reference it in a commit or PR
|
||||||
|
- Add new information or updates
|
||||||
|
|
||||||
|
Thank you for your contributions to org-roam! 🙏
|
||||||
|
|
||||||
|
close-issue-message: |
|
||||||
|
🔒 **Issue Automatically Closed**
|
||||||
|
|
||||||
|
This issue was automatically closed due to **6 months of inactivity** followed by 2 weeks notice.
|
||||||
|
|
||||||
|
**To reopen:**
|
||||||
|
- If still relevant, comment below and we'll reopen
|
||||||
|
- Or create a new issue with updated information
|
||||||
|
|
||||||
|
If this issue is not reopened in 2 weeks, it will be locked.
|
||||||
|
|
||||||
|
This helps keep our issue tracker focused and manageable.
|
||||||
|
|
||||||
|
stale-pr-message: |
|
||||||
|
📅 **Stale Pull Request Notice**
|
||||||
|
|
||||||
|
This pull request has been automatically marked as stale because it has not had recent activity for **6 months**.
|
||||||
|
|
||||||
|
**⏰ This PR will be closed in 2 weeks** if no further activity occurs.
|
||||||
|
|
||||||
|
**To keep this PR open:**
|
||||||
|
- Push new commits
|
||||||
|
- Comment with updates
|
||||||
|
- Rebase on latest main branch
|
||||||
|
|
||||||
|
Thank you for your contributions to org-roam! 🙏
|
||||||
|
|
||||||
|
close-pr-message: |
|
||||||
|
🔒 **Pull Request Automatically Closed**
|
||||||
|
|
||||||
|
This pull request was automatically closed due to **6 months of inactivity** followed by 2 weeks notice.
|
||||||
|
|
||||||
|
# Timing (6 months + 2 weeks)
|
||||||
|
days-before-stale: 182 # ~6 months
|
||||||
|
days-before-close: 14 # 2 weeks notice
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
operations-per-run: 1000
|
||||||
|
|
||||||
|
# Show dry run summary
|
||||||
|
- name: Dry run summary
|
||||||
|
if: github.event.inputs.dry_run == 'true'
|
||||||
|
run: |
|
||||||
|
echo "🧪 DRY RUN COMPLETED"
|
||||||
|
echo "This was a dry run - no actual changes were made."
|
||||||
|
echo "Check the action logs above to see what would have happened."
|
||||||
|
echo ""
|
||||||
|
echo "To run for real:"
|
||||||
|
echo "1. Go to Actions tab"
|
||||||
|
echo "2. Click 'Run workflow'"
|
||||||
|
echo "3. Leave 'Dry run mode' unchecked"
|
||||||
|
echo "4. Click 'Run workflow'"
|
167
CHANGELOG.md
167
CHANGELOG.md
@ -1,6 +1,147 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2.2.0
|
## 2.3.1 (2025-06-26)
|
||||||
|
|
||||||
|
* (fix): Use correct type specifications to suppress warnings by @okomestudio in https://github.com/org-roam/org-roam/pull/2522
|
||||||
|
* perf: suppress extra org features in the temp buffer by @dustinfarris in https://github.com/org-roam/org-roam/pull/2524
|
||||||
|
|
||||||
|
## 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
|
### Added
|
||||||
- [#1806](https://github.com/org-roam/org-roam/pull/1806), [#2017](https://github.com/org-roam/org-roam/pull/2017) db: support caching and usage of Org 9.5's in-built citations
|
- [#1806](https://github.com/org-roam/org-roam/pull/1806), [#2017](https://github.com/org-roam/org-roam/pull/2017) db: support caching and usage of Org 9.5's in-built citations
|
||||||
- [#1963](https://github.com/org-roam/org-roam/pull/1963) db: cache file title into files table
|
- [#1963](https://github.com/org-roam/org-roam/pull/1963) db: cache file title into files table
|
||||||
@ -31,7 +172,8 @@
|
|||||||
- [#2016](https://github.com/org-roam/org-roam/pull/2016) db: fix node caching being affected by agenda variables
|
- [#2016](https://github.com/org-roam/org-roam/pull/2016) db: fix node caching being affected by agenda variables
|
||||||
- [#2033](https://github.com/org-roam/org-roam/pull/2023) db: respect local variables during db parsing
|
- [#2033](https://github.com/org-roam/org-roam/pull/2023) db: respect local variables during db parsing
|
||||||
|
|
||||||
## 2.1.0
|
## 2.1.0 (2021-08-20)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- [#1693](https://github.com/org-roam/org-roam/pull/1693) added `filter-fn` and `templates` parameter to `org-roam-capture`, `org-roam-node-find`, and `org-roam-node-insert`
|
- [#1693](https://github.com/org-roam/org-roam/pull/1693) added `filter-fn` and `templates` parameter to `org-roam-capture`, `org-roam-node-find`, and `org-roam-node-insert`
|
||||||
- [#1709](https://github.com/org-roam/org-roam/pull/1709) added ability to specify default value in org-roam capture templates
|
- [#1709](https://github.com/org-roam/org-roam/pull/1709) added ability to specify default value in org-roam capture templates
|
||||||
@ -61,7 +203,10 @@
|
|||||||
- [#1713](https://github.com/org-roam/org-roam/pull/1713) capture: check for file-existence before template insertion
|
- [#1713](https://github.com/org-roam/org-roam/pull/1713) capture: check for file-existence before template insertion
|
||||||
- [#1725](https://github.com/org-roam/org-roam/pull/1725) db: always compute hash of encrypted file to prevent re-processing of encrypted files
|
- [#1725](https://github.com/org-roam/org-roam/pull/1725) db: always compute hash of encrypted file to prevent re-processing of encrypted files
|
||||||
|
|
||||||
## 2.0.0
|
## 2.0.0 (2021-07-17)
|
||||||
|
|
||||||
|
A few symbols have been marked as obsolete. Have a look at the content of [org-roam-compat.el](https://github.com/org-roam/org-roam/blob/f819720c510185af713522c592833ec9f2934251/org-roam-compat.el#L159)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- [#1396](https://github.com/org-roam/org-roam/pull/1396) add option to choose between prepending, appending, and omitting `roam_tags` in file completion
|
- [#1396](https://github.com/org-roam/org-roam/pull/1396) add option to choose between prepending, appending, and omitting `roam_tags` in file completion
|
||||||
- [#1270](https://github.com/org-roam/org-roam/pull/1270) capture: create OLP if it does not exist. Removes need for OLP setup in `:head`.
|
- [#1270](https://github.com/org-roam/org-roam/pull/1270) capture: create OLP if it does not exist. Removes need for OLP setup in `:head`.
|
||||||
@ -88,7 +233,7 @@
|
|||||||
- [#1409](https://github.com/org-roam/org-roam/issues/1398) prevent inclusion of non-org-roam files in `org-roam-dailies--list-files`
|
- [#1409](https://github.com/org-roam/org-roam/issues/1398) prevent inclusion of non-org-roam files in `org-roam-dailies--list-files`
|
||||||
- [#1542](https://github.com/org-roam/org-roam/issues/1542) fix files not excluded when `org-roam-list-files-commands` is nil
|
- [#1542](https://github.com/org-roam/org-roam/issues/1542) fix files not excluded when `org-roam-list-files-commands` is nil
|
||||||
|
|
||||||
## 1.2.3 (13-11-2020)
|
## 1.2.3 (2020-11-13)
|
||||||
|
|
||||||
Primarily a stabilization and bug-fix release.
|
Primarily a stabilization and bug-fix release.
|
||||||
|
|
||||||
@ -119,7 +264,7 @@ Org-roam-dailies has also been revamped to include new features, see [this video
|
|||||||
- [#1233](https://github.com/org-roam/org-roam/issues/1233) fixes bug where descriptive file links become plain links during update for relative paths
|
- [#1233](https://github.com/org-roam/org-roam/issues/1233) fixes bug where descriptive file links become plain links during update for relative paths
|
||||||
- [#1252](https://github.com/org-roam/org-roam/issues/1252) respect original link type during automatic replacement
|
- [#1252](https://github.com/org-roam/org-roam/issues/1252) respect original link type during automatic replacement
|
||||||
|
|
||||||
## 1.2.2 (06-10-2020)
|
## 1.2.2 (2020-10-06)
|
||||||
|
|
||||||
In this release we support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`. Completion for these fuzzy links is supported via `completion-at-point`.
|
In this release we support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`. Completion for these fuzzy links is supported via `completion-at-point`.
|
||||||
|
|
||||||
@ -157,7 +302,7 @@ This change requires you to set `org-roam-directory` to the resolved path of a f
|
|||||||
- [#1057](https://github.com/org-roam/org-roam/pull/1057) Improve performance of database builds by preventing generation of LaTeX and image previews.
|
- [#1057](https://github.com/org-roam/org-roam/pull/1057) Improve performance of database builds by preventing generation of LaTeX and image previews.
|
||||||
- [#1103](https://github.com/org-roam/org-roam/pull/1103) Fix long build-times for Windows on files with URL links
|
- [#1103](https://github.com/org-roam/org-roam/pull/1103) Fix long build-times for Windows on files with URL links
|
||||||
|
|
||||||
## 1.2.1 (27-07-2020)
|
## 1.2.1 (2020-07-27)
|
||||||
|
|
||||||
This release consisted of a big deal of refactoring and bug fixes. Notably, we fixed several catastrophic failures on db builds with bad setups (#854), and modularized tag and title extractions.
|
This release consisted of a big deal of refactoring and bug fixes. Notably, we fixed several catastrophic failures on db builds with bad setups (#854), and modularized tag and title extractions.
|
||||||
|
|
||||||
@ -190,7 +335,7 @@ We also added some new features that had been a long time coming:
|
|||||||
- [#894](https://github.com/org-roam/org-roam/pull/894) Perform link fixes on all Org-roam files
|
- [#894](https://github.com/org-roam/org-roam/pull/894) Perform link fixes on all Org-roam files
|
||||||
- [#952](https://github.com/org-roam/org-roam/pull/952) Cache `${foo}` template variables so they do not need to be re-entered twice
|
- [#952](https://github.com/org-roam/org-roam/pull/952) Cache `${foo}` template variables so they do not need to be re-entered twice
|
||||||
|
|
||||||
## 1.2.0 (12-06-2020)
|
## 1.2.0 (2020-06-12)
|
||||||
|
|
||||||
In this release, we improved the linking process by achieving feature parity between links to files and links to headlines. Before, we used the `file:foo::*bar` format to link to the headline `bar` in file `foo`, but this was prone to breakage upon renaming the file or modifying the headline. This is not the case anymore. Now, we use `org-id` to create IDs for those headlines, which are then stored in our database to compute the relationships and jump around. Note that this will work even if you’re not using `org-id` in your global configuration for Org-mode.
|
In this release, we improved the linking process by achieving feature parity between links to files and links to headlines. Before, we used the `file:foo::*bar` format to link to the headline `bar` in file `foo`, but this was prone to breakage upon renaming the file or modifying the headline. This is not the case anymore. Now, we use `org-id` to create IDs for those headlines, which are then stored in our database to compute the relationships and jump around. Note that this will work even if you’re not using `org-id` in your global configuration for Org-mode.
|
||||||
|
|
||||||
@ -218,7 +363,7 @@ We also add `org-roam-unlinked-references`, which naively finds text that could
|
|||||||
- [#759](https://github.com/org-roam/org-roam/pull/759), [#760](https://github.com/org-roam/org-roam/pull/760) Tags are only added to the tags table if there are actually tags present
|
- [#759](https://github.com/org-roam/org-roam/pull/759), [#760](https://github.com/org-roam/org-roam/pull/760) Tags are only added to the tags table if there are actually tags present
|
||||||
- [#700](https://github.com/org-roam/org-roam/pull/700), [#733](https://github.com/org-roam/org-roam/pull/733) Allow symlinks within the `org-roam` directory
|
- [#700](https://github.com/org-roam/org-roam/pull/700), [#733](https://github.com/org-roam/org-roam/pull/733) Allow symlinks within the `org-roam` directory
|
||||||
|
|
||||||
## 1.1.1 (18-05-2020)
|
## 1.1.1 (2020-05-18)
|
||||||
|
|
||||||
In this release, we added two new features:
|
In this release, we added two new features:
|
||||||
|
|
||||||
@ -258,7 +403,7 @@ As usual, this release comes with a multitude of bug-fixes and refactorings.
|
|||||||
- [#606](https://github.com/org-roam/org-roam/pull/606) Added `org-roam-dev.el` for developer coding standards
|
- [#606](https://github.com/org-roam/org-roam/pull/606) Added `org-roam-dev.el` for developer coding standards
|
||||||
- [#622](https://github.com/org-roam/org-roam/pull/622) Online documentation now points to the Org-based documentation
|
- [#622](https://github.com/org-roam/org-roam/pull/622) Online documentation now points to the Org-based documentation
|
||||||
|
|
||||||
## 1.1.0 (21-04-2020)
|
## 1.1.0 (2020-04-21)
|
||||||
|
|
||||||
To the average user, this release is mainly a bugfix release with additional options to customize. However, the changes made to the source is significant. Most notably, in this release:
|
To the average user, this release is mainly a bugfix release with additional options to customize. However, the changes made to the source is significant. Most notably, in this release:
|
||||||
|
|
||||||
@ -296,7 +441,7 @@ In the coming months, you can expect work on bigger projects (e.g. revamping the
|
|||||||
- [#363](https://github.com/org-roam/org-roam/pull/363), [#473](https://github.com/org-roam/org-roam/pull/473) Modularize org-roam features.
|
- [#363](https://github.com/org-roam/org-roam/pull/363), [#473](https://github.com/org-roam/org-roam/pull/473) Modularize org-roam features.
|
||||||
- [#497](https://github.com/org-roam/org-roam/pull/497) Simplify `org-roam--list-files` implementation
|
- [#497](https://github.com/org-roam/org-roam/pull/497) Simplify `org-roam--list-files` implementation
|
||||||
|
|
||||||
## 1.0.0 (23-03-2020)
|
## 1.0.0 (2020-03-23)
|
||||||
|
|
||||||
Org-roam is now on MELPA! We have squashed most of the bugs, and Org-roam has
|
Org-roam is now on MELPA! We have squashed most of the bugs, and Org-roam has
|
||||||
been stable for the most part.
|
been stable for the most part.
|
||||||
@ -315,7 +460,7 @@ been stable for the most part.
|
|||||||
- [#293](https://github.com/org-roam/org-roam/pull/293) Fix capture templates not working as expected for `org-roam-find-file`
|
- [#293](https://github.com/org-roam/org-roam/pull/293) Fix capture templates not working as expected for `org-roam-find-file`
|
||||||
- [#275](https://github.com/org-roam/org-roam/pull/275) Fix database rebuild when `org-roam-directory` is set locally
|
- [#275](https://github.com/org-roam/org-roam/pull/275) Fix database rebuild when `org-roam-directory` is set locally
|
||||||
|
|
||||||
## 1.0.0-rc1 (06-03-2020)
|
## 1.0.0-rc1 (2020-03-06)
|
||||||
|
|
||||||
This is a pre-release before the push to MELPA. It contains large
|
This is a pre-release before the push to MELPA. It contains large
|
||||||
internal changes, with little user-facing changes. Most notably, the
|
internal changes, with little user-facing changes. Most notably, the
|
||||||
|
57
README.md
57
README.md
@ -47,30 +47,6 @@ Stable](https://stable.melpa.org/) using `package.el`:
|
|||||||
```
|
```
|
||||||
M-x package-install RET org-roam RET
|
M-x package-install RET org-roam RET
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
|
||||||
(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.
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Using `straight.el`
|
### Using `straight.el`
|
||||||
@ -177,9 +153,8 @@ dependencies. These include:
|
|||||||
- dash
|
- dash
|
||||||
- f
|
- f
|
||||||
- s
|
- s
|
||||||
- org (9.4 is the minimal required version!)
|
- org (9.6 is the minimum required version!)
|
||||||
- emacsql
|
- emacsql
|
||||||
- emacsql-sqlite
|
|
||||||
- magit-section
|
- magit-section
|
||||||
- filenotify-recursive
|
- filenotify-recursive
|
||||||
|
|
||||||
@ -198,6 +173,33 @@ 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.
|
system. Read the manual to find more details for how to install them manually.
|
||||||
</details>
|
</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
|
## Getting Started
|
||||||
|
|
||||||
[David Wilson](https://github.com/daviwil) of [System
|
[David Wilson](https://github.com/daviwil) of [System
|
||||||
@ -225,8 +227,9 @@ it has not already been addressed on [GitHub][issues] or on
|
|||||||
|
|
||||||
- [Jethro Kuan](https://braindump.jethro.dev/)
|
- [Jethro Kuan](https://braindump.jethro.dev/)
|
||||||
([Source](https://github.com/jethrokuan/braindump/tree/master/org))
|
([Source](https://github.com/jethrokuan/braindump/tree/master/org))
|
||||||
- [Alexey Shmalko](https://braindump.rasen.dev/)
|
- [Alexey Shmalko](https://www.alexeyshmalko.com/)
|
||||||
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
|
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
|
||||||
|
- [Martin Edström](https://edstrom.dev/)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
671
doc/org-roam.org
671
doc/org-roam.org
@ -1,23 +1,23 @@
|
|||||||
#+title: Org-roam User Manual
|
#+title: Org-roam User Manual
|
||||||
#+author: Jethro Kuan
|
#+author: Jethro Kuan
|
||||||
#+email: jethrokuan95@gmail.com
|
#+email: jethrokuan95@gmail.com
|
||||||
#+date: 2020-2022
|
#+date: 2020-2025
|
||||||
#+language: en
|
#+language: en
|
||||||
|
|
||||||
#+texinfo_deffn: t
|
#+texinfo_deffn: t
|
||||||
#+texinfo_dir_category: Emacs
|
#+texinfo_dir_category: Emacs
|
||||||
#+texinfo_dir_title: Org-roam: (org-roam).
|
#+texinfo_dir_title: Org-roam: (org-roam).
|
||||||
#+texinfo_dir_desc: Roam Research for Emacs.
|
#+texinfo_dir_desc: Roam Research for Emacs.
|
||||||
#+subtitle: for version 2.2.0
|
#+subtitle: for version 2.3.1
|
||||||
|
|
||||||
#+options: H:4 num:3 toc:nil creator:t ':t
|
#+options: H:4 num:3 toc:nil creator:t ':t
|
||||||
#+property: header-args :eval never
|
#+property: header-args :eval never
|
||||||
#+texinfo: @noindent
|
#+texinfo: @noindent
|
||||||
|
|
||||||
This manual is for Org-roam version 2.2.0.
|
This manual is for Org-roam version 2.3.1.
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
Copyright (C) 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
Copyright (C) 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
You can redistribute this document and/or modify it under the terms of the GNU
|
You can redistribute this document and/or modify it under the terms of the GNU
|
||||||
General Public License as published by the Free Software Foundation, either
|
General Public License as published by the Free Software Foundation, either
|
||||||
@ -134,7 +134,7 @@ A slip-box requires a method for quickly capturing ideas. These are called
|
|||||||
*fleeting notes*: they are simple reminders of information or ideas that will
|
*fleeting notes*: they are simple reminders of information or ideas that will
|
||||||
need to be processed later on, or trashed. This is typically accomplished using
|
need to be processed later on, or trashed. This is typically accomplished using
|
||||||
~org-capture~ (see info:org#Capture), or using Org-roam's daily notes
|
~org-capture~ (see info:org#Capture), or using Org-roam's daily notes
|
||||||
functionality (see [[*Org-roam Dailies][Org-roam Dailies]]). This provides a central inbox for collecting
|
functionality (see [[*org-roam-dailies][org-roam-dailies]]). This provides a central inbox for collecting
|
||||||
thoughts, to be processed later into permanent notes.
|
thoughts, to be processed later into permanent notes.
|
||||||
|
|
||||||
*Permanent notes*
|
*Permanent notes*
|
||||||
@ -178,18 +178,7 @@ archives to =package-archives=:
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Org-roam also depends on a recent version of Org, which can be obtained in Org's
|
Org-roam also depends on a recent version of Org, which can be obtained in Org's
|
||||||
package repository (see info:org#Installation). To use Org's ELPA archive:
|
package repository (see info:org#Installation).
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
Once you have added your preferred archive, you need to update the
|
|
||||||
local package list using:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
M-x package-refresh-contents RET
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
Once you have done that, you can install Org-roam and its dependencies
|
Once you have done that, you can install Org-roam and its dependencies
|
||||||
using:
|
using:
|
||||||
@ -235,7 +224,6 @@ dependencies that it requires. These include:
|
|||||||
- s
|
- s
|
||||||
- org
|
- org
|
||||||
- emacsql
|
- emacsql
|
||||||
- emacsql-sqlite
|
|
||||||
- magit-section
|
- magit-section
|
||||||
|
|
||||||
You can install this manually as well, or get the latest version from MELPA. You
|
You can install this manually as well, or get the latest version from MELPA. You
|
||||||
@ -279,40 +267,6 @@ file:
|
|||||||
install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir
|
install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Installation Troubleshooting
|
|
||||||
*** C Compiler
|
|
||||||
Org-roam relies on an Emacs package called ~emacsql~ and ~emacsql-sqlite~ to
|
|
||||||
work with the ~sqlite~ database. Both of them should be installed automatically
|
|
||||||
in your Emacs environment as a prerequisite for Org-roam when you install it.
|
|
||||||
|
|
||||||
~emacsql-sqlite~ requires a C compiler (e.g. ~gcc~ or ~clang~) to be present in
|
|
||||||
your computer. How to install a C compiler depends on the OS that you use.
|
|
||||||
|
|
||||||
**** C Compiler for Windows
|
|
||||||
|
|
||||||
One of the easiest ways to install a C compiler in Windows is to use [[https://www.msys2.org/][MSYS2]] as at the time of this writing:
|
|
||||||
|
|
||||||
1. Download and use the installer in the official MSYS2 website
|
|
||||||
2. Run MSYS2 and in its terminal, type the following and answer "Y" to
|
|
||||||
proceed -- this will install ~gcc~ in your PC:
|
|
||||||
|
|
||||||
#+BEGIN_SRC bash
|
|
||||||
pacman -S gcc
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
4. On Windows, add ~C:\msys64\usr\bin~ (command =where gcc= in MSYS2 terminal
|
|
||||||
can tell you the correct path) to ~PATH~ in your environmental variables
|
|
||||||
|
|
||||||
5. Launch Emacs and call ~M-x org-roam-db-autosync-mode~ (launch Emacs after
|
|
||||||
defining the path, so that Emacs can recognize it)
|
|
||||||
|
|
||||||
This will automatically start compiling ~emacsql-sqlite~; you should see a
|
|
||||||
message in minibuffer. It may take a while until compilation completes. Once
|
|
||||||
complete, you should see a new file ~emacsql-sqlite.exe~ created in a subfolder
|
|
||||||
named ~sqlite~ under ~emacsql-sqlite~ installation folder. It's typically in
|
|
||||||
your Emacs configuration folder like this:
|
|
||||||
~/.config/emacs/elpa/emacsql-sqlite-20190727.1710/sqlite~
|
|
||||||
|
|
||||||
* Getting Started
|
* Getting Started
|
||||||
** The Org-roam Node
|
** The Org-roam Node
|
||||||
|
|
||||||
@ -369,7 +323,12 @@ For this tutorial, create an empty directory, and set ~org-roam-directory~:
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
The ~file-truename~ function is only necessary when you use symbolic links
|
The ~file-truename~ function is only necessary when you use symbolic links
|
||||||
inside ~org-roam-directory~: Org-roam does not resolve symbolic links.
|
inside ~org-roam-directory~: Org-roam does not resolve symbolic links. One can
|
||||||
|
however instruct Emacs to always resolve symlinks, at a performance cost:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq find-file-visit-truename t)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
Next, we setup Org-roam to run functions on file changes to maintain cache
|
Next, we setup Org-roam to run functions on file changes to maintain cache
|
||||||
consistency. This is achieved by running ~M-x org-roam-db-autosync-mode~. To
|
consistency. This is achieved by running ~M-x org-roam-db-autosync-mode~. To
|
||||||
@ -413,51 +372,58 @@ brought through the node creation process.
|
|||||||
One can also conveniently insert links via the completion-at-point functions
|
One can also conveniently insert links via the completion-at-point functions
|
||||||
Org-roam provides (see [[*Completion][Completion]]).
|
Org-roam provides (see [[*Completion][Completion]]).
|
||||||
|
|
||||||
|
** Customizing Node Completions
|
||||||
|
|
||||||
|
Node selection is achieved via the ~completing-read~ interface, typically
|
||||||
|
through ~org-roam-node-read~. The presentation of these nodes are governed by
|
||||||
|
~org-roam-node-display-template~.
|
||||||
|
|
||||||
|
- Variable: org-roam-node-display-template
|
||||||
|
|
||||||
|
Configures display formatting for Org-roam node.
|
||||||
|
|
||||||
|
Patterns of form "${field-name:length}" are interpolated based
|
||||||
|
on the current node.
|
||||||
|
|
||||||
|
Each "field-name" is replaced with the return value of each
|
||||||
|
corresponding accessor function for org-roam-node, e.g.
|
||||||
|
"${title}" will be interpolated by the result of
|
||||||
|
org-roam-node-title. You can also define custom accessors using
|
||||||
|
cl-defmethod. For example, you can define:
|
||||||
|
|
||||||
|
(cl-defmethod org-roam-node-my-title ((node org-roam-node))
|
||||||
|
(concat "My " (org-roam-node-title node)))
|
||||||
|
|
||||||
|
and then reference it here or in the capture templates as
|
||||||
|
"${my-title}".
|
||||||
|
|
||||||
|
"length" is an optional specifier and declares how many
|
||||||
|
characters can be used to display the value of the corresponding
|
||||||
|
field. If it's not specified, the field will be inserted as is,
|
||||||
|
i.e. it won't be aligned nor trimmed. If it's an integer, the
|
||||||
|
field will be aligned accordingly and all the exceeding
|
||||||
|
characters will be trimmed out. If it's "*", the field will use
|
||||||
|
as many characters as possible and will be aligned accordingly.
|
||||||
|
|
||||||
|
A closure can also be assigned to this variable in which case the
|
||||||
|
closure is evaluated and the return value is used as the
|
||||||
|
template. The closure must evaluate to a valid template string.
|
||||||
|
|
||||||
|
If you're using a vertical completion framework, such as Ivy and Selectrum,
|
||||||
|
Org-roam supports the generation of an aligned, tabular completion interface.
|
||||||
|
For example, to include a column for tags up to 10 character widths wide, one
|
||||||
|
can set ~org-roam-node-display-template~ as such:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq org-roam-node-display-template
|
||||||
|
(concat "${title:*} "
|
||||||
|
(propertize "${tags:10}" 'face 'org-tag)))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
* Customizing Node Caching
|
* Customizing Node Caching
|
||||||
** How to cache
|
** How to cache
|
||||||
|
Org-roam uses a SQLite database to perform caching. This integration is
|
||||||
Org-roam uses a sqlite database to perform caching, but there are multiple Emacs
|
managed by the [[https://github.com/magit/emacsql][emacsql]] library. It should "just work".
|
||||||
libraries that can be used. The default used by Org-roam is ~emacs-sqlite~.
|
|
||||||
Below the pros and cons of each package is used:
|
|
||||||
|
|
||||||
[[https://github.com/skeeto/emacsql][**emacs-sqlite**]]
|
|
||||||
|
|
||||||
The default option used by Org-roam. This library is the most mature and
|
|
||||||
well-supported and is imported by default in Org-roam.
|
|
||||||
|
|
||||||
One downside of using ~emacs-sqlite~ is that using it requires compilation and
|
|
||||||
can cause issues in some environments (especially Windows). If you have issues
|
|
||||||
producing the customized binary required by ~emacs-sqlite~, consider using
|
|
||||||
~emacs-sqlite3~.
|
|
||||||
|
|
||||||
[[https://github.com/cireu/emacsql-sqlite3][**emacs-sqlite3**]]
|
|
||||||
|
|
||||||
~emacs-sqlite3~ uses the official sqlite3 binary that can be obtained from your
|
|
||||||
system's package manager. This is useful if you have issues producing the
|
|
||||||
~sqlite3~ binary required by the other packages. However, it is not recommended
|
|
||||||
because it has some compatibility issues with Emacs, but should work for most
|
|
||||||
regular cases. See [[https://nullprogram.com/blog/2014/02/06/][Chris Wellon's blog post]] for more information.
|
|
||||||
|
|
||||||
To use ~emacsql-sqlite3~, ensure that the package is installed, and set:
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(setq org-roam-database-connector 'sqlite3)
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
[[https://github.com/emacscollective/emacsql-libsqlite3/][**emacsql-libsqlite3**]]
|
|
||||||
|
|
||||||
~emacs-libsqlite3~ is a relatively young package which uses an Emacs module that
|
|
||||||
exposes parts of the SQLite C API to Emacs Lisp, instead of using subprocess as
|
|
||||||
~emacsql-sqlite~ does. It is expected to be a more performant drop-in
|
|
||||||
replacement for ~emacs-sqlite~.
|
|
||||||
|
|
||||||
At the moment it is experimental and does not work well with the SQL query load
|
|
||||||
required by Org-roam, but you may still try it by ensuring the package is
|
|
||||||
installed and setting:
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(setq org-roam-database-connector 'libsqlite3)
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
** What to cache
|
** What to cache
|
||||||
|
|
||||||
@ -479,12 +445,41 @@ property to a non-nil value. For example:
|
|||||||
One can also set ~org-roam-db-node-include-function~. For example, to exclude
|
One can also set ~org-roam-db-node-include-function~. For example, to exclude
|
||||||
all headlines with the ~ATTACH~ tag from the Org-roam database, one can set:
|
all headlines with the ~ATTACH~ tag from the Org-roam database, one can set:
|
||||||
|
|
||||||
#+begin_src org
|
#+begin_src emacs-lisp
|
||||||
(setq org-roam-db-node-include-function
|
(setq org-roam-db-node-include-function
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(not (member "ATTACH" (org-get-tags)))))
|
(not (member "ATTACH" (org-get-tags)))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
Org-roam relied on the obtained Org AST for the buffer to parse links. However,
|
||||||
|
links appearing in some places (e.g. within property drawers) are not considered
|
||||||
|
by the Org AST to be links. Therefore, Org-roam takes special care of
|
||||||
|
additionally trying to process these links. Use
|
||||||
|
~org-roam-db-extra-links-elements~ to specify which additional Org AST element
|
||||||
|
types to consider.
|
||||||
|
|
||||||
|
- Variable: org-roam-db-extra-links-elements
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
Additionally, one may want to ignore certain keys from being excluded within
|
||||||
|
property drawers. For example, we would not want ~ROAM_REFS~ links to be
|
||||||
|
self-referential. Hence, to exclude specific keys, we use
|
||||||
|
~org-roam-db-extra-links-exclude-keys~.
|
||||||
|
|
||||||
|
- Variable: org-roam-db-extra-links-exclude-keys
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
** When to cache
|
** When to cache
|
||||||
|
|
||||||
By default, Org-roam is eager in caching: each time an Org-roam file is modified
|
By default, Org-roam is eager in caching: each time an Org-roam file is modified
|
||||||
@ -551,10 +546,10 @@ There are currently 3 provided widget types:
|
|||||||
- Unlinked references :: View nodes that contain text that match the nodes
|
- Unlinked references :: View nodes that contain text that match the nodes
|
||||||
title/alias but are not linked
|
title/alias but are not linked
|
||||||
|
|
||||||
To configure what sections are displayed in the buffer, set ~org-roam-mode-section-functions~.
|
To configure what sections are displayed in the buffer, set ~org-roam-mode-sections~.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-roam-mode-section-functions
|
(setq org-roam-mode-sections
|
||||||
(list #'org-roam-backlinks-section
|
(list #'org-roam-backlinks-section
|
||||||
#'org-roam-reflinks-section
|
#'org-roam-reflinks-section
|
||||||
;; #'org-roam-unlinked-references-section
|
;; #'org-roam-unlinked-references-section
|
||||||
@ -563,6 +558,29 @@ To configure what sections are displayed in the buffer, set ~org-roam-mode-secti
|
|||||||
|
|
||||||
Note that computing unlinked references may be slow, and has not been added in by default.
|
Note that computing unlinked references may be slow, and has not been added in by default.
|
||||||
|
|
||||||
|
For each section function, you can pass args along to modify its behaviour. For
|
||||||
|
example, if you want to render unique sources for backlinks (and also keep
|
||||||
|
rendering reference links), set ~org-roam-mode-sections~ as follows:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq org-roam-mode-sections
|
||||||
|
'((org-roam-backlinks-section :unique t)
|
||||||
|
org-roam-reflinks-section))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The backlinks section ~org-roam-backlinks-section~ also supports a
|
||||||
|
predicate to filter backlinks, ~:show-backlink-p~. This can be used
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defun my-org-roam-show-backlink-p (backlink)
|
||||||
|
(not (member "daily" (org-roam-node-tags (org-roam-backlink-source-node backlink)))))
|
||||||
|
|
||||||
|
(setq org-roam-mode-sections
|
||||||
|
'((org-roam-backlinks-section :unique t :show-backlink-p my-org-roam-show-backlink-p)
|
||||||
|
org-roam-reflinks-section))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
** Configuring the Org-roam buffer display
|
** Configuring the Org-roam buffer display
|
||||||
|
|
||||||
Org-roam does not control how the pop-up buffer is displayed: this is left to
|
Org-roam does not control how the pop-up buffer is displayed: this is left to
|
||||||
@ -670,7 +688,7 @@ With the above example, if another node links to https://www.google.com/, it
|
|||||||
will show up as a “reference backlink”.
|
will show up as a “reference backlink”.
|
||||||
|
|
||||||
These keys also come in useful for when taking website notes, using the
|
These keys also come in useful for when taking website notes, using the
|
||||||
~roam-ref~ protocol (see [[*Org-roam Protocol][Roam Protocol]]).
|
~roam-ref~ protocol (see [[*org-roam-protocol][org-roam-protocol]]).
|
||||||
|
|
||||||
You may assign multiple refs to a single node, for example when you want
|
You may assign multiple refs to a single node, for example when you want
|
||||||
multiple papers in a series to share the same note, or an article has a citation
|
multiple papers in a series to share the same note, or an article has a citation
|
||||||
@ -773,7 +791,7 @@ Similarly, the completion candidates are the titles and aliases for all Org-roam
|
|||||||
nodes, and upon choosing a candidate a ~roam:Title~ link will be inserted
|
nodes, and upon choosing a candidate a ~roam:Title~ link will be inserted
|
||||||
linking to the node of choice.
|
linking to the node of choice.
|
||||||
|
|
||||||
This is disable by default. To enable it, set ~org-roam-completion-everywhere~
|
This is disabled by default. To enable it, set ~org-roam-completion-everywhere~
|
||||||
to ~t~:
|
to ~t~:
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
@ -801,202 +819,6 @@ Note that the Org-roam database stores metadata information in plain-text
|
|||||||
(headline text, for example), so if this information is private to you then you
|
(headline text, for example), so if this information is private to you then you
|
||||||
should also ensure the database is encrypted.
|
should also ensure the database is encrypted.
|
||||||
|
|
||||||
* Org-roam Protocol
|
|
||||||
|
|
||||||
Org-roam provides extensions for capturing content from external applications
|
|
||||||
such as the browser, via ~org-protocol~. Org-roam extends ~org-protocol~ with 2
|
|
||||||
protocols: the ~roam-node~ and ~roam-ref~ protocols.
|
|
||||||
|
|
||||||
** Installation
|
|
||||||
|
|
||||||
To enable Org-roam's protocol extensions, simply add the following to your init
|
|
||||||
file:
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(require 'org-roam-protocol)
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
We also need to set up ~org-protocol~: the instructions for setting up
|
|
||||||
~org-protocol~ are reproduced below.
|
|
||||||
|
|
||||||
*** Linux
|
|
||||||
For Linux users, create a desktop application in
|
|
||||||
~~/.local/share/applications/org-protocol.desktop~:
|
|
||||||
|
|
||||||
#+begin_example
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=Org-Protocol
|
|
||||||
Exec=emacsclient %u
|
|
||||||
Icon=emacs-icon
|
|
||||||
Type=Application
|
|
||||||
Terminal=false
|
|
||||||
MimeType=x-scheme-handler/org-protocol
|
|
||||||
#+end_example
|
|
||||||
|
|
||||||
Associate ~org-protocol://~ links with the desktop application by
|
|
||||||
running in your shell:
|
|
||||||
|
|
||||||
#+BEGIN_SRC bash
|
|
||||||
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
#+BEGIN_SRC bash
|
|
||||||
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
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
and then restart Chrome (for example, by navigating to <chrome://restart>) to
|
|
||||||
make the new policy take effect.
|
|
||||||
|
|
||||||
See [[https://www.chromium.org/administrators/linux-quick-start][here]] for more info on the ~/etc/opt/chrome/policies/managed~ directory and
|
|
||||||
[[https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExternalProtocolDialogShowAlwaysOpenCheckbox][here]] for information on the ~ExternalProtocolDialogShowAlwaysOpenCheckbox~ policy.
|
|
||||||
|
|
||||||
*** Mac OS
|
|
||||||
For Mac OS, we need to create our own application.
|
|
||||||
|
|
||||||
1. Launch Script Editor
|
|
||||||
2. Use the following script, paying attention to the path to ~emacsclient~:
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
on open location this_URL
|
|
||||||
set EC to "/usr/local/bin/emacsclient --no-wait "
|
|
||||||
set filePath to quoted form of this_URL
|
|
||||||
do shell script EC & filePath
|
|
||||||
tell application "Emacs" to activate
|
|
||||||
end open location
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
3. Save the script in ~/Applications/OrgProtocolClient.app~, changing the script type to
|
|
||||||
"Application", rather than "Script".
|
|
||||||
4. Edit ~/Applications/OrgProtocolClient.app/Contents/Info.plist~, adding the
|
|
||||||
following before the last ~</dict>~ tag:
|
|
||||||
|
|
||||||
#+begin_src text
|
|
||||||
<key>CFBundleURLTypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleURLName</key>
|
|
||||||
<string>org-protocol handler</string>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>org-protocol</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
5. Save the file, and run the ~OrgProtocolClient.app~ to register the 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:
|
|
||||||
|
|
||||||
#+BEGIN_SRC bash
|
|
||||||
defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -bool true
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
If you're using [[https://github.com/railwaycat/homebrew-emacsmacport][Emacs Mac Port]], it registered its `Emacs.app` as the default
|
|
||||||
handler for the URL scheme `org-protocol`. To make ~OrgProtocol.app~
|
|
||||||
the default handler instead, run:
|
|
||||||
|
|
||||||
#+BEGIN_SRC bash
|
|
||||||
defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers -array-add \
|
|
||||||
'{"LSHandlerPreferredVersions" = { "LSHandlerRoleAll" = "-"; }; LSHandlerRoleAll = "org.yourusername.OrgProtocol"; LSHandlerURLScheme = "org-protocol";}'
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
Then restart your computer.
|
|
||||||
|
|
||||||
**** Testing org-protocol
|
|
||||||
|
|
||||||
To test that you have the handler setup and registered properly from the command
|
|
||||||
line you can run:
|
|
||||||
|
|
||||||
#+begin_src bash
|
|
||||||
open org-protocol://roam-ref\?template=r\&ref=test\&title=this
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
If you get an error similar too this or the wrong handler is run:
|
|
||||||
|
|
||||||
#+begin_quote
|
|
||||||
No application knows how to open URL org-protocol://roam-ref?template=r&ref=test&title=this (Error Domain=NSOSStatusErrorDomain Code=-10814 "kLSApplicationNotFoundErr: E.g. no application claims the file" UserInfo={_LSLine=1489, _LSFunction=runEvaluator}).
|
|
||||||
|
|
||||||
#+end_quote
|
|
||||||
|
|
||||||
You may need to manually register your handler, like this:
|
|
||||||
|
|
||||||
#+begin_src bash
|
|
||||||
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -R -f /Applications/OrgProtocolClient.app
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Here is a link to the lsregister command that is really useful: https://eclecticlight.co/2019/03/25/lsregister-a-valuable-undocumented-command-for-launchservices/
|
|
||||||
*** Windows
|
|
||||||
For Windows, create a temporary ~org-protocol.reg~ file:
|
|
||||||
|
|
||||||
#+BEGIN_SRC text
|
|
||||||
REGEDIT4
|
|
||||||
|
|
||||||
[HKEY_CLASSES_ROOT\org-protocol]
|
|
||||||
@="URL:Org Protocol"
|
|
||||||
"URL Protocol"=""
|
|
||||||
[HKEY_CLASSES_ROOT\org-protocol\shell]
|
|
||||||
[HKEY_CLASSES_ROOT\org-protocol\shell\open]
|
|
||||||
[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
|
|
||||||
@="\"C:\\Windows\\System32\\wsl.exe\" emacsclient \"%1\""
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
The above will forward the protocol to WSL. If you run Emacs natively on
|
|
||||||
Windows, replace the last line with:
|
|
||||||
|
|
||||||
#+BEGIN_SRC text
|
|
||||||
@="\"c:\\path\\to\\emacs\\bin\\emacsclientw.exe\" \"%1\""
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
After executing the .reg file, the protocol is registered and you can delete the
|
|
||||||
file.
|
|
||||||
|
|
||||||
** The roam-node protocol
|
|
||||||
|
|
||||||
The roam-node protocol opens the node with ID specified by the ~node~ key (e.g.
|
|
||||||
~org-protocol://roam-node?node=node-id~). ~org-roam-graph~ uses this to make the
|
|
||||||
graph navigable.
|
|
||||||
|
|
||||||
** The roam-ref protocol
|
|
||||||
|
|
||||||
This protocol finds or creates a new note with a given ~ROAM_REFS~:
|
|
||||||
|
|
||||||
[[file:images/roam-ref.gif]]
|
|
||||||
|
|
||||||
To use this, create the following [[https://en.wikipedia.org/wiki/Bookmarklet][bookmarklet]] in your browser:
|
|
||||||
|
|
||||||
#+BEGIN_SRC javascript
|
|
||||||
javascript:location.href =
|
|
||||||
'org-protocol://roam-ref?template=r&ref='
|
|
||||||
+ encodeURIComponent(location.href)
|
|
||||||
+ '&title='
|
|
||||||
+ encodeURIComponent(document.title)
|
|
||||||
+ '&body='
|
|
||||||
+ encodeURIComponent(window.getSelection())
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
or as a keybinding in ~qutebrowser~ in , using the ~config.py~ file (see
|
|
||||||
[[https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc][Configuring qutebrowser]]):
|
|
||||||
|
|
||||||
#+BEGIN_SRC python
|
|
||||||
config.bind("<Ctrl-r>", "open javascript:location.href='org-protocol://roam-ref?template=r&ref='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)")
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
where ~template~ is the template key for a template in
|
|
||||||
~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]).
|
|
||||||
|
|
||||||
* The Templating System
|
* The Templating System
|
||||||
|
|
||||||
Org-roam extends the ~org-capture~ system, providing a smoother note-taking
|
Org-roam extends the ~org-capture~ system, providing a smoother note-taking
|
||||||
@ -1078,12 +900,232 @@ One can check the list of available keys for nodes by inspecting the
|
|||||||
|
|
||||||
This makes ~${file}~, ~${file-hash}~ etc. all valid substitutions.
|
This makes ~${file}~, ~${file-hash}~ etc. all valid substitutions.
|
||||||
|
|
||||||
* Graphing
|
* Extensions
|
||||||
|
** org-roam-protocol
|
||||||
|
|
||||||
|
Org-roam provides extensions for capturing content from external applications
|
||||||
|
such as the browser, via ~org-protocol~. Org-roam extends ~org-protocol~ with 2
|
||||||
|
protocols: the ~roam-node~ and ~roam-ref~ protocols.
|
||||||
|
|
||||||
|
*** Installation
|
||||||
|
|
||||||
|
To enable Org-roam's protocol extensions, simply add the following to your init
|
||||||
|
file:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(require 'org-roam-protocol)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
We also need to set up ~org-protocol~: the instructions for setting up
|
||||||
|
~org-protocol~ are reproduced here.
|
||||||
|
|
||||||
|
On a high-level, external calls are passed to Emacs via ~emacsclient~.
|
||||||
|
~org-protocol~ intercepts these and runs custom actions based on the protocols
|
||||||
|
registered. Hence, to use ~org-protocol~, once must:
|
||||||
|
|
||||||
|
1. launch the ~emacsclient~ process
|
||||||
|
2. Register ~org-protocol://~ as a valid scheme-handler
|
||||||
|
|
||||||
|
The instructions for the latter for each operating system is detailed below.
|
||||||
|
|
||||||
|
**** Linux
|
||||||
|
For Linux users, create a desktop application in
|
||||||
|
~~/.local/share/applications/org-protocol.desktop~:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Org-Protocol
|
||||||
|
Exec=emacsclient %u
|
||||||
|
Icon=emacs-icon
|
||||||
|
Type=Application
|
||||||
|
Terminal=false
|
||||||
|
MimeType=x-scheme-handler/org-protocol
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
Associate ~org-protocol://~ links with the desktop application by
|
||||||
|
running in your shell:
|
||||||
|
|
||||||
|
#+BEGIN_SRC bash
|
||||||
|
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
#+BEGIN_SRC bash
|
||||||
|
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
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
and then restart Chrome (for example, by navigating to <chrome://restart>) to
|
||||||
|
make the new policy take effect.
|
||||||
|
|
||||||
|
See [[https://www.chromium.org/administrators/linux-quick-start][here]] for more info on the ~/etc/opt/chrome/policies/managed~ directory and
|
||||||
|
[[https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExternalProtocolDialogShowAlwaysOpenCheckbox][here]] for information on the ~ExternalProtocolDialogShowAlwaysOpenCheckbox~ policy.
|
||||||
|
|
||||||
|
**** Mac OS
|
||||||
|
For Mac OS, we need to create our own application.
|
||||||
|
|
||||||
|
1. Launch Script Editor
|
||||||
|
2. Use the following script, paying attention to the path to ~emacsclient~:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
on open location this_URL
|
||||||
|
set EC to "/usr/local/bin/emacsclient --no-wait "
|
||||||
|
set filePath to quoted form of this_URL
|
||||||
|
do shell script EC & filePath & " &> /dev/null &"
|
||||||
|
tell application "Emacs" to activate
|
||||||
|
end open location
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
3. Save the script in ~/Applications/OrgProtocolClient.app~, changing the script type to
|
||||||
|
"Application", rather than "Script".
|
||||||
|
4. Edit ~/Applications/OrgProtocolClient.app/Contents/Info.plist~, adding the
|
||||||
|
following before the last ~</dict>~ tag:
|
||||||
|
|
||||||
|
#+begin_src text
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>org-protocol handler</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>org-protocol</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
5. Save the file, and run the ~OrgProtocolClient.app~ to register the 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:
|
||||||
|
|
||||||
|
#+BEGIN_SRC bash
|
||||||
|
defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -bool true
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
If you're using [[https://github.com/railwaycat/homebrew-emacsmacport][Emacs Mac Port]], it registered its `Emacs.app` as the default
|
||||||
|
handler for the URL scheme `org-protocol`. To make ~OrgProtocol.app~
|
||||||
|
the default handler instead, run:
|
||||||
|
|
||||||
|
#+BEGIN_SRC bash
|
||||||
|
defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers -array-add \
|
||||||
|
'{"LSHandlerPreferredVersions" = { "LSHandlerRoleAll" = "-"; }; LSHandlerRoleAll = "org.yourusername.OrgProtocol"; LSHandlerURLScheme = "org-protocol";}'
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Then restart your computer.
|
||||||
|
|
||||||
|
If you're using the [[https://formulae.brew.sh/formula/emacs][Emacs Homebrew formula]], you may need one of the following additional configurations:
|
||||||
|
|
||||||
|
a) Add option `-c` to `emacsclient` in the script, and start emacs from command line with `emacs --daemon`
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
on open location this_URL
|
||||||
|
set EC to "/usr/local/bin/emacsclient -c --no-wait "
|
||||||
|
set filePath to quoted form of this_URL
|
||||||
|
do shell script EC & filePath & " &> /dev/null &"
|
||||||
|
tell application "Emacs" to activate
|
||||||
|
end open location
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
b) Add `(server-start)` in .emacs (in this case you do not need option `-c` for `emacsclient` in the script, and you do not need to start emacs with `emacs --daemon`
|
||||||
|
|
||||||
|
***** Testing org-protocol
|
||||||
|
|
||||||
|
To test that you have the handler setup and registered properly from the command
|
||||||
|
line you can run:
|
||||||
|
|
||||||
|
#+begin_src bash
|
||||||
|
open org-protocol://roam-ref\?template=r\&ref=test\&title=this
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
If you get an error similar too this or the wrong handler is run:
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
No application knows how to open URL org-protocol://roam-ref?template=r&ref=test&title=this (Error Domain=NSOSStatusErrorDomain Code=-10814 "kLSApplicationNotFoundErr: E.g. no application claims the file" UserInfo={_LSLine=1489, _LSFunction=runEvaluator}).
|
||||||
|
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
You may need to manually register your handler, like this:
|
||||||
|
|
||||||
|
#+begin_src bash
|
||||||
|
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -R -f /Applications/OrgProtocolClient.app
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Here is a link to the lsregister command that is really useful: https://eclecticlight.co/2019/03/25/lsregister-a-valuable-undocumented-command-for-launchservices/
|
||||||
|
**** Windows
|
||||||
|
For Windows, create a temporary ~org-protocol.reg~ file:
|
||||||
|
|
||||||
|
#+BEGIN_SRC text
|
||||||
|
REGEDIT4
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\org-protocol]
|
||||||
|
@="URL:Org Protocol"
|
||||||
|
"URL Protocol"=""
|
||||||
|
[HKEY_CLASSES_ROOT\org-protocol\shell]
|
||||||
|
[HKEY_CLASSES_ROOT\org-protocol\shell\open]
|
||||||
|
[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
|
||||||
|
@="\"C:\\Windows\\System32\\wsl.exe\" emacsclient \"%1\""
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
The above will forward the protocol to WSL. If you run Emacs natively on
|
||||||
|
Windows, replace the last line with:
|
||||||
|
|
||||||
|
#+BEGIN_SRC text
|
||||||
|
@="\"c:\\path\\to\\emacs\\bin\\emacsclientw.exe\" \"%1\""
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
After executing the .reg file, the protocol is registered and you can delete the
|
||||||
|
file.
|
||||||
|
|
||||||
|
*** The roam-node protocol
|
||||||
|
|
||||||
|
The roam-node protocol opens the node with ID specified by the ~node~ key (e.g.
|
||||||
|
~org-protocol://roam-node?node=node-id~). ~org-roam-graph~ uses this to make the
|
||||||
|
graph navigable.
|
||||||
|
|
||||||
|
*** The roam-ref protocol
|
||||||
|
|
||||||
|
This protocol finds or creates a new note with a given ~ROAM_REFS~:
|
||||||
|
|
||||||
|
[[file:images/roam-ref.gif]]
|
||||||
|
|
||||||
|
To use this, create the following [[https://en.wikipedia.org/wiki/Bookmarklet][bookmarklet]] in your browser:
|
||||||
|
|
||||||
|
#+BEGIN_SRC javascript
|
||||||
|
javascript:location.href =
|
||||||
|
'org-protocol://roam-ref?template=r&ref='
|
||||||
|
+ encodeURIComponent(location.href)
|
||||||
|
+ '&title='
|
||||||
|
+ encodeURIComponent(document.title)
|
||||||
|
+ '&body='
|
||||||
|
+ encodeURIComponent(window.getSelection())
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
or as a keybinding in ~qutebrowser~ in , using the ~config.py~ file (see
|
||||||
|
[[https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc][Configuring qutebrowser]]):
|
||||||
|
|
||||||
|
#+BEGIN_SRC python
|
||||||
|
config.bind("<Ctrl-r>", "open javascript:location.href='org-protocol://roam-ref?template=r&ref='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)")
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
where ~template~ is the template key for a template in
|
||||||
|
~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]).
|
||||||
|
|
||||||
|
** org-roam-graph
|
||||||
|
|
||||||
Org-roam provides basic graphing capabilities to explore interconnections
|
Org-roam provides basic graphing capabilities to explore interconnections
|
||||||
between notes, in ~org-roam-graph~. This is done by performing SQL queries and
|
between notes, in ~org-roam-graph~. This is done by performing SQL queries and
|
||||||
generating images using [[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*Org-roam Protocol][Roam
|
generating images using [[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*org-roam-protocol][org-roam-protocol]].
|
||||||
Protocol]].
|
|
||||||
|
|
||||||
The entry point to graph creation is ~org-roam-graph~.
|
The entry point to graph creation is ~org-roam-graph~.
|
||||||
|
|
||||||
@ -1124,7 +1166,7 @@ ARG may be any of the following values:
|
|||||||
(org-roam-graph--open (concat "file://///wsl$/Ubuntu" file)))))
|
(org-roam-graph--open (concat "file://///wsl$/Ubuntu" file)))))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Graph Options
|
*** Graph Options
|
||||||
|
|
||||||
Graphviz provides many options for customizing the graph output, and Org-roam
|
Graphviz provides many options for customizing the graph output, and Org-roam
|
||||||
supports some of them. See https://graphviz.gitlab.io/_pages/doc/info/attrs.html
|
supports some of them. See https://graphviz.gitlab.io/_pages/doc/info/attrs.html
|
||||||
@ -1150,12 +1192,12 @@ for customizable options.
|
|||||||
Extra options for edges in the graphviz output (The "E" attributes).
|
Extra options for edges in the graphviz output (The "E" attributes).
|
||||||
Example: ~'(("dir" . "back"))~
|
Example: ~'(("dir" . "back"))~
|
||||||
|
|
||||||
* Org-roam Dailies
|
** org-roam-dailies
|
||||||
|
|
||||||
Org-roam provides journaling capabilities akin to
|
Org-roam provides journaling capabilities akin to
|
||||||
Org-journal with ~org-roam-dailies~.
|
Org-journal with ~org-roam-dailies~.
|
||||||
|
|
||||||
** Configuration
|
*** Configuration
|
||||||
|
|
||||||
For ~org-roam-dailies~ to work, you need to define two variables:
|
For ~org-roam-dailies~ to work, you need to define two variables:
|
||||||
|
|
||||||
@ -1181,7 +1223,7 @@ Here is a sane default configuration:
|
|||||||
|
|
||||||
See [[*The Templating System][The Templating System]] for creating new templates.
|
See [[*The Templating System][The Templating System]] for creating new templates.
|
||||||
|
|
||||||
** Usage
|
*** Usage
|
||||||
|
|
||||||
~org-roam-dailies~ provides these interactive functions:
|
~org-roam-dailies~ provides these interactive functions:
|
||||||
|
|
||||||
@ -1199,7 +1241,7 @@ There are variants of those commands for ~-yesterday~ and ~-tomorrow~:
|
|||||||
|
|
||||||
- Function: ~org-roam-dailies-capture-yesterday~ n &optional goto
|
- Function: ~org-roam-dailies-capture-yesterday~ n &optional goto
|
||||||
|
|
||||||
Create an entry in the daily note for yesteday.
|
Create an entry in the daily note for yesterday.
|
||||||
|
|
||||||
With numeric argument ~n~, use the daily note ~n~ days in the past.
|
With numeric argument ~n~, use the daily note ~n~ days in the past.
|
||||||
|
|
||||||
@ -1235,6 +1277,18 @@ There are also commands which allow you to use Emacs’s ~calendar~ to find the
|
|||||||
- Function: ~org-roam-dailies-goto-next-note~
|
- Function: ~org-roam-dailies-goto-next-note~
|
||||||
|
|
||||||
When in an daily-note, find the next one.
|
When in an daily-note, find the next one.
|
||||||
|
** org-roam-export
|
||||||
|
|
||||||
|
Because Org-roam files are plain org files, they can be exported easily using
|
||||||
|
~org-export~ to a variety of formats, including ~html~ and ~pdf~. However,
|
||||||
|
Org-roam relies heavily on ID links, which Org's html export has poor support
|
||||||
|
of. To fix this, Org-roam provides a bunch of overrides to better support
|
||||||
|
export. To use them, simply run:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(require 'org-roam-export)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
* Performance Optimization
|
* Performance Optimization
|
||||||
** Garbage Collection
|
** Garbage Collection
|
||||||
|
|
||||||
@ -1308,7 +1362,7 @@ The Deft interface can slow down quickly when the number of files get huge.
|
|||||||
|
|
||||||
[[https://github.com/bastibe/org-journal][Org-journal]] provides journaling capabilities to Org-mode. A lot of its
|
[[https://github.com/bastibe/org-journal][Org-journal]] provides journaling capabilities to Org-mode. A lot of its
|
||||||
functionalities have been incorporated into Org-roam under the name
|
functionalities have been incorporated into Org-roam under the name
|
||||||
[[*Org-roam Dailies][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose
|
[[*org-roam-dailies][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose
|
||||||
journal entries from the ideas you would write on a scratchpad.
|
journal entries from the ideas you would write on a scratchpad.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
@ -1536,7 +1590,6 @@ to the publishing directory. Example code follows:
|
|||||||
(kill-buffer (file-name-nondirectory svg))
|
(kill-buffer (file-name-nondirectory svg))
|
||||||
(setq my-publish-time 0)))))
|
(setq my-publish-time 0)))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
* Developer's Guide to Org-roam
|
* Developer's Guide to Org-roam
|
||||||
** Org-roam's Design Principle
|
** Org-roam's Design Principle
|
||||||
|
|
||||||
@ -1575,7 +1628,7 @@ queries on their Org files.
|
|||||||
** Building Extensions and Advanced Customization of Org-roam
|
** Building Extensions and Advanced Customization of Org-roam
|
||||||
|
|
||||||
Because Org-roam's core functionality is small, it is possible and sometimes
|
Because Org-roam's core functionality is small, it is possible and sometimes
|
||||||
desirable to build extensions on top of it. These extensions may one or more of
|
desirable to build extensions on top of it. These extensions may use one or more of
|
||||||
the following functionalities:
|
the following functionalities:
|
||||||
|
|
||||||
- Access to Org-roam's database
|
- Access to Org-roam's database
|
||||||
@ -1682,7 +1735,7 @@ When GOTO is non-nil, go the note without creating an entry."
|
|||||||
:END:
|
:END:
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
Copyright (C) 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
Copyright (C) 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
You can redistribute this document and/or modify it under the terms
|
You can redistribute this document and/or modify it under the terms
|
||||||
of the GNU General Public License as published by the Free Software
|
of the GNU General Public License as published by the Free Software
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,14 @@
|
|||||||
;;; org-roam-dailies.el --- Daily-notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-dailies.el --- Daily-notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
;;;
|
;;;
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; Copyright © 2020 Leo Vivier <leo.vivier+dev@gmail.com>
|
;; Copyright © 2020 Leo Vivier <leo.vivier+dev@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; Leo Vivier <leo.vivier+dev@gmail.com>
|
;; Leo Vivier <leo.vivier+dev@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org-roam "2.1"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org-roam "2.1"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -34,10 +34,9 @@
|
|||||||
;; each file named after certain date and stored in `org-roam-dailies-directory'.
|
;; 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,
|
;; One can use dailies for various purposes, e.g. journaling, fleeting notes,
|
||||||
;; scratch notes and whatever else you can came up with.
|
;; scratch notes or whatever else you can think of.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'f)
|
|
||||||
(require 'dash)
|
(require 'dash)
|
||||||
(require 'org-roam)
|
(require 'org-roam)
|
||||||
|
|
||||||
@ -140,72 +139,93 @@ In this case, interactive selection will be bypassed."
|
|||||||
(org-roam-dailies--capture (current-time) goto keys))
|
(org-roam-dailies--capture (current-time) goto keys))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-goto-today ()
|
(defun org-roam-dailies-goto-today (&optional keys)
|
||||||
"Find the daily-note for today, creating it if necessary."
|
"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)
|
(interactive)
|
||||||
(org-roam-dailies-capture-today t))
|
(org-roam-dailies-capture-today t keys))
|
||||||
|
|
||||||
;;;; Tomorrow
|
;;;; Tomorrow
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-capture-tomorrow (n &optional goto)
|
(defun org-roam-dailies-capture-tomorrow (n &optional goto keys)
|
||||||
"Create an entry in the daily-note for tomorrow.
|
"Create an entry in the daily-note for tomorrow.
|
||||||
|
|
||||||
With numeric argument N, use the daily-note N days in the future.
|
With numeric argument N, use the daily-note N days in the future.
|
||||||
|
|
||||||
With a `C-u' prefix or when GOTO is non-nil, go the note without
|
With a `C-u' prefix or when GOTO is non-nil, go the note without
|
||||||
creating an entry."
|
creating an entry.
|
||||||
|
|
||||||
|
ELisp programs can set KEYS to a string associated with a template.
|
||||||
|
In this case, interactive selection will be bypassed."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(org-roam-dailies--capture (time-add (* n 86400) (current-time)) goto))
|
(org-roam-dailies--capture (time-add (* n 86400) (current-time)) goto keys))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-goto-tomorrow (n)
|
(defun org-roam-dailies-goto-tomorrow (n &optional keys)
|
||||||
"Find the daily-note for tomorrow, creating it if necessary.
|
"Find the daily-note for tomorrow, creating it if necessary.
|
||||||
|
|
||||||
With numeric argument N, use the daily-note N days in the
|
With numeric argument N, use the daily-note N days in the
|
||||||
future."
|
future.
|
||||||
|
|
||||||
|
ELisp programs can set KEYS to a string associated with a template.
|
||||||
|
In this case, interactive selection will be bypassed."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(org-roam-dailies-capture-tomorrow n t))
|
(org-roam-dailies-capture-tomorrow n t keys))
|
||||||
|
|
||||||
;;;; Yesterday
|
;;;; Yesterday
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-capture-yesterday (n &optional goto)
|
(defun org-roam-dailies-capture-yesterday (n &optional goto keys)
|
||||||
"Create an entry in the daily-note for yesteday.
|
"Create an entry in the daily-note for yesteday.
|
||||||
|
|
||||||
With numeric argument N, use the daily-note N days in the past.
|
With numeric argument N, use the daily-note N days in the past.
|
||||||
|
|
||||||
When GOTO is non-nil, go the note without creating an entry."
|
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")
|
(interactive "p")
|
||||||
(org-roam-dailies-capture-tomorrow (- n) goto))
|
(org-roam-dailies-capture-tomorrow (- n) goto keys))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-goto-yesterday (n)
|
(defun org-roam-dailies-goto-yesterday (n &optional keys)
|
||||||
"Find the daily-note for yesterday, creating it if necessary.
|
"Find the daily-note for yesterday, creating it if necessary.
|
||||||
|
|
||||||
With numeric argument N, use the daily-note N days in the
|
With numeric argument N, use the daily-note N days in the
|
||||||
future."
|
future.
|
||||||
|
|
||||||
|
ELisp programs can set KEYS to a string associated with a template.
|
||||||
|
In this case, interactive selection will be bypassed."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(org-roam-dailies-capture-tomorrow (- n) t))
|
(org-roam-dailies-capture-tomorrow (- n) t keys))
|
||||||
|
|
||||||
;;;; Date
|
;;;; Date
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-capture-date (&optional goto prefer-future)
|
(defun org-roam-dailies-capture-date (&optional goto prefer-future keys)
|
||||||
"Create an entry in the daily-note for a date using the calendar.
|
"Create an entry in the daily-note for a date using the calendar.
|
||||||
Prefer past dates, unless PREFER-FUTURE is non-nil.
|
Prefer past dates, unless PREFER-FUTURE is non-nil.
|
||||||
With a `C-u' prefix or when GOTO is non-nil, go the note without
|
With a `C-u' prefix or when GOTO is non-nil, go the note without
|
||||||
creating an entry."
|
creating an entry.
|
||||||
|
|
||||||
|
ELisp programs can set KEYS to a string associated with a template.
|
||||||
|
In this case, interactive selection will be bypassed."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((time (let ((org-read-date-prefer-future prefer-future))
|
(let ((time (let ((org-read-date-prefer-future prefer-future))
|
||||||
(org-read-date nil t nil (if goto
|
(org-read-date nil t nil (if goto
|
||||||
"Find daily-note: "
|
"Find daily-note: "
|
||||||
"Capture to daily-note: ")))))
|
"Capture to daily-note: ")))))
|
||||||
(org-roam-dailies--capture time goto)))
|
(org-roam-dailies--capture time goto keys)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-goto-date (&optional prefer-future)
|
(defun org-roam-dailies-goto-date (&optional prefer-future keys)
|
||||||
"Find the daily-note for a date using the calendar, creating it if necessary.
|
"Find the daily-note for a date using the calendar, creating it if necessary.
|
||||||
Prefer past dates, unless PREFER-FUTURE is non-nil."
|
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)
|
(interactive)
|
||||||
(org-roam-dailies-capture-date t prefer-future))
|
(org-roam-dailies-capture-date t prefer-future keys))
|
||||||
|
|
||||||
;;;; Navigation
|
;;;; Navigation
|
||||||
(defun org-roam-dailies-goto-next-note (&optional n)
|
(defun org-roam-dailies-goto-next-note (&optional n)
|
||||||
@ -269,7 +289,7 @@ If FILE is not specified, use the current buffer's file-path."
|
|||||||
(save-match-data
|
(save-match-data
|
||||||
(and
|
(and
|
||||||
(org-roam-file-p path)
|
(org-roam-file-p path)
|
||||||
(f-descendant-of-p path directory)))))
|
(org-roam-descendant-of-p path directory)))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-dailies-find-directory ()
|
(defun org-roam-dailies-find-directory ()
|
||||||
@ -309,7 +329,8 @@ When GOTO is non-nil, go the note without creating an entry.
|
|||||||
|
|
||||||
ELisp programs can set KEYS to a string associated with a template.
|
ELisp programs can set KEYS to a string associated with a template.
|
||||||
In this case, interactive selection will be bypassed."
|
In this case, interactive selection will be bypassed."
|
||||||
(let ((org-roam-directory (expand-file-name org-roam-dailies-directory org-roam-directory)))
|
(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))
|
(org-roam-capture- :goto (when goto '(4))
|
||||||
:keys keys
|
:keys keys
|
||||||
:node (org-roam-node-create)
|
:node (org-roam-node-create)
|
||||||
|
75
extensions/org-roam-export.el
Normal file
75
extensions/org-roam-export.el
Normal 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.1
|
||||||
|
;; 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
|
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-graph.el --- Basic graphing functionality for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-graph.el --- Basic graphing functionality for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
|
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ Handles both Org-roam nodes, and string nodes (e.g. urls)."
|
|||||||
(org-roam-quote-string
|
(org-roam-quote-string
|
||||||
(pcase org-roam-graph-shorten-titles
|
(pcase org-roam-graph-shorten-titles
|
||||||
(`truncate (truncate-string-to-width title org-roam-graph-max-title-length nil nil "..."))
|
(`truncate (truncate-string-to-width title org-roam-graph-max-title-length nil nil "..."))
|
||||||
(`wrap (s-word-wrap org-roam-graph-max-title-length title))
|
(`wrap (org-roam-word-wrap org-roam-graph-max-title-length title))
|
||||||
(_ title)))))
|
(_ title)))))
|
||||||
(setq node-id (org-roam-node-id node)
|
(setq node-id (org-roam-node-id node)
|
||||||
node-properties `(("label" . ,shortened-title)
|
node-properties `(("label" . ,shortened-title)
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-overlay.el --- Link overlay for [id:] links to Org-roam nodes -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-overlay.el --- Link overlay for [id:] links to Org-roam nodes -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
|
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
|
;; Package-Requires: ((emacs "26.1") (org "9.6") (org-roam "2.1"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -169,25 +169,6 @@ org-protocol://roam-node?node=uuid"
|
|||||||
(push '("org-roam-node" :protocol "roam-node" :function org-roam-protocol-open-node)
|
(push '("org-roam-node" :protocol "roam-node" :function org-roam-protocol-open-node)
|
||||||
org-protocol-protocol-alist)
|
org-protocol-protocol-alist)
|
||||||
|
|
||||||
;;; Capture implementation
|
|
||||||
(add-hook 'org-roam-capture-preface-hook #'org-roam-protocol--try-capture-to-ref-h)
|
|
||||||
(defun org-roam-protocol--try-capture-to-ref-h ()
|
|
||||||
"Try to capture to an existing node that match the ref."
|
|
||||||
(when-let ((node (and (plist-get org-roam-capture--info :ref)
|
|
||||||
(org-roam-node-from-ref
|
|
||||||
(plist-get org-roam-capture--info :ref)))))
|
|
||||||
(set-buffer (org-capture-target-buffer (org-roam-node-file node)))
|
|
||||||
(goto-char (org-roam-node-point node))
|
|
||||||
(widen)
|
|
||||||
(org-roam-node-id node)))
|
|
||||||
|
|
||||||
(add-hook 'org-roam-capture-new-node-hook #'org-roam-protocol--insert-captured-ref-h)
|
|
||||||
(defun org-roam-protocol--insert-captured-ref-h ()
|
|
||||||
"Insert the ref if any."
|
|
||||||
(when-let ((ref (plist-get org-roam-capture--info :ref)))
|
|
||||||
(org-roam-ref-add ref)))
|
|
||||||
|
|
||||||
|
|
||||||
(provide 'org-roam-protocol)
|
(provide 'org-roam-protocol)
|
||||||
|
|
||||||
;;; org-roam-protocol.el ends here
|
;;; org-roam-protocol.el ends here
|
||||||
|
11
github-eldev
Executable file
11
github-eldev
Executable 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
|
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-capture.el --- Capture functionality -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-capture.el --- Capture functionality -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -407,6 +407,8 @@ TEMPLATES is a list of org-roam templates."
|
|||||||
(mapcar (lambda (template)
|
(mapcar (lambda (template)
|
||||||
(org-roam-capture--convert-template template props))
|
(org-roam-capture--convert-template template props))
|
||||||
(or templates org-roam-capture-templates)))
|
(or templates org-roam-capture-templates)))
|
||||||
|
(_ (setf (org-roam-node-id node) (or (org-roam-node-id node)
|
||||||
|
(org-id-new))))
|
||||||
(org-roam-capture--node node)
|
(org-roam-capture--node node)
|
||||||
(org-roam-capture--info info))
|
(org-roam-capture--info info))
|
||||||
(when (and (not keys)
|
(when (and (not keys)
|
||||||
@ -503,7 +505,7 @@ Return the ID of the location."
|
|||||||
(set-buffer (org-capture-target-buffer path))
|
(set-buffer (org-capture-target-buffer path))
|
||||||
(when new-file-p
|
(when new-file-p
|
||||||
(org-roam-capture--put :new-file path)
|
(org-roam-capture--put :new-file path)
|
||||||
(insert (org-roam-capture--fill-template head t)))
|
(insert (org-roam-capture--fill-template head 'ensure-newline)))
|
||||||
(widen)
|
(widen)
|
||||||
(setq p (goto-char (point-min))))
|
(setq p (goto-char (point-min))))
|
||||||
(`(file+head+olp ,path ,head ,olp)
|
(`(file+head+olp ,path ,head ,olp)
|
||||||
@ -513,7 +515,7 @@ Return the ID of the location."
|
|||||||
(widen)
|
(widen)
|
||||||
(when new-file-p
|
(when new-file-p
|
||||||
(org-roam-capture--put :new-file path)
|
(org-roam-capture--put :new-file path)
|
||||||
(insert (org-roam-capture--fill-template head t)))
|
(insert (org-roam-capture--fill-template head 'ensure-newline)))
|
||||||
(setq p (point-min))
|
(setq p (point-min))
|
||||||
(let ((m (org-roam-capture-find-or-create-olp olp)))
|
(let ((m (org-roam-capture-find-or-create-olp olp)))
|
||||||
(goto-char m)))
|
(goto-char m)))
|
||||||
@ -572,11 +574,11 @@ Return the ID of the location."
|
|||||||
;; caller.
|
;; caller.
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char p)
|
(goto-char p)
|
||||||
(when-let* ((node org-roam-capture--node)
|
(if-let ((id (org-entry-get p "ID")))
|
||||||
(id (org-roam-node-id node)))
|
(setf (org-roam-node-id org-roam-capture--node) id)
|
||||||
(org-entry-put p "ID" id))
|
(org-entry-put p "ID" (org-roam-node-id org-roam-capture--node)))
|
||||||
(prog1
|
(prog1
|
||||||
(org-id-get-create)
|
(org-id-get)
|
||||||
(run-hooks 'org-roam-capture-new-node-hook)))))
|
(run-hooks 'org-roam-capture-new-node-hook)))))
|
||||||
|
|
||||||
(defun org-roam-capture--get-target ()
|
(defun org-roam-capture--get-target ()
|
||||||
@ -589,8 +591,9 @@ Return the ID of the location."
|
|||||||
PATH is a string that can optionally contain templated text in
|
PATH is a string that can optionally contain templated text in
|
||||||
it."
|
it."
|
||||||
(or (org-roam-node-file org-roam-capture--node)
|
(or (org-roam-node-file org-roam-capture--node)
|
||||||
(thread-first path
|
(thread-first
|
||||||
(org-roam-capture--fill-template t)
|
path
|
||||||
|
(org-roam-capture--fill-template)
|
||||||
(string-trim)
|
(string-trim)
|
||||||
(expand-file-name org-roam-directory))))
|
(expand-file-name org-roam-directory))))
|
||||||
|
|
||||||
@ -615,7 +618,7 @@ you can catch it with `condition-case'."
|
|||||||
(org-with-wide-buffer
|
(org-with-wide-buffer
|
||||||
(goto-char start)
|
(goto-char start)
|
||||||
(dolist (heading olp)
|
(dolist (heading olp)
|
||||||
(setq heading (org-roam-capture--fill-template heading t))
|
(setq heading (org-roam-capture--fill-template heading))
|
||||||
(let ((re (format org-complex-heading-regexp-format
|
(let ((re (format org-complex-heading-regexp-format
|
||||||
(regexp-quote heading)))
|
(regexp-quote heading)))
|
||||||
(cnt 0))
|
(cnt 0))
|
||||||
@ -677,6 +680,24 @@ the current value of `point'."
|
|||||||
(goto-char (org-entry-end-position))))))))
|
(goto-char (org-entry-end-position))))))))
|
||||||
(point))
|
(point))
|
||||||
|
|
||||||
|
;;; Capture implementation
|
||||||
|
(add-hook 'org-roam-capture-preface-hook #'org-roam-capture--try-capture-to-ref-h)
|
||||||
|
(defun org-roam-capture--try-capture-to-ref-h ()
|
||||||
|
"Try to capture to an existing node that match the ref."
|
||||||
|
(when-let ((node (and (plist-get org-roam-capture--info :ref)
|
||||||
|
(org-roam-node-from-ref
|
||||||
|
(plist-get org-roam-capture--info :ref)))))
|
||||||
|
(set-buffer (org-capture-target-buffer (org-roam-node-file node)))
|
||||||
|
(goto-char (org-roam-node-point node))
|
||||||
|
(widen)
|
||||||
|
(org-roam-node-id node)))
|
||||||
|
|
||||||
|
(add-hook 'org-roam-capture-new-node-hook #'org-roam-capture--insert-captured-ref-h)
|
||||||
|
(defun org-roam-capture--insert-captured-ref-h ()
|
||||||
|
"Insert the ref if any."
|
||||||
|
(when-let ((ref (plist-get org-roam-capture--info :ref)))
|
||||||
|
(org-roam-ref-add ref)))
|
||||||
|
|
||||||
;;;; Finalizers
|
;;;; Finalizers
|
||||||
(add-hook 'org-capture-prepare-finalize-hook #'org-roam-capture--install-finalize-h)
|
(add-hook 'org-capture-prepare-finalize-hook #'org-roam-capture--install-finalize-h)
|
||||||
(defun org-roam-capture--install-finalize-h ()
|
(defun org-roam-capture--install-finalize-h ()
|
||||||
@ -686,14 +707,15 @@ the current value of `point'."
|
|||||||
|
|
||||||
(defun org-roam-capture--finalize ()
|
(defun org-roam-capture--finalize ()
|
||||||
"Finalize the `org-roam-capture' process."
|
"Finalize the `org-roam-capture' process."
|
||||||
(when-let ((region (org-roam-capture--get :region)))
|
|
||||||
(org-roam-unshield-region (car region) (cdr region)))
|
|
||||||
(if org-note-abort
|
(if org-note-abort
|
||||||
(when-let ((new-file (org-roam-capture--get :new-file)))
|
(when-let ((new-file (org-roam-capture--get :new-file))
|
||||||
(org-roam-message "Deleting file for aborted capture %s" new-file)
|
(_ (yes-or-no-p "Delete file for aborted capture?")))
|
||||||
(when (find-buffer-visiting new-file)
|
(when (find-buffer-visiting new-file)
|
||||||
(kill-buffer (find-buffer-visiting new-file)))
|
(kill-buffer (find-buffer-visiting new-file)))
|
||||||
(delete-file new-file))
|
(delete-file new-file))
|
||||||
|
(when-let* ((buffer (plist-get org-capture-plist :buffer))
|
||||||
|
(file (buffer-file-name buffer)))
|
||||||
|
(org-id-add-location (org-roam-capture--get :id) file))
|
||||||
(when-let* ((finalize (org-roam-capture--get :finalize))
|
(when-let* ((finalize (org-roam-capture--get :finalize))
|
||||||
(org-roam-finalize-fn (intern (concat "org-roam-capture--finalize-"
|
(org-roam-finalize-fn (intern (concat "org-roam-capture--finalize-"
|
||||||
(symbol-name finalize)))))
|
(symbol-name finalize)))))
|
||||||
@ -716,52 +738,59 @@ This function is to be called in the Org-capture finalization process."
|
|||||||
(buf (marker-buffer mkr)))
|
(buf (marker-buffer mkr)))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(when-let ((region (org-roam-capture--get :region)))
|
(when-let ((region (org-roam-capture--get :region)))
|
||||||
(org-roam-unshield-region (car region) (cdr region))
|
|
||||||
(delete-region (car region) (cdr region))
|
(delete-region (car region) (cdr region))
|
||||||
(set-marker (car region) nil)
|
(set-marker (car region) nil)
|
||||||
(set-marker (cdr region) nil))
|
(set-marker (cdr region) nil))
|
||||||
(org-with-point-at mkr
|
(let* ((id (org-roam-capture--get :id))
|
||||||
(insert (org-link-make-string (concat "id:" (org-roam-capture--get :id))
|
(description (org-roam-capture--get :link-description))
|
||||||
(org-roam-capture--get :link-description)))))))
|
(link (org-link-make-string (concat "id:" id)
|
||||||
|
description)))
|
||||||
|
(if (eq (point) (marker-position mkr))
|
||||||
|
(insert link)
|
||||||
|
(org-with-point-at mkr
|
||||||
|
(insert link)))
|
||||||
|
(run-hook-with-args 'org-roam-post-node-insert-hook
|
||||||
|
id
|
||||||
|
description)))))
|
||||||
|
|
||||||
;;;; Processing of the capture templates
|
;;;; Processing of the capture templates
|
||||||
(defun org-roam-capture--fill-template (template &optional org-capture-p newline)
|
(defun org-roam-capture--fill-template (template &optional ensure-newline)
|
||||||
"Expand TEMPLATE and return it.
|
"Expand TEMPLATE and return it.
|
||||||
It expands ${var} occurrences in TEMPLATE. When ORG-CAPTURE-P,
|
It expands ${var} occurrences in TEMPLATE, and then runs
|
||||||
also run Org-capture's template expansion.
|
org-capture's template expansion.
|
||||||
If NEWLINE, ensure that the template returned ends with a newline."
|
When ENSURE-NEWLINE, always ensure there's a newline behind."
|
||||||
(setq template (org-roam-format-template
|
(let* ((template (if (functionp template)
|
||||||
template
|
(funcall template)
|
||||||
(lambda (key default-val)
|
template))
|
||||||
(let ((fn (intern key))
|
(template-whitespace-content (org-roam-whitespace-content template)))
|
||||||
(node-fn (intern (concat "org-roam-node-" key)))
|
|
||||||
(ksym (intern (concat ":" key))))
|
|
||||||
(cond
|
|
||||||
((fboundp fn)
|
|
||||||
(funcall fn org-roam-capture--node))
|
|
||||||
((fboundp node-fn)
|
|
||||||
(funcall node-fn org-roam-capture--node))
|
|
||||||
((plist-get org-roam-capture--info ksym)
|
|
||||||
(plist-get org-roam-capture--info ksym))
|
|
||||||
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
|
|
||||||
(plist-put org-roam-capture--info ksym r)
|
|
||||||
r)))))))
|
|
||||||
;; WARNING:
|
|
||||||
;; `org-capture-fill-template' fills the template, but post-processes whitespace such that the resultant
|
|
||||||
;; template does not start with any whitespace, and only ends with a single newline
|
|
||||||
;;
|
|
||||||
;; In most cases where we rely on `org-capture-fill-template' to populate non-org-capture-related templates,
|
|
||||||
;; (e.g. in OLPs), we strip the final newline, obtaining a template that seems to be string-trimmed.
|
|
||||||
;;
|
|
||||||
;; This means that if the original passed template has newlines, and ORG-CAPTURE-P is true, then the extra
|
|
||||||
;; whitespace specified in the template will be ignored.
|
|
||||||
(when org-capture-p
|
|
||||||
(setq template
|
(setq template
|
||||||
(replace-regexp-in-string "\n$" "" (org-capture-fill-template template))))
|
(org-roam-format-template
|
||||||
(when (and newline
|
template
|
||||||
(not (string-suffix-p "\n" template)))
|
(lambda (key default-val)
|
||||||
(setq template (concat template "\n")))
|
(let ((fn (intern key))
|
||||||
template)
|
(node-fn (intern (concat "org-roam-node-" key)))
|
||||||
|
(ksym (intern (concat ":" key))))
|
||||||
|
(cond
|
||||||
|
((fboundp fn)
|
||||||
|
(funcall fn org-roam-capture--node))
|
||||||
|
((fboundp node-fn)
|
||||||
|
(funcall node-fn org-roam-capture--node))
|
||||||
|
((plist-get org-roam-capture--info ksym)
|
||||||
|
(plist-get org-roam-capture--info ksym))
|
||||||
|
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
|
||||||
|
(plist-put org-roam-capture--info ksym r)
|
||||||
|
r)))))))
|
||||||
|
;; WARNING:
|
||||||
|
;; `org-capture-fill-template' fills the template, but post-processes whitespace such that the resultant
|
||||||
|
;; template does not start with any whitespace, and only ends with a single newline
|
||||||
|
;;
|
||||||
|
;; Instead, we restore the whitespace in the original template.
|
||||||
|
(setq template (replace-regexp-in-string "[\n]*\\'" "" (org-capture-fill-template template)))
|
||||||
|
(when (and ensure-newline
|
||||||
|
(string-equal template-whitespace-content ""))
|
||||||
|
(setq template-whitespace-content "\n"))
|
||||||
|
(setq template (concat template template-whitespace-content))
|
||||||
|
template))
|
||||||
|
|
||||||
(defun org-roam-capture--convert-template (template &optional props)
|
(defun org-roam-capture--convert-template (template &optional props)
|
||||||
"Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax.
|
"Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax.
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
;;; org-roam-compat.el --- Backward compatibility code -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-compat.el --- Backward compatibility code -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1"))
|
;; Package-Requires: ((emacs "26.1"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -229,6 +229,10 @@ nodes." org-id-locations-file)
|
|||||||
'org-roam-remove-property
|
'org-roam-remove-property
|
||||||
'org-roam-property-remove "org-roam 2.1")
|
'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
|
;;; Obsolete functions
|
||||||
(make-obsolete 'org-roam-get-keyword 'org-collect-keywords "org-roam 2.0")
|
(make-obsolete 'org-roam-get-keyword 'org-collect-keywords "org-roam 2.0")
|
||||||
|
|
||||||
|
239
org-roam-db.el
239
org-roam-db.el
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-db.el --- Org-roam database API -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-db.el --- Org-roam database API -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -31,29 +31,11 @@
|
|||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'org-roam)
|
(require 'org-roam)
|
||||||
|
(require 'url-parse)
|
||||||
|
(require 'ol)
|
||||||
(defvar org-outline-path-cache)
|
(defvar org-outline-path-cache)
|
||||||
|
|
||||||
;;; Options
|
;;; Options
|
||||||
(defcustom org-roam-database-connector 'sqlite
|
|
||||||
"The database connector used by Org-roam.
|
|
||||||
This must be set before `org-roam' is loaded. To use an
|
|
||||||
alternative connector you must install the respective package
|
|
||||||
explicitly. When `sqlite', then use the `emacsql-sqlite' library
|
|
||||||
that is being maintained in the same repository as `emacsql'
|
|
||||||
itself. When `libsqlite3', then use the `emacsql-libsqlite3'
|
|
||||||
library, which itself uses a module provided by the `sqlite3'
|
|
||||||
package. This is still experimental. When `sqlite3', then use the
|
|
||||||
`emacsql-sqlite3' library, which uses the official `sqlite3' cli
|
|
||||||
tool, which is not recommended because it is not suitable to be
|
|
||||||
used like this, but has the advantage that you likely don't need
|
|
||||||
a compiler. See https://nullprogram.com/blog/2014/02/06/."
|
|
||||||
:package-version '(org-roam . "2.2.0")
|
|
||||||
:group 'org-roam
|
|
||||||
:type '(choice (const sqlite)
|
|
||||||
(const libsqlite3)
|
|
||||||
(const sqlite3)
|
|
||||||
(symbol :tag "other")))
|
|
||||||
|
|
||||||
(defcustom org-roam-db-location (locate-user-emacs-file "org-roam.db")
|
(defcustom org-roam-db-location (locate-user-emacs-file "org-roam.db")
|
||||||
"The path to file where the Org-roam database is stored.
|
"The path to file where the Org-roam database is stored.
|
||||||
|
|
||||||
@ -98,8 +80,35 @@ slow."
|
|||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'org-roam)
|
: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
|
;;; Variables
|
||||||
(defconst org-roam-db-version 18)
|
(defconst org-roam-db-version 20)
|
||||||
|
|
||||||
(defvar org-roam-db--connection (make-hash-table :test #'equal)
|
(defvar org-roam-db--connection (make-hash-table :test #'equal)
|
||||||
"Database connection to Org-roam database.")
|
"Database connection to Org-roam database.")
|
||||||
@ -110,26 +119,6 @@ slow."
|
|||||||
(gethash (expand-file-name (file-name-as-directory org-roam-directory))
|
(gethash (expand-file-name (file-name-as-directory org-roam-directory))
|
||||||
org-roam-db--connection))
|
org-roam-db--connection))
|
||||||
|
|
||||||
(declare-function emacsql-sqlite "ext:emacsql-sqlite")
|
|
||||||
(declare-function emacsql-libsqlite3 "ext:emacsql-libsqlite3")
|
|
||||||
(declare-function emacsql-sqlite3 "ext:emacsql-sqlite3")
|
|
||||||
|
|
||||||
(defun org-roam-db--conn-fn ()
|
|
||||||
"Return the function for creating the database connection."
|
|
||||||
(cl-case org-roam-database-connector
|
|
||||||
(sqlite
|
|
||||||
(progn
|
|
||||||
(require 'emacsql-sqlite)
|
|
||||||
#'emacsql-sqlite))
|
|
||||||
(libsqlite3
|
|
||||||
(progn
|
|
||||||
(require 'emacsql-libsqlite3)
|
|
||||||
#'emacsql-libsqlite3))
|
|
||||||
(sqlite3
|
|
||||||
(progn
|
|
||||||
(require 'emacsql-sqlite3)
|
|
||||||
#'emacsql-sqlite3))))
|
|
||||||
|
|
||||||
(defun org-roam-db ()
|
(defun org-roam-db ()
|
||||||
"Entrypoint to the Org-roam sqlite database.
|
"Entrypoint to the Org-roam sqlite database.
|
||||||
Initializes and stores the database, and the database connection.
|
Initializes and stores the database, and the database connection.
|
||||||
@ -138,10 +127,7 @@ Performs a database upgrade when required."
|
|||||||
(emacsql-live-p (org-roam-db--get-connection)))
|
(emacsql-live-p (org-roam-db--get-connection)))
|
||||||
(let ((init-db (not (file-exists-p org-roam-db-location))))
|
(let ((init-db (not (file-exists-p org-roam-db-location))))
|
||||||
(make-directory (file-name-directory org-roam-db-location) t)
|
(make-directory (file-name-directory org-roam-db-location) t)
|
||||||
(let ((conn (funcall (org-roam-db--conn-fn) org-roam-db-location)))
|
(let ((conn (emacsql-sqlite-open org-roam-db-location)))
|
||||||
(emacsql conn [:pragma (= foreign_keys ON)])
|
|
||||||
(when-let ((process (emacsql-process conn)))
|
|
||||||
(set-process-query-on-exit-flag process nil))
|
|
||||||
(puthash (expand-file-name (file-name-as-directory org-roam-directory))
|
(puthash (expand-file-name (file-name-as-directory org-roam-directory))
|
||||||
conn
|
conn
|
||||||
org-roam-db--connection)
|
org-roam-db--connection)
|
||||||
@ -153,7 +139,7 @@ Performs a database upgrade when required."
|
|||||||
((> version org-roam-db-version)
|
((> version org-roam-db-version)
|
||||||
(emacsql-close conn)
|
(emacsql-close conn)
|
||||||
(user-error
|
(user-error
|
||||||
"The Org-roam database was created with a newer Org-roam version. "
|
"The Org-roam database was created with a newer Org-roam version. %s"
|
||||||
"You need to update the Org-roam package"))
|
"You need to update the Org-roam package"))
|
||||||
((< version org-roam-db-version)
|
((< version org-roam-db-version)
|
||||||
(emacsql-close conn)
|
(emacsql-close conn)
|
||||||
@ -295,20 +281,21 @@ If FILE is nil, clear the current buffer."
|
|||||||
If there is no title, return the file name relative to
|
If there is no title, return the file name relative to
|
||||||
`org-roam-directory'."
|
`org-roam-directory'."
|
||||||
(org-link-display-format
|
(org-link-display-format
|
||||||
(or (cadr (assoc "TITLE" (org-collect-keywords '("title"))))
|
(or (string-join (cdr (assoc "TITLE" (org-collect-keywords '("title")))) " ")
|
||||||
(file-name-sans-extension (file-relative-name
|
(file-name-sans-extension (file-relative-name
|
||||||
(buffer-file-name (buffer-base-buffer))
|
(buffer-file-name (buffer-base-buffer))
|
||||||
org-roam-directory)))))
|
org-roam-directory)))))
|
||||||
|
|
||||||
(defun org-roam-db-insert-file ()
|
(defun org-roam-db-insert-file (&optional hash)
|
||||||
"Update the files table for the current buffer.
|
"Update the files table for the current buffer.
|
||||||
If UPDATE-P is non-nil, first remove the file in the database."
|
If UPDATE-P is non-nil, first remove the file in the database.
|
||||||
|
If HASH is non-nil, use that as the file's hash without recalculating it."
|
||||||
(let* ((file (buffer-file-name))
|
(let* ((file (buffer-file-name))
|
||||||
(file-title (org-roam-db--file-title))
|
(file-title (org-roam-db--file-title))
|
||||||
(attr (file-attributes file))
|
(attr (file-attributes file))
|
||||||
(atime (file-attribute-access-time attr))
|
(atime (file-attribute-access-time attr))
|
||||||
(mtime (file-attribute-modification-time attr))
|
(mtime (file-attribute-modification-time attr))
|
||||||
(hash (org-roam-db--file-hash)))
|
(hash (or hash (org-roam-db--file-hash file))))
|
||||||
(org-roam-db-query
|
(org-roam-db-query
|
||||||
[:insert :into files
|
[:insert :into files
|
||||||
:values $v1]
|
:values $v1]
|
||||||
@ -317,12 +304,12 @@ If UPDATE-P is non-nil, first remove the file in the database."
|
|||||||
(defun org-roam-db-get-scheduled-time ()
|
(defun org-roam-db-get-scheduled-time ()
|
||||||
"Return the scheduled time at point in ISO8601 format."
|
"Return the scheduled time at point in ISO8601 format."
|
||||||
(when-let ((time (org-get-scheduled-time (point))))
|
(when-let ((time (org-get-scheduled-time (point))))
|
||||||
(org-format-time-string "%FT%T%z" time)))
|
(format-time-string "%FT%T" time)))
|
||||||
|
|
||||||
(defun org-roam-db-get-deadline-time ()
|
(defun org-roam-db-get-deadline-time ()
|
||||||
"Return the deadline time at point in ISO8601 format."
|
"Return the deadline time at point in ISO8601 format."
|
||||||
(when-let ((time (org-get-deadline-time (point))))
|
(when-let ((time (org-get-deadline-time (point))))
|
||||||
(org-format-time-string "%FT%T%z" time)))
|
(format-time-string "%FT%T" time)))
|
||||||
|
|
||||||
(defun org-roam-db-node-p ()
|
(defun org-roam-db-node-p ()
|
||||||
"Return t if headline at point is an Org-roam node, else return nil."
|
"Return t if headline at point is an Org-roam node, else return nil."
|
||||||
@ -332,12 +319,13 @@ If UPDATE-P is non-nil, first remove the file in the database."
|
|||||||
|
|
||||||
(defun org-roam-db-map-nodes (fns)
|
(defun org-roam-db-map-nodes (fns)
|
||||||
"Run FNS over all nodes in the current buffer."
|
"Run FNS over all nodes in the current buffer."
|
||||||
(org-map-region
|
(org-with-wide-buffer
|
||||||
(lambda ()
|
(org-map-region
|
||||||
(when (org-roam-db-node-p)
|
(lambda ()
|
||||||
(dolist (fn fns)
|
(when (org-roam-db-node-p)
|
||||||
(funcall fn))))
|
(dolist (fn fns)
|
||||||
(point-min) (point-max)))
|
(funcall fn))))
|
||||||
|
(point-min) (point-max))))
|
||||||
|
|
||||||
(defun org-roam-db-map-links (fns)
|
(defun org-roam-db-map-links (fns)
|
||||||
"Run FNS over all links in the current buffer."
|
"Run FNS over all links in the current buffer."
|
||||||
@ -346,30 +334,23 @@ If UPDATE-P is non-nil, first remove the file in the database."
|
|||||||
;; `re-search-forward' let the cursor one character after the link, we need to go backward one char to
|
;; `re-search-forward' let the cursor one character after the link, we need to go backward one char to
|
||||||
;; make the point be on the link.
|
;; make the point be on the link.
|
||||||
(backward-char)
|
(backward-char)
|
||||||
(let* ((element (org-element-context))
|
(let* ((begin (match-beginning 0))
|
||||||
|
(element (org-element-context))
|
||||||
(type (org-element-type element))
|
(type (org-element-type element))
|
||||||
link bounds)
|
link)
|
||||||
(cond
|
(cond
|
||||||
;; Links correctly recognized by Org Mode
|
;; Links correctly recognized by Org Mode
|
||||||
((eq type 'link)
|
((eq type 'link)
|
||||||
(setq link element))
|
(setq link element))
|
||||||
;; Prevent self-referencing links in ROAM_REFS
|
|
||||||
((and (eq type 'node-property)
|
|
||||||
(org-roam-string-equal (org-element-property :key element) "ROAM_REFS"))
|
|
||||||
nil)
|
|
||||||
;; Links in property drawers and lines starting with #+. Recall that, as for Org Mode v9.4.4, the
|
;; 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
|
;; org-element-type of links within properties drawers is "node-property" and for lines starting with
|
||||||
;; #+ is "keyword".
|
;; #+ is "keyword".
|
||||||
((and (or (eq type 'node-property)
|
((and (member type org-roam-db-extra-links-elements)
|
||||||
(eq type 'keyword))
|
(not (member-ignore-case (org-element-property :key element)
|
||||||
(setq bounds (org-in-regexp org-link-any-re))
|
(cdr (assoc type org-roam-db-extra-links-exclude-keys))))
|
||||||
(setq link (buffer-substring-no-properties
|
(setq link (save-excursion
|
||||||
(car bounds)
|
(goto-char begin)
|
||||||
(cdr bounds))))
|
(save-match-data (org-element-link-parser)))))))
|
||||||
(with-temp-buffer
|
|
||||||
(delay-mode-hooks (org-mode))
|
|
||||||
(insert link)
|
|
||||||
(setq link (org-element-context)))))
|
|
||||||
(when link
|
(when link
|
||||||
(dolist (fn fns)
|
(dolist (fn fns)
|
||||||
(funcall fn link)))))))
|
(funcall fn link)))))))
|
||||||
@ -493,9 +474,14 @@ INFO is the org-element parsed buffer."
|
|||||||
(;; https://google.com, cite:citeKey
|
(;; https://google.com, cite:citeKey
|
||||||
;; Note: we use string-match here because it matches any link: e.g. [[cite:abc][abc]]
|
;; Note: we use string-match here because it matches any link: e.g. [[cite:abc][abc]]
|
||||||
;; But this form of matching is loose, and can accept invalid links e.g. [[cite:abc]
|
;; But this form of matching is loose, and can accept invalid links e.g. [[cite:abc]
|
||||||
(string-match org-link-plain-re ref)
|
(string-match org-link-any-re (org-link-encode ref '(#x20)))
|
||||||
(let ((link-type (match-string 1 ref))
|
(setq ref (org-link-encode ref '(#x20)))
|
||||||
(path (match-string 2 ref)))
|
(let ((ref-url (url-generic-parse-url (or (match-string 2 ref) (match-string 0 ref))))
|
||||||
|
(link-type ()) ;; clear url-type for backward compatible.
|
||||||
|
(path ()))
|
||||||
|
(setq link-type (url-type ref-url))
|
||||||
|
(setf (url-type ref-url) nil)
|
||||||
|
(setq path (org-link-decode (url-recreate-url ref-url)))
|
||||||
(if (and (boundp 'org-ref-cite-types)
|
(if (and (boundp 'org-ref-cite-types)
|
||||||
(or (assoc link-type org-ref-cite-types)
|
(or (assoc link-type org-ref-cite-types)
|
||||||
(member link-type org-ref-cite-types)))
|
(member link-type org-ref-cite-types)))
|
||||||
@ -514,12 +500,18 @@ INFO is the org-element parsed buffer."
|
|||||||
"Insert link data for LINK at current point into the Org-roam cache."
|
"Insert link data for LINK at current point into the Org-roam cache."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (org-element-property :begin link))
|
(goto-char (org-element-property :begin link))
|
||||||
(let ((type (org-element-property :type link))
|
(let* ((type (org-element-property :type link))
|
||||||
(path (org-element-property :path link))
|
(path (org-element-property :path link))
|
||||||
(source (org-roam-id-at-point))
|
(option (and (string-match "::\\(.*\\)\\'" path)
|
||||||
(properties (list :outline (ignore-errors
|
(match-string 1 path)))
|
||||||
;; This can error if link is not under any headline
|
(path (if (not option) path
|
||||||
(org-get-outline-path 'with-self 'use-cache)))))
|
(substring path 0 (match-beginning 0))))
|
||||||
|
(source (org-roam-id-at-point))
|
||||||
|
(properties (list :outline (ignore-errors
|
||||||
|
;; This can error if link is not under any headline
|
||||||
|
(org-get-outline-path 'with-self 'use-cache))))
|
||||||
|
(properties (if option (plist-put properties :search-option option)
|
||||||
|
properties)))
|
||||||
;; For Org-ref links, we need to split the path into the cite keys
|
;; For Org-ref links, we need to split the path into the cite keys
|
||||||
(when (and source path)
|
(when (and source path)
|
||||||
(if (and (boundp 'org-ref-cite-types)
|
(if (and (boundp 'org-ref-cite-types)
|
||||||
@ -559,19 +551,12 @@ INFO is the org-element parsed buffer."
|
|||||||
(puthash (car row) (cadr row) ht))
|
(puthash (car row) (cadr row) ht))
|
||||||
ht))
|
ht))
|
||||||
|
|
||||||
(defun org-roam-db--file-hash (&optional file-path)
|
(defun org-roam-db--file-hash (file-path)
|
||||||
"Compute the hash of FILE-PATH, a file or current buffer."
|
"Compute the hash of FILE-PATH."
|
||||||
;; If it is a GPG encrypted file, we always want to compute the hash
|
(with-temp-buffer
|
||||||
;; for the GPG encrypted file (undecrypted)
|
(set-buffer-multibyte nil)
|
||||||
(when (and (not file-path) (equal "gpg" (file-name-extension (buffer-file-name))))
|
(insert-file-contents-literally file-path)
|
||||||
(setq file-path (buffer-file-name)))
|
(secure-hash 'sha1 (current-buffer))))
|
||||||
(if file-path
|
|
||||||
(with-temp-buffer
|
|
||||||
(set-buffer-multibyte nil)
|
|
||||||
(insert-file-contents-literally file-path)
|
|
||||||
(secure-hash 'sha1 (current-buffer)))
|
|
||||||
(org-with-wide-buffer
|
|
||||||
(secure-hash 'sha1 (current-buffer)))))
|
|
||||||
|
|
||||||
;;;; Synchronization
|
;;;; Synchronization
|
||||||
(defun org-roam-db-update-file (&optional file-path no-require)
|
(defun org-roam-db-update-file (&optional file-path no-require)
|
||||||
@ -594,27 +579,28 @@ in `org-roam-db-sync'."
|
|||||||
(org-roam-require '(org-ref oc)))
|
(org-roam-require '(org-ref oc)))
|
||||||
(org-roam-with-file file-path nil
|
(org-roam-with-file file-path nil
|
||||||
(emacsql-with-transaction (org-roam-db)
|
(emacsql-with-transaction (org-roam-db)
|
||||||
(save-excursion
|
(org-with-wide-buffer
|
||||||
(org-set-regexps-and-options 'tags-only)
|
(org-set-regexps-and-options 'tags-only)
|
||||||
(org-refresh-category-properties)
|
;; Org doesn't use this anymore, so we probably should stop too.
|
||||||
(org-roam-db-clear-file)
|
;; (org-refresh-category-properties)
|
||||||
(org-roam-db-insert-file)
|
(org-roam-db-clear-file)
|
||||||
(org-roam-db-insert-file-node)
|
(org-roam-db-insert-file content-hash)
|
||||||
(setq org-outline-path-cache nil)
|
(org-roam-db-insert-file-node)
|
||||||
(org-roam-db-map-nodes
|
(setq org-outline-path-cache nil)
|
||||||
(list #'org-roam-db-insert-node-data
|
(org-roam-db-map-nodes
|
||||||
#'org-roam-db-insert-aliases
|
(list #'org-roam-db-insert-node-data
|
||||||
#'org-roam-db-insert-tags
|
#'org-roam-db-insert-aliases
|
||||||
#'org-roam-db-insert-refs))
|
#'org-roam-db-insert-tags
|
||||||
(setq org-outline-path-cache nil)
|
#'org-roam-db-insert-refs))
|
||||||
(setq info (org-element-parse-buffer))
|
(setq org-outline-path-cache nil)
|
||||||
(org-roam-db-map-links
|
(setq info (org-element-parse-buffer))
|
||||||
(list #'org-roam-db-insert-link))
|
(org-roam-db-map-links
|
||||||
(when (fboundp 'org-cite-insert)
|
(list #'org-roam-db-insert-link))
|
||||||
(require 'oc) ;ensure feature is loaded
|
(when (fboundp 'org-cite-insert)
|
||||||
(org-roam-db-map-citations
|
(require 'oc) ;ensure feature is loaded
|
||||||
info
|
(org-roam-db-map-citations
|
||||||
(list #'org-roam-db-insert-citation)))))))))
|
info
|
||||||
|
(list #'org-roam-db-insert-citation)))))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-db-sync (&optional force)
|
(defun org-roam-db-sync (&optional force)
|
||||||
@ -669,12 +655,14 @@ database, see `org-roam-db-sync' command."
|
|||||||
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
||||||
(advice-add #'rename-file :after #'org-roam-db-autosync--rename-file-a)
|
(advice-add #'rename-file :after #'org-roam-db-autosync--rename-file-a)
|
||||||
(advice-add #'delete-file :before #'org-roam-db-autosync--delete-file-a)
|
(advice-add #'delete-file :before #'org-roam-db-autosync--delete-file-a)
|
||||||
|
(advice-add #'vc-delete-file :around #'org-roam-db-autosync--vc-delete-file-a)
|
||||||
(org-roam-db-sync))
|
(org-roam-db-sync))
|
||||||
(t
|
(t
|
||||||
(remove-hook 'find-file-hook #'org-roam-db-autosync--setup-file-h)
|
(remove-hook 'find-file-hook #'org-roam-db-autosync--setup-file-h)
|
||||||
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
||||||
(advice-remove #'rename-file #'org-roam-db-autosync--rename-file-a)
|
(advice-remove #'rename-file #'org-roam-db-autosync--rename-file-a)
|
||||||
(advice-remove #'delete-file #'org-roam-db-autosync--delete-file-a)
|
(advice-remove #'delete-file #'org-roam-db-autosync--delete-file-a)
|
||||||
|
(advice-remove #'vc-delete-file #'org-roam-db-autosync--vc-delete-file-a)
|
||||||
(org-roam-db--close-all)
|
(org-roam-db--close-all)
|
||||||
;; Disable local hooks for all org-roam buffers
|
;; Disable local hooks for all org-roam buffers
|
||||||
(dolist (buf (org-roam-buffer-list))
|
(dolist (buf (org-roam-buffer-list))
|
||||||
@ -702,6 +690,17 @@ FILE is removed from the database."
|
|||||||
(org-roam-file-p file))
|
(org-roam-file-p file))
|
||||||
(org-roam-db-clear-file (expand-file-name file))))
|
(org-roam-db-clear-file (expand-file-name file))))
|
||||||
|
|
||||||
|
(defun org-roam-db-autosync--vc-delete-file-a (fun file)
|
||||||
|
"Maintain cache consistency on file deletion by FUN.
|
||||||
|
FILE is removed from the database."
|
||||||
|
(let ((org-roam-file-p (and (not (auto-save-file-name-p file))
|
||||||
|
(not (backup-file-name-p file))
|
||||||
|
(org-roam-file-p file))))
|
||||||
|
(apply fun `(,file))
|
||||||
|
(when (and org-roam-file-p
|
||||||
|
(not (file-exists-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)
|
(defun org-roam-db-autosync--rename-file-a (old-file new-file-or-dir &rest _args)
|
||||||
"Maintain cache consistency of file rename.
|
"Maintain cache consistency of file rename.
|
||||||
OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
|
OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
|
||||||
|
94
org-roam-id.el
Normal file
94
org-roam-id.el
Normal 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.1
|
||||||
|
;; 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
53
org-roam-log.el
Normal 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.1
|
||||||
|
;; 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
|
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-migrate.el --- Migration utilities from v1 to v2 -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-migrate.el --- Migration utilities from v1 to v2 -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
|
208
org-roam-mode.el
208
org-roam-mode.el
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-mode.el --- Major mode for special Org-roam buffers -*- lexical-binding: t -*-
|
;;; org-roam-mode.el --- Major mode for special Org-roam buffers -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -39,14 +39,28 @@
|
|||||||
(defvar org-ref-buffer-hacked)
|
(defvar org-ref-buffer-hacked)
|
||||||
|
|
||||||
;;; Options
|
;;; Options
|
||||||
(defcustom org-roam-mode-section-functions (list #'org-roam-backlinks-section
|
(defcustom org-roam-mode-sections (list #'org-roam-backlinks-section
|
||||||
#'org-roam-reflinks-section)
|
#'org-roam-reflinks-section)
|
||||||
"Functions that insert sections in the `org-roam-mode' based buffers.
|
"A list of sections for the `org-roam-mode' based buffers.
|
||||||
Each function is called with one argument, which is an
|
Each section is a function that is passed the `org-roam-node'
|
||||||
`org-roam-node' for which the buffer will be constructed for.
|
for which the section will be constructed as the first
|
||||||
Normally this node is `org-roam-buffer-current-node'."
|
argument. Normally this node is `org-roam-buffer-current-node'.
|
||||||
|
The function may also accept other optional arguments. Each item
|
||||||
|
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
|
:group 'org-roam
|
||||||
:type 'hook)
|
: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)
|
(defcustom org-roam-buffer-postrender-functions (list)
|
||||||
"Functions to run after the Org-roam buffer is rendered.
|
"Functions to run after the Org-roam buffer is rendered.
|
||||||
@ -168,7 +182,7 @@ This mode is used by special Org-roam buffers, such as persistent
|
|||||||
`org-roam-buffer' and dedicated Org-roam buffers
|
`org-roam-buffer' and dedicated Org-roam buffers
|
||||||
\(`org-roam-buffer-display-dedicated'), which render the
|
\(`org-roam-buffer-display-dedicated'), which render the
|
||||||
information in a section-like manner (see
|
information in a section-like manner (see
|
||||||
`org-roam-mode-section-functions'), with which the user can
|
`org-roam-mode-sections'), with which the user can
|
||||||
interact with."
|
interact with."
|
||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
(face-remap-add-relative 'header-line 'org-roam-header-line))
|
(face-remap-add-relative 'header-line 'org-roam-header-line))
|
||||||
@ -228,7 +242,14 @@ buffer."
|
|||||||
(org-roam-node-title org-roam-buffer-current-node))
|
(org-roam-node-title org-roam-buffer-current-node))
|
||||||
(magit-insert-section (org-roam)
|
(magit-insert-section (org-roam)
|
||||||
(magit-insert-heading)
|
(magit-insert-heading)
|
||||||
(run-hook-with-args 'org-roam-mode-section-functions org-roam-buffer-current-node))
|
(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)
|
(run-hooks 'org-roam-buffer-postrender-functions)
|
||||||
(goto-char 0)))
|
(goto-char 0)))
|
||||||
|
|
||||||
@ -289,7 +310,7 @@ To toggle its display use `org-roam-buffer-toggle' command.")
|
|||||||
(pcase (org-roam-buffer--visibility)
|
(pcase (org-roam-buffer--visibility)
|
||||||
('visible
|
('visible
|
||||||
(progn
|
(progn
|
||||||
(delete-window (get-buffer-window org-roam-buffer))
|
(quit-window nil (get-buffer-window org-roam-buffer))
|
||||||
(remove-hook 'post-command-hook #'org-roam-buffer--redisplay-h)))
|
(remove-hook 'post-command-hook #'org-roam-buffer--redisplay-h)))
|
||||||
((or 'exists 'none)
|
((or 'exists 'none)
|
||||||
(progn
|
(progn
|
||||||
@ -298,7 +319,7 @@ To toggle its display use `org-roam-buffer-toggle' command.")
|
|||||||
|
|
||||||
(define-inline org-roam-buffer--visibility ()
|
(define-inline org-roam-buffer--visibility ()
|
||||||
"Return the current visibility state of the persistent `org-roam-buffer'.
|
"Return the current visibility state of the persistent `org-roam-buffer'.
|
||||||
Valid states are 'visible, 'exists and 'none."
|
Valid states are `visible', `exists' and `none'."
|
||||||
(declare (side-effect-free t))
|
(declare (side-effect-free t))
|
||||||
(inline-quote
|
(inline-quote
|
||||||
(cond
|
(cond
|
||||||
@ -318,7 +339,7 @@ Has no effect when there's no `org-roam-node-at-point'."
|
|||||||
(add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t)))))
|
(add-hook 'kill-buffer-hook #'org-roam-buffer--persistent-cleanup-h nil t)))))
|
||||||
|
|
||||||
(defun org-roam-buffer--persistent-cleanup-h ()
|
(defun org-roam-buffer--persistent-cleanup-h ()
|
||||||
"Clean-up global state thats dedicated for the persistent `org-roam-buffer'."
|
"Clean-up global state that's dedicated for the persistent `org-roam-buffer'."
|
||||||
(setq-default org-roam-buffer-current-node nil
|
(setq-default org-roam-buffer-current-node nil
|
||||||
org-roam-buffer-current-directory nil))
|
org-roam-buffer-current-directory nil))
|
||||||
|
|
||||||
@ -420,7 +441,7 @@ In interactive calls OTHER-WINDOW is set with
|
|||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(widen)
|
(widen)
|
||||||
(goto-char point))
|
(goto-char point))
|
||||||
(when (org-invisible-p) (org-show-context))
|
(when (org-invisible-p) (org-fold-show-context))
|
||||||
buf))
|
buf))
|
||||||
|
|
||||||
(defun org-roam-preview-default-function ()
|
(defun org-roam-preview-default-function ()
|
||||||
@ -428,10 +449,12 @@ In interactive calls OTHER-WINDOW is set with
|
|||||||
|
|
||||||
This function returns the all contents under the current
|
This function returns the all contents under the current
|
||||||
headline, up to the next headline."
|
headline, up to the next headline."
|
||||||
(let ((beg (progn (org-roam-end-of-meta-data t)
|
(let ((beg (save-excursion
|
||||||
(point)))
|
(org-roam-end-of-meta-data t)
|
||||||
(end (progn (org-next-visible-heading 1)
|
(point)))
|
||||||
(point))))
|
(end (save-excursion
|
||||||
|
(org-next-visible-heading 1)
|
||||||
|
(point))))
|
||||||
(string-trim (buffer-substring-no-properties beg end))))
|
(string-trim (buffer-substring-no-properties beg end))))
|
||||||
|
|
||||||
(defun org-roam-preview-get-contents (file pt)
|
(defun org-roam-preview-get-contents (file pt)
|
||||||
@ -459,14 +482,23 @@ headline, up to the next headline."
|
|||||||
(org-roam-populate (org-roam-backlink-target-node backlink)))
|
(org-roam-populate (org-roam-backlink-target-node backlink)))
|
||||||
backlink)
|
backlink)
|
||||||
|
|
||||||
(defun org-roam-backlinks-get (node)
|
(cl-defun org-roam-backlinks-get (node &key unique)
|
||||||
"Return the backlinks for NODE."
|
"Return the backlinks for NODE.
|
||||||
(let ((backlinks (org-roam-db-query
|
|
||||||
[:select [source dest pos properties]
|
When UNIQUE is nil, show all positions where references are found.
|
||||||
:from links
|
When UNIQUE is t, limit to unique sources."
|
||||||
:where (= dest $s1)
|
(let* ((sql (if unique
|
||||||
:and (= type "id")]
|
[:select :distinct [source dest pos properties]
|
||||||
(org-roam-node-id node))))
|
: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
|
(cl-loop for backlink in backlinks
|
||||||
collect (pcase-let ((`(,source-id ,dest-id ,pos ,properties) backlink))
|
collect (pcase-let ((`(,source-id ,dest-id ,pos ,properties) backlink))
|
||||||
(org-roam-populate
|
(org-roam-populate
|
||||||
@ -482,16 +514,28 @@ Sorts by title."
|
|||||||
(string< (org-roam-node-title (org-roam-backlink-source-node a))
|
(string< (org-roam-node-title (org-roam-backlink-source-node a))
|
||||||
(org-roam-node-title (org-roam-backlink-source-node b))))
|
(org-roam-node-title (org-roam-backlink-source-node b))))
|
||||||
|
|
||||||
(defun org-roam-backlinks-section (node)
|
(cl-defun org-roam-backlinks-section (node &key (unique nil) (show-backlink-p nil)
|
||||||
"The backlinks section for NODE."
|
(section-heading "Backlinks:"))
|
||||||
(when-let ((backlinks (seq-sort #'org-roam-backlinks-sort (org-roam-backlinks-get node))))
|
"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-section (org-roam-backlinks)
|
||||||
(magit-insert-heading "Backlinks:")
|
(magit-insert-heading section-heading)
|
||||||
(dolist (backlink backlinks)
|
(dolist (backlink backlinks)
|
||||||
(org-roam-node-insert-section
|
(when (or (null show-backlink-p)
|
||||||
:source-node (org-roam-backlink-source-node backlink)
|
(and (not (null show-backlink-p))
|
||||||
:point (org-roam-backlink-point backlink)
|
(funcall show-backlink-p backlink)))
|
||||||
:properties (org-roam-backlink-properties backlink)))
|
(org-roam-node-insert-section
|
||||||
|
:source-node (org-roam-backlink-source-node backlink)
|
||||||
|
:point (org-roam-backlink-point backlink)
|
||||||
|
:properties (org-roam-backlink-properties backlink))))
|
||||||
(insert ?\n))))
|
(insert ?\n))))
|
||||||
|
|
||||||
;;;; Reflinks
|
;;;; Reflinks
|
||||||
@ -586,7 +630,7 @@ instead."
|
|||||||
(forward-line (1- row)))
|
(forward-line (1- row)))
|
||||||
(when col
|
(when col
|
||||||
(forward-char (1- col))))
|
(forward-char (1- col))))
|
||||||
(when (org-invisible-p) (org-show-context))
|
(when (org-invisible-p) (org-fold-show-context))
|
||||||
buf))
|
buf))
|
||||||
|
|
||||||
;;;; Unlinked references
|
;;;; Unlinked references
|
||||||
@ -614,49 +658,69 @@ This is the ROW within FILE."
|
|||||||
(end-of-line)
|
(end-of-line)
|
||||||
(point)))))
|
(point)))))
|
||||||
|
|
||||||
|
(defun org-roam-unlinked-references--rg-command (titles temp-file)
|
||||||
|
"Return the ripgrep command searching for TITLES using TEMP-FILE for pattern.
|
||||||
|
This avoids shell escaping issues by writing the pattern to a file instead
|
||||||
|
of passing it directly through the shell command line."
|
||||||
|
;; Write pattern to temp file to avoid shell escaping issues with quotes,
|
||||||
|
;; spaces, and other special characters in titles
|
||||||
|
(with-temp-file temp-file
|
||||||
|
(insert "\\[([^[]]++|(?R))*\\]"
|
||||||
|
(mapconcat (lambda (title)
|
||||||
|
;; Use regexp-quote instead of shell-quote-argument
|
||||||
|
;; since we're writing a regex pattern, not a shell argument
|
||||||
|
(format "|(\\b%s\\b)" (regexp-quote title)))
|
||||||
|
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)
|
||||||
|
" ")
|
||||||
|
" --file " (shell-quote-argument temp-file) " "
|
||||||
|
(shell-quote-argument (expand-file-name org-roam-directory))))
|
||||||
|
|
||||||
(defun org-roam-unlinked-references-section (node)
|
(defun org-roam-unlinked-references-section (node)
|
||||||
"The unlinked references section for NODE.
|
"The unlinked references section for NODE.
|
||||||
References from FILE are excluded."
|
References from FILE are excluded."
|
||||||
(when (and (executable-find "rg")
|
(when (and (executable-find "rg")
|
||||||
|
(org-roam-node-title node)
|
||||||
(not (string-match "PCRE2 is not available"
|
(not (string-match "PCRE2 is not available"
|
||||||
(shell-command-to-string "rg --pcre2-version"))))
|
(shell-command-to-string "rg --pcre2-version"))))
|
||||||
(let* ((titles (cons (org-roam-node-title node)
|
(let* ((titles (cons (org-roam-node-title node)
|
||||||
(org-roam-node-aliases node)))
|
(org-roam-node-aliases node)))
|
||||||
(rg-command (concat "rg -o --vimgrep -P -i "
|
;; Create temp file for the regex pattern
|
||||||
(mapconcat (lambda (glob) (concat "-g " glob))
|
(temp-file (make-temp-file "org-roam-rg-pattern-"))
|
||||||
(org-roam--list-files-search-globs org-roam-file-extensions)
|
(rg-command (org-roam-unlinked-references--rg-command titles temp-file)))
|
||||||
" ")
|
;; Use unwind-protect to ensure temp file cleanup even if errors occur
|
||||||
(format " '\\[([^[]]++|(?R))*\\]%s' "
|
(unwind-protect
|
||||||
(mapconcat (lambda (title)
|
(let* ((results (split-string (shell-command-to-string rg-command) "\n"))
|
||||||
(format "|(\\b%s\\b)" (shell-quote-argument title)))
|
f row col match)
|
||||||
titles ""))
|
(magit-insert-section (unlinked-references)
|
||||||
org-roam-directory))
|
(magit-insert-heading "Unlinked References:")
|
||||||
(results (split-string (shell-command-to-string rg-command) "\n"))
|
(dolist (line results)
|
||||||
f row col match)
|
(save-match-data
|
||||||
(magit-insert-section (unlinked-references)
|
(when (string-match org-roam-unlinked-references-result-re line)
|
||||||
(magit-insert-heading "Unlinked References:")
|
(setq f (match-string 1 line)
|
||||||
(dolist (line results)
|
row (string-to-number (match-string 2 line))
|
||||||
(save-match-data
|
col (string-to-number (match-string 3 line))
|
||||||
(when (string-match org-roam-unlinked-references-result-re line)
|
match (match-string 4 line))
|
||||||
(setq f (match-string 1 line)
|
(when (and match
|
||||||
row (string-to-number (match-string 2 line))
|
(not (file-equal-p (org-roam-node-file node) f))
|
||||||
col (string-to-number (match-string 3 line))
|
(member (downcase match) (mapcar #'downcase titles)))
|
||||||
match (match-string 4 line))
|
(magit-insert-section section (org-roam-grep-section)
|
||||||
(when (and match
|
(oset section file f)
|
||||||
(not (f-equal-p (org-roam-node-file node) f))
|
(oset section row row)
|
||||||
(member (downcase match) (mapcar #'downcase titles)))
|
(oset section col col)
|
||||||
(magit-insert-section section (org-roam-grep-section)
|
(insert (propertize (format "%s:%s:%s"
|
||||||
(oset section file f)
|
(truncate-string-to-width (file-name-base f) 15 nil nil t)
|
||||||
(oset section row row)
|
row col) 'font-lock-face 'org-roam-dim)
|
||||||
(oset section col col)
|
" "
|
||||||
(insert (propertize (format "%s:%s:%s"
|
(org-roam-fontify-like-in-org-mode
|
||||||
(truncate-string-to-width (file-name-base f) 15 nil nil t)
|
(org-roam-unlinked-references-preview-line f row))
|
||||||
row col) 'font-lock-face 'org-roam-dim)
|
"\n"))))))
|
||||||
" "
|
(insert ?\n)))
|
||||||
(org-roam-fontify-like-in-org-mode
|
;; Clean up temp file - this runs even if an error occurs above
|
||||||
(org-roam-unlinked-references-preview-line f row))
|
(delete-file temp-file)))))
|
||||||
"\n"))))))
|
|
||||||
(insert ?\n)))))
|
|
||||||
|
|
||||||
(provide 'org-roam-mode)
|
(provide 'org-roam-mode)
|
||||||
;;; org-roam-mode.el ends here
|
;;; org-roam-mode.el ends here
|
||||||
|
449
org-roam-node.el
449
org-roam-node.el
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-node.el --- Interfacing and interacting with nodes -*- lexical-binding: t; -*-
|
;;; org-roam-node.el --- Interfacing and interacting with nodes -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (magit-section "3.0.0"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (magit-section "3.0.0"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -32,13 +32,23 @@
|
|||||||
;; interactively.
|
;; interactively.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
(require 'crm)
|
||||||
(require 'org-roam)
|
(require 'org-roam)
|
||||||
|
|
||||||
;;; Options
|
;;; Options
|
||||||
;;;; Completing-read
|
;;;; Completing-read
|
||||||
(defcustom org-roam-node-display-template
|
(defcustom org-roam-node-display-template "${title}"
|
||||||
(concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag))
|
|
||||||
"Configures display formatting for Org-roam node.
|
"Configures display formatting for Org-roam node.
|
||||||
|
|
||||||
|
If it is a function, it will be called to format a node.
|
||||||
|
Its result is expected to be a string (potentially with
|
||||||
|
embedded properties).
|
||||||
|
|
||||||
|
If it is a string and it will be used as described in org-roam
|
||||||
|
(see org-roam-node-display-template)
|
||||||
|
|
||||||
|
When it is a string, the following processing is done:
|
||||||
|
|
||||||
Patterns of form \"${field-name:length}\" are interpolated based
|
Patterns of form \"${field-name:length}\" are interpolated based
|
||||||
on the current node.
|
on the current node.
|
||||||
|
|
||||||
@ -64,9 +74,23 @@ as many characters as possible and will be aligned accordingly.
|
|||||||
|
|
||||||
A closure can also be assigned to this variable in which case the
|
A closure can also be assigned to this variable in which case the
|
||||||
closure is evaluated and the return value is used as the
|
closure is evaluated and the return value is used as the
|
||||||
template. The closure must evaluate to a valid template string."
|
template. The closure must evaluate to a valid template string.
|
||||||
|
|
||||||
|
When org-roam-node-display-template is a function, the function is
|
||||||
|
expected to return a string, potentially propertized. For example, the
|
||||||
|
following function shows the title and base filename of the node:
|
||||||
|
|
||||||
|
\(defun my--org-roam-format (node)
|
||||||
|
\"formats the node\"
|
||||||
|
(format \"%-40s %s\"
|
||||||
|
(if (org-roam-node-title node)
|
||||||
|
(propertize (org-roam-node-title node) 'face 'org-todo)
|
||||||
|
\"\")
|
||||||
|
(file-name-nondirectory (org-roam-node-file node))))
|
||||||
|
|
||||||
|
\q(setq org-roam-node-display-template 'my--org-roam-format)"
|
||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
:type '(string function))
|
:type '(choice string function))
|
||||||
|
|
||||||
(defcustom org-roam-node-annotation-function #'org-roam-node-read--annotation
|
(defcustom org-roam-node-annotation-function #'org-roam-node-read--annotation
|
||||||
"This function used to attach annotations for `org-roam-node-read'.
|
"This function used to attach annotations for `org-roam-node-read'.
|
||||||
@ -90,7 +114,7 @@ argument, an `org-roam-node', and return a string.
|
|||||||
If a string is provided, it is a template string expanded by
|
If a string is provided, it is a template string expanded by
|
||||||
`org-roam-node--format-entry'."
|
`org-roam-node--format-entry'."
|
||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
:type '(string function))
|
:type '(choice string function))
|
||||||
|
|
||||||
(defcustom org-roam-node-template-prefixes
|
(defcustom org-roam-node-template-prefixes
|
||||||
'(("tags" . "#")
|
'(("tags" . "#")
|
||||||
@ -113,6 +137,12 @@ It takes a single argument REF, which is a propertized string."
|
|||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
:type '(function))
|
:type '(function))
|
||||||
|
|
||||||
|
(defcustom org-roam-ref-prompt-function nil
|
||||||
|
"Function to prompt for ref strings in `org-roam-ref-add'.
|
||||||
|
Should take no arguments, prompt the user, and return a string."
|
||||||
|
:group 'org-roam
|
||||||
|
:type 'function)
|
||||||
|
|
||||||
;;;; Completion-at-point
|
;;;; Completion-at-point
|
||||||
(defcustom org-roam-completion-everywhere nil
|
(defcustom org-roam-completion-everywhere nil
|
||||||
"When non-nil, provide link completion matching outside of Org links."
|
"When non-nil, provide link completion matching outside of Org links."
|
||||||
@ -132,10 +162,15 @@ It takes a single argument REF, which is a propertized string."
|
|||||||
:type 'boolean)
|
:type 'boolean)
|
||||||
|
|
||||||
(defcustom org-roam-extract-new-file-path "%<%Y%m%d%H%M%S>-${slug}.org"
|
(defcustom org-roam-extract-new-file-path "%<%Y%m%d%H%M%S>-${slug}.org"
|
||||||
"The file path to use when a node is extracted to its own file."
|
"The file path template to use when a node is extracted to its own file.
|
||||||
|
This path is relative to `org-roam-directory'."
|
||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
:type 'string)
|
:type 'string)
|
||||||
|
|
||||||
|
(defvar org-roam-link-type "roam"
|
||||||
|
"Link type for org-roam nodes.
|
||||||
|
Replaced by `id' automatically when `org-roam-link-auto-replace' is non-nil.")
|
||||||
|
|
||||||
(defvar org-roam-node-history nil
|
(defvar org-roam-node-history nil
|
||||||
"Minibuffer history of nodes.")
|
"Minibuffer history of nodes.")
|
||||||
|
|
||||||
@ -144,6 +179,11 @@ It takes a single argument REF, which is a propertized string."
|
|||||||
|
|
||||||
;;; Definition
|
;;; Definition
|
||||||
(cl-defstruct (org-roam-node (:constructor org-roam-node-create)
|
(cl-defstruct (org-roam-node (:constructor org-roam-node-create)
|
||||||
|
(:constructor org-roam-node-create-from-db
|
||||||
|
(title aliases ; 2
|
||||||
|
id file file-title level todo ; 5
|
||||||
|
point priority scheduled deadline properties ;;5
|
||||||
|
olp file-atime file-mtime tags refs)) ;;5
|
||||||
(:copier nil))
|
(:copier nil))
|
||||||
"A heading or top level file with an assigned ID property."
|
"A heading or top level file with an assigned ID property."
|
||||||
file file-title file-hash file-atime file-mtime
|
file file-title file-hash file-atime file-mtime
|
||||||
@ -175,6 +215,7 @@ It takes a single argument REF, which is a propertized string."
|
|||||||
776 ; U+0308 COMBINING DIAERESIS
|
776 ; U+0308 COMBINING DIAERESIS
|
||||||
777 ; U+0309 COMBINING HOOK ABOVE
|
777 ; U+0309 COMBINING HOOK ABOVE
|
||||||
778 ; U+030A COMBINING RING ABOVE
|
778 ; U+030A COMBINING RING ABOVE
|
||||||
|
779 ; U+030B COMBINING DOUBLE ACUTE ACCENT
|
||||||
780 ; U+030C COMBINING CARON
|
780 ; U+030C COMBINING CARON
|
||||||
795 ; U+031B COMBINING HORN
|
795 ; U+031B COMBINING HORN
|
||||||
803 ; U+0323 COMBINING DOT BELOW
|
803 ; U+0323 COMBINING DOT BELOW
|
||||||
@ -186,14 +227,12 @@ It takes a single argument REF, which is a propertized string."
|
|||||||
816 ; U+0330 COMBINING TILDE BELOW
|
816 ; U+0330 COMBINING TILDE BELOW
|
||||||
817 ; U+0331 COMBINING MACRON BELOW
|
817 ; U+0331 COMBINING MACRON BELOW
|
||||||
)))
|
)))
|
||||||
(cl-flet* ((nonspacing-mark-p (char)
|
(cl-flet* ((nonspacing-mark-p (char) (memq char slug-trim-chars))
|
||||||
(memq char slug-trim-chars))
|
(strip-nonspacing-marks (s) (string-glyph-compose
|
||||||
(strip-nonspacing-marks (s)
|
(apply #'string
|
||||||
(string-glyph-compose
|
(seq-remove #'nonspacing-mark-p
|
||||||
(apply #'string (seq-remove #'nonspacing-mark-p
|
(string-glyph-decompose s)))))
|
||||||
(string-glyph-decompose s)))))
|
(cl-replace (title pair) (replace-regexp-in-string (car pair) (cdr pair) title)))
|
||||||
(cl-replace (title pair)
|
|
||||||
(replace-regexp-in-string (car pair) (cdr pair) title)))
|
|
||||||
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
|
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
|
||||||
("__*" . "_") ;; remove sequential underscores
|
("__*" . "_") ;; remove sequential underscores
|
||||||
("^_" . "") ;; remove starting underscore
|
("^_" . "") ;; remove starting underscore
|
||||||
@ -211,6 +250,10 @@ It takes a single argument REF, which is a propertized string."
|
|||||||
(_
|
(_
|
||||||
(org-roam-node-title node))))
|
(org-roam-node-title node))))
|
||||||
|
|
||||||
|
(cl-defmethod org-roam-node-category ((node org-roam-node))
|
||||||
|
"Return the category for NODE."
|
||||||
|
(cdr (assoc-string "CATEGORY" (org-roam-node-properties node))))
|
||||||
|
|
||||||
;;; Nodes
|
;;; Nodes
|
||||||
;;;; Getters
|
;;;; Getters
|
||||||
(defun org-roam-node-at-point (&optional assert)
|
(defun org-roam-node-at-point (&optional assert)
|
||||||
@ -225,9 +268,12 @@ populated."
|
|||||||
(magit-section-up)
|
(magit-section-up)
|
||||||
(org-roam-node-at-point)))
|
(org-roam-node-at-point)))
|
||||||
(t (org-with-wide-buffer
|
(t (org-with-wide-buffer
|
||||||
(org-back-to-heading-or-point-min t)
|
(while (not (or (org-roam-db-node-p)
|
||||||
(while (and (not (org-roam-db-node-p))
|
(bobp)
|
||||||
(not (bobp)))
|
(eq (funcall outline-level)
|
||||||
|
(save-excursion
|
||||||
|
(org-roam-up-heading-or-point-min)
|
||||||
|
(funcall outline-level)))))
|
||||||
(org-roam-up-heading-or-point-min))
|
(org-roam-up-heading-or-point-min))
|
||||||
(when-let ((id (org-id-get)))
|
(when-let ((id (org-id-get)))
|
||||||
(org-roam-populate
|
(org-roam-populate
|
||||||
@ -244,17 +290,21 @@ Return nil if a node with ID does not exist."
|
|||||||
id)) 0)
|
id)) 0)
|
||||||
(org-roam-populate (org-roam-node-create :id id))))
|
(org-roam-populate (org-roam-node-create :id id))))
|
||||||
|
|
||||||
(defun org-roam-node-from-title-or-alias (s)
|
(defun org-roam-node-from-title-or-alias (s &optional nocase)
|
||||||
"Return an `org-roam-node' for the node with title or alias S.
|
"Return an `org-roam-node' for the node with title or alias S.
|
||||||
Return nil if the node does not exist.
|
Return nil if the node does not exist.
|
||||||
Throw an error if multiple choices exist."
|
Throw an error if multiple choices exist.
|
||||||
|
|
||||||
|
If NOCASE is non-nil, the query is case insensitive. It is case sensitive otherwise."
|
||||||
(let ((matches (seq-uniq
|
(let ((matches (seq-uniq
|
||||||
(append
|
(append
|
||||||
(org-roam-db-query [:select [id] :from nodes
|
(org-roam-db-query (vconcat [:select [id] :from nodes
|
||||||
:where (= title $s1)]
|
:where (= title $s1)]
|
||||||
|
(if nocase [ :collate NOCASE ]))
|
||||||
s)
|
s)
|
||||||
(org-roam-db-query [:select [node-id] :from aliases
|
(org-roam-db-query (vconcat [:select [node-id] :from aliases
|
||||||
:where (= alias $s1)]
|
:where (= alias $s1)]
|
||||||
|
(if nocase [ :collate NOCASE ]))
|
||||||
s)))))
|
s)))))
|
||||||
(cond
|
(cond
|
||||||
((seq-empty-p matches)
|
((seq-empty-p matches)
|
||||||
@ -293,7 +343,8 @@ Return nil if there's no node with such REF."
|
|||||||
Uses the ID, and fetches remaining details from the database.
|
Uses the ID, and fetches remaining details from the database.
|
||||||
This can be quite costly: avoid, unless dealing with very few
|
This can be quite costly: avoid, unless dealing with very few
|
||||||
nodes."
|
nodes."
|
||||||
(when-let ((node-info (car (org-roam-db-query [:select [file level pos todo priority
|
(when-let ((node-info (car (org-roam-db-query [:select [
|
||||||
|
file level pos todo priority
|
||||||
scheduled deadline title properties olp]
|
scheduled deadline title properties olp]
|
||||||
:from nodes
|
:from nodes
|
||||||
:where (= id $s1)
|
:where (= id $s1)
|
||||||
@ -334,23 +385,27 @@ nodes."
|
|||||||
(defun org-roam-node-list ()
|
(defun org-roam-node-list ()
|
||||||
"Return all nodes stored in the database as a list of `org-roam-node's."
|
"Return all nodes stored in the database as a list of `org-roam-node's."
|
||||||
(let ((rows (org-roam-db-query
|
(let ((rows (org-roam-db-query
|
||||||
"SELECT
|
"
|
||||||
|
SELECT
|
||||||
|
title,
|
||||||
|
aliases,
|
||||||
|
|
||||||
id,
|
id,
|
||||||
file,
|
file,
|
||||||
filetitle,
|
filetitle,
|
||||||
\"level\",
|
\"level\",
|
||||||
todo,
|
todo,
|
||||||
|
|
||||||
pos,
|
pos,
|
||||||
priority ,
|
priority ,
|
||||||
scheduled ,
|
scheduled ,
|
||||||
deadline ,
|
deadline ,
|
||||||
title,
|
|
||||||
properties ,
|
properties ,
|
||||||
|
|
||||||
olp,
|
olp,
|
||||||
atime,
|
atime,
|
||||||
mtime,
|
mtime,
|
||||||
'(' || group_concat(tags, ' ') || ')' as tags,
|
'(' || group_concat(tags, ' ') || ')' as tags,
|
||||||
aliases,
|
|
||||||
refs
|
refs
|
||||||
FROM
|
FROM
|
||||||
(
|
(
|
||||||
@ -399,46 +454,56 @@ FROM
|
|||||||
LEFT JOIN refs ON refs.node_id = nodes.id
|
LEFT JOIN refs ON refs.node_id = nodes.id
|
||||||
GROUP BY nodes.id, tags.tag, aliases.alias )
|
GROUP BY nodes.id, tags.tag, aliases.alias )
|
||||||
GROUP BY id, tags )
|
GROUP BY id, tags )
|
||||||
GROUP BY id")))
|
GROUP BY id
|
||||||
(cl-loop for row in rows
|
")))
|
||||||
append (pcase-let* ((`(,id ,file ,file-title ,level ,todo ,pos ,priority ,scheduled ,deadline
|
(mapcan
|
||||||
,title ,properties ,olp ,atime ,mtime ,tags ,aliases ,refs)
|
(lambda (row)
|
||||||
row)
|
(let (
|
||||||
(all-titles (cons title aliases)))
|
(all-titles (cons (car row) (nth 1 row)))
|
||||||
(mapcar (lambda (temp-title)
|
)
|
||||||
(org-roam-node-create :id id
|
(mapcar (lambda (temp-title)
|
||||||
:file file
|
(apply 'org-roam-node-create-from-db (cons temp-title (cdr row))))
|
||||||
:file-title file-title
|
all-titles)
|
||||||
:file-atime atime
|
))
|
||||||
:file-mtime mtime
|
rows)
|
||||||
:level level
|
)
|
||||||
:point pos
|
)
|
||||||
:todo todo
|
|
||||||
:priority priority
|
|
||||||
:scheduled scheduled
|
|
||||||
:deadline deadline
|
|
||||||
:title temp-title
|
|
||||||
:aliases aliases
|
|
||||||
:properties properties
|
|
||||||
:olp olp
|
|
||||||
:tags tags
|
|
||||||
:refs refs))
|
|
||||||
all-titles)))))
|
|
||||||
|
|
||||||
;;;; Finders
|
;;;; Finders
|
||||||
(defun org-roam-node-find-noselect (node &optional force)
|
(defun org-roam-node-marker (node)
|
||||||
"Navigate to the point for NODE, and return the buffer.
|
"Get the marker for NODE."
|
||||||
If NODE is already visited, this won't automatically move the
|
(let* ((file (org-roam-node-file node))
|
||||||
point to the beginning of the NODE, unless FORCE is non-nil."
|
(buffer (or (find-buffer-visiting file)
|
||||||
(unless (org-roam-node-file node)
|
(find-file-noselect file))))
|
||||||
(user-error "Node does not have corresponding file"))
|
(with-current-buffer buffer
|
||||||
(let ((buf (find-file-noselect (org-roam-node-file node))))
|
(move-marker (make-marker) (org-roam-node-point node) buffer))))
|
||||||
(with-current-buffer buf
|
|
||||||
(when (or force
|
(defun org-roam-node-open (node &optional cmd force)
|
||||||
(not (equal (org-roam-node-id node)
|
"Go to the node NODE.
|
||||||
(org-roam-id-at-point))))
|
CMD is the command used to display the buffer. If not provided,
|
||||||
(goto-char (org-roam-node-point node))))
|
`org-link-frame-setup' is respected. Assumes that the node is
|
||||||
buf))
|
fully populated, with file and point. If NODE is already visited,
|
||||||
|
this won't automatically move the point to the beginning of the
|
||||||
|
NODE, unless FORCE is non-nil."
|
||||||
|
(interactive (list (org-roam-node-at-point) current-prefix-arg))
|
||||||
|
(org-mark-ring-push)
|
||||||
|
(let ((m (org-roam-node-marker node))
|
||||||
|
(cmd (or cmd
|
||||||
|
(cdr
|
||||||
|
(assq
|
||||||
|
(cdr (assq 'file org-link-frame-setup))
|
||||||
|
'((find-file . switch-to-buffer)
|
||||||
|
(find-file-other-window . switch-to-buffer-other-window)
|
||||||
|
(find-file-other-frame . switch-to-buffer-other-frame))))
|
||||||
|
'switch-to-buffer-other-window)))
|
||||||
|
(if (not (equal (current-buffer) (marker-buffer m)))
|
||||||
|
(funcall cmd (marker-buffer m)))
|
||||||
|
(when (or force
|
||||||
|
(not (equal (org-roam-node-id node)
|
||||||
|
(org-roam-id-at-point))))
|
||||||
|
(goto-char m))
|
||||||
|
(move-marker m nil))
|
||||||
|
(org-fold-show-context))
|
||||||
|
|
||||||
(defun org-roam-node-visit (node &optional other-window force)
|
(defun org-roam-node-visit (node &optional other-window force)
|
||||||
"From the current buffer, visit NODE. Return the visited buffer.
|
"From the current buffer, visit NODE. Return the visited buffer.
|
||||||
@ -450,16 +515,13 @@ If NODE is already visited, this won't automatically move the
|
|||||||
point to the beginning of the NODE, unless FORCE is non-nil. In
|
point to the beginning of the NODE, unless FORCE is non-nil. In
|
||||||
interactive calls FORCE always set to t."
|
interactive calls FORCE always set to t."
|
||||||
(interactive (list (org-roam-node-at-point t) current-prefix-arg t))
|
(interactive (list (org-roam-node-at-point t) current-prefix-arg t))
|
||||||
(let ((buf (org-roam-node-find-noselect node force))
|
(org-roam-node-open node (if other-window
|
||||||
(display-buffer-fn (if other-window
|
|
||||||
#'switch-to-buffer-other-window
|
#'switch-to-buffer-other-window
|
||||||
#'pop-to-buffer-same-window)))
|
#'pop-to-buffer-same-window)
|
||||||
(funcall display-buffer-fn buf)
|
force))
|
||||||
(when (org-invisible-p) (org-show-context))
|
|
||||||
buf))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(cl-defun org-roam-node-find (&optional other-window initial-input filter-fn &key templates)
|
(cl-defun org-roam-node-find (&optional other-window initial-input filter-fn pred &key templates)
|
||||||
"Find and open an Org-roam node by its title or alias.
|
"Find and open an Org-roam node by its title or alias.
|
||||||
INITIAL-INPUT is the initial input for the prompt.
|
INITIAL-INPUT is the initial input for the prompt.
|
||||||
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
|
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
|
||||||
@ -468,7 +530,7 @@ If OTHER-WINDOW, visit the NODE in another window.
|
|||||||
The TEMPLATES, if provided, override the list of capture templates (see
|
The TEMPLATES, if provided, override the list of capture templates (see
|
||||||
`org-roam-capture-'.)"
|
`org-roam-capture-'.)"
|
||||||
(interactive current-prefix-arg)
|
(interactive current-prefix-arg)
|
||||||
(let ((node (org-roam-node-read initial-input filter-fn)))
|
(let ((node (org-roam-node-read initial-input filter-fn pred)))
|
||||||
(if (org-roam-node-file node)
|
(if (org-roam-node-file node)
|
||||||
(org-roam-node-visit node other-window)
|
(org-roam-node-visit node other-window)
|
||||||
(org-roam-capture-
|
(org-roam-capture-
|
||||||
@ -477,16 +539,16 @@ The TEMPLATES, if provided, override the list of capture templates (see
|
|||||||
:props '(:finalize find-file)))))
|
:props '(:finalize find-file)))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-node-random (&optional other-window)
|
(defun org-roam-node-random (&optional other-window filter-fn)
|
||||||
"Find and open a random Org-roam node.
|
"Find and open a random Org-roam node.
|
||||||
With prefix argument OTHER-WINDOW, visit the node in another
|
With prefix argument OTHER-WINDOW, visit the node in another
|
||||||
window instead."
|
window instead.
|
||||||
|
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
|
||||||
|
and when nil is returned the node will be filtered out."
|
||||||
(interactive current-prefix-arg)
|
(interactive current-prefix-arg)
|
||||||
(let ((random-row (seq-random-elt (org-roam-db-query [:select [id file pos] :from nodes]))))
|
(org-roam-node-visit
|
||||||
(org-roam-node-visit (org-roam-node-create :id (nth 0 random-row)
|
(cdr (seq-random-elt (org-roam-node-read--completions filter-fn)))
|
||||||
:file (nth 1 random-row)
|
other-window))
|
||||||
:point (nth 2 random-row))
|
|
||||||
other-window)))
|
|
||||||
|
|
||||||
;;;; Completing-read interface
|
;;;; Completing-read interface
|
||||||
(defun org-roam-node-read (&optional initial-input filter-fn sort-fn require-match prompt)
|
(defun org-roam-node-read (&optional initial-input filter-fn sort-fn require-match prompt)
|
||||||
@ -498,17 +560,7 @@ SORT-FN is a function to sort nodes. See `org-roam-node-read-sort-by-file-mtime'
|
|||||||
for an example sort function.
|
for an example sort function.
|
||||||
If REQUIRE-MATCH, the minibuffer prompt will require a match.
|
If REQUIRE-MATCH, the minibuffer prompt will require a match.
|
||||||
PROMPT is a string to show at the beginning of the mini-buffer, defaulting to \"Node: \""
|
PROMPT is a string to show at the beginning of the mini-buffer, defaulting to \"Node: \""
|
||||||
(let* ((nodes (org-roam-node-read--completions))
|
(let* ((nodes (org-roam-node-read--completions filter-fn sort-fn))
|
||||||
(nodes (if filter-fn
|
|
||||||
(cl-remove-if-not
|
|
||||||
(lambda (n) (funcall filter-fn (cdr n)))
|
|
||||||
nodes)
|
|
||||||
nodes))
|
|
||||||
(sort-fn (or sort-fn
|
|
||||||
(when org-roam-node-default-sort
|
|
||||||
(intern (concat "org-roam-node-read-sort-by-"
|
|
||||||
(symbol-name org-roam-node-default-sort))))))
|
|
||||||
(_ (when sort-fn (setq nodes (seq-sort sort-fn nodes))))
|
|
||||||
(prompt (or prompt "Node: "))
|
(prompt (or prompt "Node: "))
|
||||||
(node (completing-read
|
(node (completing-read
|
||||||
prompt
|
prompt
|
||||||
@ -529,15 +581,52 @@ PROMPT is a string to show at the beginning of the mini-buffer, defaulting to \"
|
|||||||
(or (cdr (assoc node nodes))
|
(or (cdr (assoc node nodes))
|
||||||
(org-roam-node-create :title node))))
|
(org-roam-node-create :title node))))
|
||||||
|
|
||||||
(defun org-roam-node-read--completions ()
|
(defun org-roam--format-nodes-using-template (nodes)
|
||||||
|
"Formats NODES using org-roam template features.
|
||||||
|
Uses org-roam--node-display-template."
|
||||||
|
(let (
|
||||||
|
(wTemplate (org-roam-node--process-display-format org-roam-node-display-template))
|
||||||
|
)
|
||||||
|
(mapcar (lambda (node)
|
||||||
|
(org-roam-node-read--to-candidate node wTemplate)) nodes))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun org-roam--format-nodes-using-function (nodes)
|
||||||
|
"Formats NODES using the function org-roam-node-display-template."
|
||||||
|
(mapcar (lambda (node)
|
||||||
|
(cons
|
||||||
|
(propertize (funcall org-roam-node-display-template node) 'node node)
|
||||||
|
node))
|
||||||
|
nodes)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun org-roam-node-read--completions (&optional filter-fn sort-fn)
|
||||||
"Return an alist for node completion.
|
"Return an alist for node completion.
|
||||||
The car is the displayed title or alias for the node, and the cdr
|
The car is the displayed title or alias for the node, and the cdr
|
||||||
is the `org-roam-node'.
|
is the `org-roam-node'.
|
||||||
|
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
|
||||||
|
and when nil is returned the node will be filtered out.
|
||||||
|
SORT-FN is a function to sort nodes. See `org-roam-node-read-sort-by-file-mtime'
|
||||||
|
for an example sort function.
|
||||||
The displayed title is formatted according to `org-roam-node-display-template'."
|
The displayed title is formatted according to `org-roam-node-display-template'."
|
||||||
(let ((template (org-roam-node--process-display-format org-roam-node-display-template))
|
(let* (
|
||||||
(nodes (org-roam-node-list)))
|
(nodes (org-roam-node-list))
|
||||||
(mapcar (lambda (node)
|
(nodes (if filter-fn
|
||||||
(org-roam-node-read--to-candidate node template)) nodes)))
|
(cl-remove-if-not
|
||||||
|
(lambda (n) (funcall filter-fn n))
|
||||||
|
nodes)
|
||||||
|
nodes))
|
||||||
|
(nodes (if (functionp org-roam-node-display-template)
|
||||||
|
(org-roam--format-nodes-using-function nodes)
|
||||||
|
(org-roam--format-nodes-using-template nodes)))
|
||||||
|
|
||||||
|
(sort-fn (or sort-fn
|
||||||
|
(when org-roam-node-default-sort
|
||||||
|
(intern (concat "org-roam-node-read-sort-by-"
|
||||||
|
(symbol-name org-roam-node-default-sort))))))
|
||||||
|
(nodes (if sort-fn (seq-sort sort-fn nodes)
|
||||||
|
nodes)))
|
||||||
|
nodes))
|
||||||
|
|
||||||
(defun org-roam-node-read--to-candidate (node template)
|
(defun org-roam-node-read--to-candidate (node template)
|
||||||
"Return a minibuffer completion candidate given NODE.
|
"Return a minibuffer completion candidate given NODE.
|
||||||
@ -545,7 +634,8 @@ TEMPLATE is the processed template used to format the entry."
|
|||||||
(let ((candidate-main (org-roam-node--format-entry
|
(let ((candidate-main (org-roam-node--format-entry
|
||||||
template
|
template
|
||||||
node
|
node
|
||||||
(1- (frame-width)))))
|
(1- (if (bufferp (current-buffer))
|
||||||
|
(window-width) (frame-width))))))
|
||||||
(cons (propertize candidate-main 'node node) node)))
|
(cons (propertize candidate-main 'node node) node)))
|
||||||
|
|
||||||
(defun org-roam-node--format-entry (template node &optional width)
|
(defun org-roam-node--format-entry (template node &optional width)
|
||||||
@ -663,9 +753,13 @@ The INFO, if provided, is passed to the underlying `org-roam-capture-'."
|
|||||||
(delete-region beg end)
|
(delete-region beg end)
|
||||||
(set-marker beg nil)
|
(set-marker beg nil)
|
||||||
(set-marker end nil))
|
(set-marker end nil))
|
||||||
(insert (org-link-make-string
|
(let ((id (org-roam-node-id node)))
|
||||||
(concat "id:" (org-roam-node-id node))
|
(insert (org-link-make-string
|
||||||
description)))
|
(concat "id:" id)
|
||||||
|
description))
|
||||||
|
(run-hook-with-args 'org-roam-post-node-insert-hook
|
||||||
|
id
|
||||||
|
description)))
|
||||||
(org-roam-capture-
|
(org-roam-capture-
|
||||||
:node node
|
:node node
|
||||||
:info info
|
:info info
|
||||||
@ -673,33 +767,12 @@ The INFO, if provided, is passed to the underlying `org-roam-capture-'."
|
|||||||
:props (append
|
:props (append
|
||||||
(when (and beg end)
|
(when (and beg end)
|
||||||
(list :region (cons beg end)))
|
(list :region (cons beg end)))
|
||||||
(list :insert-at (point-marker)
|
(list :link-description description
|
||||||
:link-description description
|
|
||||||
:finalize 'insert-link))))))
|
:finalize 'insert-link))))))
|
||||||
(deactivate-mark)))
|
(deactivate-mark)))
|
||||||
|
|
||||||
(add-hook 'org-roam-find-file-hook #'org-roam-open-id-with-org-roam-db-h)
|
|
||||||
(defun org-roam-open-id-with-org-roam-db-h ()
|
|
||||||
"Try to open \"id:\" links at point by querying them to the database."
|
|
||||||
(add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point nil t))
|
|
||||||
|
|
||||||
(defun org-roam-open-id-at-point ()
|
|
||||||
"Navigate to \"id:\" link at point using the Org-roam database."
|
|
||||||
(when (org-in-regexp org-link-any-re)
|
|
||||||
(let ((link (match-string 2))
|
|
||||||
id)
|
|
||||||
(when (string-prefix-p "id:" link)
|
|
||||||
(setq id (substring-no-properties link 3))
|
|
||||||
(let ((node (org-roam-populate (org-roam-node-create :id id))))
|
|
||||||
(cond
|
|
||||||
((org-roam-node-file node)
|
|
||||||
(org-mark-ring-push)
|
|
||||||
(org-roam-node-visit node nil 'force)
|
|
||||||
t)
|
|
||||||
(t nil)))))))
|
|
||||||
|
|
||||||
;;;;; [roam:] link
|
;;;;; [roam:] link
|
||||||
(org-link-set-parameters "roam" :follow #'org-roam-link-follow-link)
|
(org-link-set-parameters org-roam-link-type :follow #'org-roam-link-follow-link)
|
||||||
(defun org-roam-link-follow-link (title-or-alias)
|
(defun org-roam-link-follow-link (title-or-alias)
|
||||||
"Navigate \"roam:\" link to find and open the node with TITLE-OR-ALIAS.
|
"Navigate \"roam:\" link to find and open the node with TITLE-OR-ALIAS.
|
||||||
Assumes that the cursor was put where the link is."
|
Assumes that the cursor was put where the link is."
|
||||||
@ -728,7 +801,7 @@ Assumes that the cursor was put where the link is."
|
|||||||
node)
|
node)
|
||||||
(goto-char (org-element-property :begin link))
|
(goto-char (org-element-property :begin link))
|
||||||
(when (and (org-in-regexp org-link-any-re 1)
|
(when (and (org-in-regexp org-link-any-re 1)
|
||||||
(string-equal type "roam")
|
(string-equal type org-roam-link-type)
|
||||||
(setq node (save-match-data (org-roam-node-from-title-or-alias path))))
|
(setq node (save-match-data (org-roam-node-from-title-or-alias path))))
|
||||||
(replace-match (org-link-make-string
|
(replace-match (org-link-make-string
|
||||||
(concat "id:" (org-roam-node-id node))
|
(concat "id:" (org-roam-node-id node))
|
||||||
@ -738,7 +811,7 @@ Assumes that the cursor was put where the link is."
|
|||||||
"Replace all \"roam:\" links in buffer with \"id:\" links."
|
"Replace all \"roam:\" links in buffer with \"id:\" links."
|
||||||
(interactive)
|
(interactive)
|
||||||
(org-with-point-at 1
|
(org-with-point-at 1
|
||||||
(while (re-search-forward org-link-bracket-re nil t)
|
(while (search-forward (concat "[[" org-roam-link-type ":") nil t)
|
||||||
(org-roam-link-replace-at-point))))
|
(org-roam-link-replace-at-point))))
|
||||||
|
|
||||||
(add-hook 'org-roam-find-file-hook #'org-roam--replace-roam-links-on-save-h)
|
(add-hook 'org-roam-find-file-hook #'org-roam--replace-roam-links-on-save-h)
|
||||||
@ -758,7 +831,8 @@ We use this as a substitute for `org-link-bracket-re', because
|
|||||||
"Complete \"roam:\" link at point to an existing Org-roam node."
|
"Complete \"roam:\" link at point to an existing Org-roam node."
|
||||||
(let (roam-p start end)
|
(let (roam-p start end)
|
||||||
(when (org-in-regexp org-roam-bracket-completion-re 1)
|
(when (org-in-regexp org-roam-bracket-completion-re 1)
|
||||||
(setq roam-p (not (string-blank-p (match-string 1)))
|
(setq roam-p (not (or (org-in-src-block-p)
|
||||||
|
(string-blank-p (match-string 1))))
|
||||||
start (match-beginning 2)
|
start (match-beginning 2)
|
||||||
end (match-end 2))
|
end (match-end 2))
|
||||||
(list start end
|
(list start end
|
||||||
@ -780,6 +854,7 @@ outside of the bracket syntax for links (i.e. \"[[roam:|]]\"),
|
|||||||
hence \"everywhere\"."
|
hence \"everywhere\"."
|
||||||
(when (and org-roam-completion-everywhere
|
(when (and org-roam-completion-everywhere
|
||||||
(thing-at-point 'word)
|
(thing-at-point 'word)
|
||||||
|
(not (org-in-src-block-p))
|
||||||
(not (save-match-data (org-in-regexp org-link-any-re))))
|
(not (save-match-data (org-in-regexp org-link-any-re))))
|
||||||
(let ((bounds (bounds-of-thing-at-point 'word)))
|
(let ((bounds (bounds-of-thing-at-point 'word)))
|
||||||
(list (car bounds) (cdr bounds)
|
(list (car bounds) (cdr bounds)
|
||||||
@ -794,6 +869,8 @@ hence \"everywhere\"."
|
|||||||
:exclusive 'no))))
|
:exclusive 'no))))
|
||||||
|
|
||||||
(add-hook 'org-roam-find-file-hook #'org-roam--register-completion-functions-h)
|
(add-hook 'org-roam-find-file-hook #'org-roam--register-completion-functions-h)
|
||||||
|
(add-hook 'org-roam-indirect-buffer-hook #'org-roam--register-completion-functions-h)
|
||||||
|
|
||||||
(defun org-roam--register-completion-functions-h ()
|
(defun org-roam--register-completion-functions-h ()
|
||||||
"Setup `org-roam-completion-functions' for `completion-at-point'."
|
"Setup `org-roam-completion-functions' for `completion-at-point'."
|
||||||
(dolist (f org-roam-completion-functions)
|
(dolist (f org-roam-completion-functions)
|
||||||
@ -811,7 +888,8 @@ Any tags declared on #+FILETAGS: are transferred to tags on the new top heading.
|
|||||||
Any top level properties drawers are incorporated into the new heading."
|
Any top level properties drawers are incorporated into the new heading."
|
||||||
(interactive)
|
(interactive)
|
||||||
(org-with-point-at 1
|
(org-with-point-at 1
|
||||||
(org-map-entries 'org-do-demote)
|
(org-map-region #'org-do-demote
|
||||||
|
(point-min) (point-max))
|
||||||
(insert "* "
|
(insert "* "
|
||||||
(org-roam--get-keyword "title")
|
(org-roam--get-keyword "title")
|
||||||
"\n")
|
"\n")
|
||||||
@ -820,31 +898,52 @@ Any top level properties drawers are incorporated into the new heading."
|
|||||||
(org-roam-erase-keyword "title")
|
(org-roam-erase-keyword "title")
|
||||||
(org-roam-erase-keyword "filetags")))
|
(org-roam-erase-keyword "filetags")))
|
||||||
|
|
||||||
|
(defun org-roam--h1-count ()
|
||||||
|
"Count level-1 headings in the current file."
|
||||||
|
(let ((h1-count 0))
|
||||||
|
(org-with-wide-buffer
|
||||||
|
(org-map-region (lambda ()
|
||||||
|
(if (= (org-current-level) 1)
|
||||||
|
(cl-incf h1-count)))
|
||||||
|
(point-min) (point-max))
|
||||||
|
h1-count)))
|
||||||
|
|
||||||
|
(defun org-roam--buffer-promoteable-p ()
|
||||||
|
"Verify that this buffer is promoteable:
|
||||||
|
There is a single level-1 heading
|
||||||
|
and no extra content before the first heading."
|
||||||
|
(and
|
||||||
|
(= (org-roam--h1-count) 1)
|
||||||
|
(org-with-point-at 1 (org-at-heading-p))))
|
||||||
|
|
||||||
(defun org-roam-promote-entire-buffer ()
|
(defun org-roam-promote-entire-buffer ()
|
||||||
"Promote the current buffer.
|
"Promote the current buffer.
|
||||||
Converts a file containing a headline node at the top to a file
|
Converts a file containing a single level-1 headline node to a file
|
||||||
node."
|
node."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
(unless (org-roam--buffer-promoteable-p)
|
||||||
|
(user-error "Cannot promote: multiple root headings or there is extra file-level text"))
|
||||||
(org-with-point-at 1
|
(org-with-point-at 1
|
||||||
(org-map-entries (lambda ()
|
|
||||||
(when (> (org-outline-level) 1)
|
|
||||||
(org-do-promote))))
|
|
||||||
(let ((title (nth 4 (org-heading-components)))
|
(let ((title (nth 4 (org-heading-components)))
|
||||||
(tags (nth 5 (org-heading-components))))
|
(tags (org-get-tags)))
|
||||||
(beginning-of-line)
|
(org-fold-show-all)
|
||||||
(kill-line 1)
|
(kill-whole-line)
|
||||||
(org-roam-set-keyword "title" title)
|
(org-roam-end-of-meta-data t)
|
||||||
(when tags (org-roam-set-keyword "filetags" tags)))))
|
(insert "#+title: " title "\n")
|
||||||
|
(when tags (org-roam-tag-add tags))
|
||||||
|
(org-map-region #'org-promote (point-min) (point-max))
|
||||||
|
(org-roam-db-update-file))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-refile ()
|
(defun org-roam-refile (node)
|
||||||
"Refile node at point to an Org-roam node.
|
"Refile node at point to an org-roam NODE.
|
||||||
|
|
||||||
If region is active, then use it instead of the node at point."
|
If region is active, then use it instead of the node at point."
|
||||||
(interactive)
|
(interactive
|
||||||
|
(list (org-roam-node-read nil nil nil 'require-match)))
|
||||||
(let* ((regionp (org-region-active-p))
|
(let* ((regionp (org-region-active-p))
|
||||||
(region-start (and regionp (region-beginning)))
|
(region-start (and regionp (region-beginning)))
|
||||||
(region-end (and regionp (region-end)))
|
(region-end (and regionp (region-end)))
|
||||||
(node (org-roam-node-read nil nil nil 'require-match))
|
|
||||||
(file (org-roam-node-file node))
|
(file (org-roam-node-file node))
|
||||||
(nbuf (or (find-buffer-visiting file)
|
(nbuf (or (find-buffer-visiting file)
|
||||||
(find-file-noselect file)))
|
(find-file-noselect file)))
|
||||||
@ -888,7 +987,7 @@ If region is active, then use it instead of the node at point."
|
|||||||
(if (buffer-file-name)
|
(if (buffer-file-name)
|
||||||
(delete-file (buffer-file-name)))
|
(delete-file (buffer-file-name)))
|
||||||
(set-buffer-modified-p nil)
|
(set-buffer-modified-p nil)
|
||||||
;; In this was done during capture, abort the capture process.
|
;; If this was done during capture, abort the capture process.
|
||||||
(when (and org-capture-mode
|
(when (and org-capture-mode
|
||||||
(buffer-base-buffer (current-buffer)))
|
(buffer-base-buffer (current-buffer)))
|
||||||
(org-capture-kill))
|
(org-capture-kill))
|
||||||
@ -920,53 +1019,22 @@ If region is active, then use it instead of the node at point."
|
|||||||
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
|
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
|
||||||
(plist-put template-info ksym r)
|
(plist-put template-info ksym r)
|
||||||
r)))))))
|
r)))))))
|
||||||
(file-path (read-file-name "Extract node to: "
|
(file-path
|
||||||
(file-name-as-directory org-roam-directory) template nil template)))
|
(expand-file-name
|
||||||
|
(read-file-name "Extract node to: "
|
||||||
|
(file-name-as-directory org-roam-directory) template nil template)
|
||||||
|
org-roam-directory)))
|
||||||
(when (file-exists-p file-path)
|
(when (file-exists-p file-path)
|
||||||
(user-error "%s exists. Aborting" file-path))
|
(user-error "%s exists. Aborting" file-path))
|
||||||
(org-cut-subtree)
|
(org-cut-subtree)
|
||||||
(save-buffer)
|
(save-buffer)
|
||||||
(with-current-buffer (find-file-noselect file-path)
|
(with-current-buffer (find-file-noselect file-path)
|
||||||
(org-paste-subtree)
|
(org-paste-subtree)
|
||||||
|
(while (> (org-current-level) 1) (org-promote-subtree))
|
||||||
|
(save-buffer)
|
||||||
(org-roam-promote-entire-buffer)
|
(org-roam-promote-entire-buffer)
|
||||||
(save-buffer)))))
|
(save-buffer)))))
|
||||||
|
|
||||||
;;; IDs
|
|
||||||
;;;; Getters
|
|
||||||
(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))))
|
|
||||||
|
|
||||||
;;;###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)))
|
|
||||||
|
|
||||||
;;; Refs
|
;;; Refs
|
||||||
;;;; Completing-read interface
|
;;;; Completing-read interface
|
||||||
(defun org-roam-ref-read (&optional initial-input filter-fn)
|
(defun org-roam-ref-read (&optional initial-input filter-fn)
|
||||||
@ -1003,8 +1071,10 @@ The car is the ref, and the cdr is the corresponding node for the ref."
|
|||||||
:file file
|
:file file
|
||||||
:point pos
|
:point pos
|
||||||
:title title)))
|
:title title)))
|
||||||
(cons (propertize ref 'node node 'type type)
|
(cons
|
||||||
node)))))
|
(concat (propertize ref 'node node 'type type)
|
||||||
|
(propertize id 'invisible t))
|
||||||
|
node)))))
|
||||||
|
|
||||||
(defun org-roam-ref-read--annotation (ref)
|
(defun org-roam-ref-read--annotation (ref)
|
||||||
"Return the annotation for REF, which assumed to be a propertized string."
|
"Return the annotation for REF, which assumed to be a propertized string."
|
||||||
@ -1027,11 +1097,15 @@ and when nil is returned the node will be filtered out."
|
|||||||
;;;; Editing
|
;;;; Editing
|
||||||
(defun org-roam-ref-add (ref)
|
(defun org-roam-ref-add (ref)
|
||||||
"Add REF to the node at point."
|
"Add REF to the node at point."
|
||||||
(interactive "sRef: ")
|
(interactive `(,(if org-roam-ref-prompt-function
|
||||||
|
(funcall org-roam-ref-prompt-function)
|
||||||
|
(read-string "Ref: "))))
|
||||||
(let ((node (org-roam-node-at-point 'assert)))
|
(let ((node (org-roam-node-at-point 'assert)))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (org-roam-node-point node))
|
(goto-char (org-roam-node-point node))
|
||||||
(org-roam-property-add "ROAM_REFS" ref))))
|
(org-roam-property-add "ROAM_REFS" (if (member " " (string-to-list ref))
|
||||||
|
(concat "\"" ref "\"")
|
||||||
|
ref)))))
|
||||||
|
|
||||||
(defun org-roam-ref-remove (&optional ref)
|
(defun org-roam-ref-remove (&optional ref)
|
||||||
"Remove a REF from the node at point."
|
"Remove a REF from the node at point."
|
||||||
@ -1059,7 +1133,8 @@ and when nil is returned the node will be filtered out."
|
|||||||
(defun org-roam-tag-add (tags)
|
(defun org-roam-tag-add (tags)
|
||||||
"Add TAGS to the node at point."
|
"Add TAGS to the node at point."
|
||||||
(interactive
|
(interactive
|
||||||
(list (completing-read-multiple "Tag: " (org-roam-tag-completions))))
|
(list (let ((crm-separator "[ ]*:[ ]*"))
|
||||||
|
(completing-read-multiple "Tag: " (org-roam-tag-completions)))))
|
||||||
(let ((node (org-roam-node-at-point 'assert)))
|
(let ((node (org-roam-node-at-point 'assert)))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (org-roam-node-point node))
|
(goto-char (org-roam-node-point node))
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam-utils.el --- Utilities for Org-roam -*- lexical-binding: t; -*-
|
;;; org-roam-utils.el --- Utilities for Org-roam -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -52,6 +52,16 @@
|
|||||||
(org-roam-replace-string "\\" "\\\\")
|
(org-roam-replace-string "\\" "\\\\")
|
||||||
(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)
|
(defun org-roam-string-equal (s1 s2)
|
||||||
"Return t if S1 and S2 are equal.
|
"Return t if S1 and S2 are equal.
|
||||||
Like `string-equal', but case-insensitive."
|
Like `string-equal', but case-insensitive."
|
||||||
@ -59,6 +69,14 @@ Like `string-equal', but case-insensitive."
|
|||||||
(or (string-equal s1 s2)
|
(or (string-equal s1 s2)
|
||||||
(string-equal (downcase s1) (downcase 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)
|
(defun org-roam-strip-comments (s)
|
||||||
"Strip Org comments from string S."
|
"Strip Org comments from string S."
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
@ -66,7 +84,8 @@ Like `string-equal', but case-insensitive."
|
|||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (not (eobp))
|
(while (not (eobp))
|
||||||
(if (org-at-comment-p)
|
(if (org-at-comment-p)
|
||||||
(delete-region (point-at-bol) (progn (forward-line) (point)))
|
(delete-region (line-beginning-position)
|
||||||
|
(progn (forward-line) (point)))
|
||||||
(forward-line)))
|
(forward-line)))
|
||||||
(buffer-string)))
|
(buffer-string)))
|
||||||
|
|
||||||
@ -99,6 +118,12 @@ SPEC is a list, as per `dolist'."
|
|||||||
`(dolist ,spec ,@body)))
|
`(dolist ,spec ,@body)))
|
||||||
|
|
||||||
;;; File utilities
|
;;; 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)
|
(defmacro org-roam-with-file (file keep-buf-p &rest body)
|
||||||
"Execute BODY within FILE.
|
"Execute BODY within FILE.
|
||||||
If FILE is nil, execute BODY in the current buffer.
|
If FILE is nil, execute BODY in the current buffer.
|
||||||
@ -138,7 +163,8 @@ If FILE, set `default-directory' to FILE's directory and insert its contents."
|
|||||||
(let ((current-org-roam-directory (make-symbol "current-org-roam-directory")))
|
(let ((current-org-roam-directory (make-symbol "current-org-roam-directory")))
|
||||||
`(let ((,current-org-roam-directory org-roam-directory))
|
`(let ((,current-org-roam-directory org-roam-directory))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(let ((org-roam-directory ,current-org-roam-directory))
|
(let ((org-roam-directory ,current-org-roam-directory)
|
||||||
|
(org-inhibit-startup t))
|
||||||
(delay-mode-hooks (org-mode))
|
(delay-mode-hooks (org-mode))
|
||||||
(when ,file
|
(when ,file
|
||||||
(insert-file-contents ,file)
|
(insert-file-contents ,file)
|
||||||
@ -204,36 +230,10 @@ Like `org-fontify-like-in-org-mode', but supports `org-ref'."
|
|||||||
(insert s)
|
(insert s)
|
||||||
(let ((org-ref-buffer-hacked t))
|
(let ((org-ref-buffer-hacked t))
|
||||||
(org-mode)
|
(org-mode)
|
||||||
(org-font-lock-ensure)
|
(setq-local org-fold-core-style 'overlays)
|
||||||
|
(font-lock-ensure)
|
||||||
(buffer-string))))
|
(buffer-string))))
|
||||||
|
|
||||||
;;;; Shielding regions
|
|
||||||
(defface org-roam-shielded
|
|
||||||
'((t :inherit (warning)))
|
|
||||||
"Face for regions that are shielded (marked as read-only).
|
|
||||||
This face is used on the region target by org-roam-insertion
|
|
||||||
during an `org-roam-capture'."
|
|
||||||
:group 'org-roam-faces)
|
|
||||||
|
|
||||||
(defun org-roam-shield-region (beg end)
|
|
||||||
"Shield region against modifications.
|
|
||||||
BEG and END are markers for the beginning and end regions.
|
|
||||||
REGION must be a cons-cell containing the marker to the region
|
|
||||||
beginning and maximum values."
|
|
||||||
(add-text-properties beg end
|
|
||||||
'(font-lock-face org-roam-shielded
|
|
||||||
read-only t)
|
|
||||||
(marker-buffer beg)))
|
|
||||||
|
|
||||||
(defun org-roam-unshield-region (beg end)
|
|
||||||
"Unshield the shielded REGION.
|
|
||||||
BEG and END are markers for the beginning and end regions."
|
|
||||||
(let ((inhibit-read-only t))
|
|
||||||
(remove-text-properties beg end
|
|
||||||
'(font-lock-face org-roam-shielded
|
|
||||||
read-only t)
|
|
||||||
(marker-buffer beg))))
|
|
||||||
|
|
||||||
;;; Org-mode utilities
|
;;; Org-mode utilities
|
||||||
;;;; Motions
|
;;;; Motions
|
||||||
(defun org-roam-up-heading-or-point-min ()
|
(defun org-roam-up-heading-or-point-min ()
|
||||||
@ -339,26 +339,14 @@ If the property is already set, it's value is replaced."
|
|||||||
(defun org-roam-add-property (val prop)
|
(defun org-roam-add-property (val prop)
|
||||||
"Add VAL value to PROP property for the node at point.
|
"Add VAL value to PROP property for the node at point.
|
||||||
Both, VAL and PROP are strings."
|
Both, VAL and PROP are strings."
|
||||||
(let* ((p (org-entry-get (point) prop))
|
(org-roam-property-add prop val))
|
||||||
(lst (when p (split-string-and-unquote p)))
|
|
||||||
(lst (if (memq val lst) lst (cons val lst)))
|
|
||||||
(lst (seq-uniq lst)))
|
|
||||||
(org-set-property prop (combine-and-quote-strings lst))
|
|
||||||
val))
|
|
||||||
|
|
||||||
(defun org-roam-remove-property (prop &optional val)
|
(defun org-roam-remove-property (prop &optional val)
|
||||||
"Remove VAL value from PROP property for the node at point.
|
"Remove VAL value from PROP property for the node at point.
|
||||||
Both VAL and PROP are strings.
|
Both VAL and PROP are strings.
|
||||||
|
|
||||||
If VAL is not specified, user is prompted to select a value."
|
If VAL is not specified, user is prompted to select a value."
|
||||||
(let* ((p (org-entry-get (point) prop))
|
(org-roam-property-remove prop val))
|
||||||
(lst (when p (split-string-and-unquote p)))
|
|
||||||
(prop-to-remove (or val (completing-read "Remove: " lst)))
|
|
||||||
(lst (delete prop-to-remove lst)))
|
|
||||||
(if lst
|
|
||||||
(org-set-property prop (combine-and-quote-strings lst))
|
|
||||||
(org-delete-property prop))
|
|
||||||
prop-to-remove))
|
|
||||||
|
|
||||||
(defun org-roam-property-add (prop val)
|
(defun org-roam-property-add (prop val)
|
||||||
"Add VAL value to PROP property for the node at point.
|
"Add VAL value to PROP property for the node at point.
|
||||||
@ -461,8 +449,11 @@ See <https://github.com/raxod502/straight.el/issues/520>."
|
|||||||
'("Doom" "Spacemacs" "N/A" "I don't know"))
|
'("Doom" "Spacemacs" "N/A" "I don't know"))
|
||||||
(quit "N/A"))))
|
(quit "N/A"))))
|
||||||
(insert (format "- Org: %s\n" (org-version nil 'full)))
|
(insert (format "- Org: %s\n" (org-version nil 'full)))
|
||||||
(insert (format "- Org-roam: %s" (org-roam-version)))))
|
(insert (format "- Org-roam: %s" (org-roam-version)))
|
||||||
|
(insert (format "- sqlite-connector: %s"
|
||||||
|
(if-let ((conn (org-roam-db--get-connection)))
|
||||||
|
(eieio-object-class conn)
|
||||||
|
"not connected")))))
|
||||||
|
|
||||||
(provide 'org-roam-utils)
|
(provide 'org-roam-utils)
|
||||||
;;; org-roam-utils.el ends here
|
;;; org-roam-utils.el ends here
|
||||||
|
119
org-roam.el
119
org-roam.el
@ -1,12 +1,12 @@
|
|||||||
;;; org-roam.el --- A database abstraction layer for Org-mode -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam.el --- A database abstraction layer for Org-mode -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright © 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020-2025 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 2.2.0
|
;; Version: 2.3.1
|
||||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
|
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.6") (emacsql "4.1.0") (magit-section "3.0.0"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
@ -71,7 +71,6 @@
|
|||||||
;; majority of them can be found at https://github.com/org-roam and MELPA.
|
;; majority of them can be found at https://github.com/org-roam and MELPA.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'f)
|
|
||||||
(require 'dash)
|
(require 'dash)
|
||||||
|
|
||||||
(require 'rx)
|
(require 'rx)
|
||||||
@ -81,9 +80,13 @@
|
|||||||
(require 'magit-section)
|
(require 'magit-section)
|
||||||
|
|
||||||
(require 'emacsql)
|
(require 'emacsql)
|
||||||
|
;; REVIEW: is this require needed?
|
||||||
|
;; emacsql-sqlite provides a common interface to an emacsql SQLite backend (e.g. emacs-sqlite-builtin)
|
||||||
|
;; not to be confused with a backend itself named emacsql-sqlite that existed in emacsql < 4.0.
|
||||||
(require 'emacsql-sqlite)
|
(require 'emacsql-sqlite)
|
||||||
|
|
||||||
(require 'org)
|
(require 'org)
|
||||||
|
(require 'org-attach) ; To set `org-attach-id-dir'
|
||||||
(require 'org-id)
|
(require 'org-id)
|
||||||
(require 'ol)
|
(require 'ol)
|
||||||
(require 'org-element)
|
(require 'org-element)
|
||||||
@ -123,6 +126,12 @@ All Org files, at any level of nesting, are considered part of the Org-roam."
|
|||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
:type 'hook)
|
: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")
|
(defcustom org-roam-file-extensions '("org")
|
||||||
"List of file extensions to be included by Org-Roam.
|
"List of file extensions to be included by Org-Roam.
|
||||||
While a file extension different from \".org\" may be used, the
|
While a file extension different from \".org\" may be used, the
|
||||||
@ -131,9 +140,11 @@ responsibility to ensure that."
|
|||||||
:type '(repeat string)
|
:type '(repeat string)
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
(defcustom org-roam-file-exclude-regexp nil
|
(defcustom org-roam-file-exclude-regexp (list org-attach-id-dir)
|
||||||
"Files matching this regular expression are excluded from the Org-roam."
|
"Files matching this regular expression or list of regular expressions are excluded from the Org-roam."
|
||||||
:type '(choice
|
:type '(choice
|
||||||
|
(repeat
|
||||||
|
(string :tag "Regular expression matching files to ignore"))
|
||||||
(string :tag "Regular expression matching files to ignore")
|
(string :tag "Regular expression matching files to ignore")
|
||||||
(const :tag "Include everything" nil))
|
(const :tag "Include everything" nil))
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
@ -144,36 +155,46 @@ responsibility to ensure that."
|
|||||||
'(find fd fdfind rg))
|
'(find fd fdfind rg))
|
||||||
"Commands that will be used to find Org-roam files.
|
"Commands that will be used to find Org-roam files.
|
||||||
|
|
||||||
It should be a list of symbols or cons cells representing any of the following
|
It should be a list of symbols or cons cells representing any of
|
||||||
supported file search methods.
|
the following supported file search methods.
|
||||||
|
|
||||||
The commands will be tried in order until an executable for a command is found.
|
The commands will be tried in order until an executable for a
|
||||||
The Elisp implementation is used if no command in the list is found.
|
command is found. The Elisp implementation is used if no command
|
||||||
|
in the list is found.
|
||||||
|
|
||||||
`find'
|
`find'
|
||||||
|
|
||||||
Use find as the file search method.
|
Use find as the file search method.
|
||||||
Example command:
|
Example command:
|
||||||
find /path/to/dir -type f \( -name \"*.org\" -o -name \"*.org.gpg\" \)
|
find /path/to/dir -type f \
|
||||||
|
\( -name \"*.org\" -o -name \"*.org.gpg\" -name \"*.org.age\" \)
|
||||||
|
|
||||||
`fd'
|
`fd'
|
||||||
|
|
||||||
Use fd as the file search method.
|
Use fd as the file search method.
|
||||||
Example command: fd /path/to/dir/ --type file -e \".org\" -e \".org.gpg\"
|
Example command:
|
||||||
|
fd /path/to/dir/ --type file -e \".org\" -e \".org.gpg\" -e \".org.age\"
|
||||||
|
|
||||||
`fdfind'
|
`fdfind'
|
||||||
|
|
||||||
Same as `fd'. It's an alias that used in some OSes (e.g. Debian, Ubuntu)
|
Same as `fd'. It's an alias that used in some OSes (e.g. Debian, Ubuntu)
|
||||||
|
|
||||||
`rg'
|
`rg'
|
||||||
Use ripgrep as the file search method.
|
|
||||||
Example command: rg /path/to/dir/ --files -g \"*.org\" -g \"*.org.gpg\"
|
|
||||||
|
|
||||||
By default, `executable-find' will be used to look up the path to the
|
Use ripgrep as the file search method.
|
||||||
executable. If a custom path is required, it can be specified together with the
|
Example command:
|
||||||
method symbol as a cons cell. For example: '(find (rg . \"/path/to/rg\"))."
|
rg /path/to/dir/ --files -g \"*.org\" -g \"*.org.gpg\" -g \"*.org.age\"
|
||||||
:type '(set (const :tag "find" find)
|
|
||||||
(const :tag "fd" fd)
|
By default, `executable-find' will be used to look up the path to
|
||||||
(const :tag "fdfind" fdfind)
|
the executable. If a custom path is required, it can be specified
|
||||||
(const :tag "rg" rg)
|
together with the method symbol as a cons cell. For example:
|
||||||
(const :tag "elisp" nil)))
|
\\='(find (rg . \"/path/to/rg\"))."
|
||||||
|
:type '(set
|
||||||
|
(const :tag "find" find)
|
||||||
|
(const :tag "fd" fd)
|
||||||
|
(const :tag "fdfind" fdfind)
|
||||||
|
(const :tag "rg" rg)
|
||||||
|
(const :tag "elisp" nil)))
|
||||||
|
|
||||||
;;; Library
|
;;; Library
|
||||||
(defun org-roam-file-p (&optional file)
|
(defun org-roam-file-p (&optional file)
|
||||||
@ -184,19 +205,34 @@ FILE is an Org-roam file if:
|
|||||||
- It's located somewhere under `org-roam-directory'
|
- It's located somewhere under `org-roam-directory'
|
||||||
- It has a matching file extension (`org-roam-file-extensions')
|
- It has a matching file extension (`org-roam-file-extensions')
|
||||||
- It doesn't match excluded regexp (`org-roam-file-exclude-regexp')"
|
- It doesn't match excluded regexp (`org-roam-file-exclude-regexp')"
|
||||||
(let* ((path (or file (buffer-file-name (buffer-base-buffer))))
|
(when (or file (buffer-file-name (buffer-base-buffer)))
|
||||||
(ext (when path (org-roam--file-name-extension path)))
|
(let* ((path (or file (buffer-file-name (buffer-base-buffer))))
|
||||||
(ext (if (string= ext "gpg")
|
(relative-path (file-relative-name path org-roam-directory))
|
||||||
(org-roam--file-name-extension (file-name-sans-extension path))
|
(ext (org-roam--file-name-extension path))
|
||||||
ext)))
|
(ext (if (or (string= ext "gpg")
|
||||||
(save-match-data
|
(string= ext "age"))
|
||||||
(and
|
(org-roam--file-name-extension (file-name-sans-extension path))
|
||||||
path
|
ext))
|
||||||
(member ext org-roam-file-extensions)
|
(org-roam-dir-p (org-roam-descendant-of-p path org-roam-directory))
|
||||||
(not (and org-roam-file-exclude-regexp
|
(valid-file-ext-p (member ext org-roam-file-extensions))
|
||||||
(string-match-p org-roam-file-exclude-regexp path)))
|
(match-exclude-regexp-p
|
||||||
(f-descendant-of-p path (expand-file-name org-roam-directory))))))
|
(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 ()
|
(defun org-roam-list-files ()
|
||||||
"Return a list of all Org-roam files under `org-roam-directory'.
|
"Return a list of all Org-roam files under `org-roam-directory'.
|
||||||
See `org-roam-file-p' for how each file is determined to be as
|
See `org-roam-file-p' for how each file is determined to be as
|
||||||
@ -260,14 +296,16 @@ If no files are found, an empty list is returned."
|
|||||||
(shell-command-to-string it)
|
(shell-command-to-string it)
|
||||||
(ansi-color-filter-apply it)
|
(ansi-color-filter-apply it)
|
||||||
(split-string it "\n")
|
(split-string it "\n")
|
||||||
(seq-filter #'s-present? it)))
|
(seq-filter (lambda (s)
|
||||||
|
(not (or (null s) (string= "" s)))) it)))
|
||||||
|
|
||||||
(defun org-roam--list-files-search-globs (exts)
|
(defun org-roam--list-files-search-globs (exts)
|
||||||
"Given EXTS, return a list of search globs.
|
"Given EXTS, return a list of search globs.
|
||||||
E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
|
E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
|
||||||
(cl-loop for e in exts
|
(cl-loop for e in exts
|
||||||
append (list (format "\"*.%s\"" e)
|
append (list (format "\"*.%s\"" e)
|
||||||
(format "\"*.%s.gpg\"" e))))
|
(format "\"*.%s.gpg\"" e)
|
||||||
|
(format "\"*.%s.age\"" e))))
|
||||||
|
|
||||||
(defun org-roam--list-files-find (executable dir)
|
(defun org-roam--list-files-find (executable dir)
|
||||||
"Return all Org-roam files under DIR, using \"find\", provided as EXECUTABLE."
|
"Return all Org-roam files under DIR, using \"find\", provided as EXECUTABLE."
|
||||||
@ -288,8 +326,9 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
|
|||||||
(defun org-roam--list-files-rg (executable dir)
|
(defun org-roam--list-files-rg (executable dir)
|
||||||
"Return all Org-roam files under DIR, using \"rg\", provided as EXECUTABLE."
|
"Return all Org-roam files under DIR, using \"rg\", provided as EXECUTABLE."
|
||||||
(let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions))
|
(let* ((globs (org-roam--list-files-search-globs org-roam-file-extensions))
|
||||||
(command (string-join `(,executable "-L" ,dir "--files"
|
(command (string-join `(
|
||||||
,@(mapcar (lambda (glob) (concat "-g " glob)) globs)) " ")))
|
,executable "-L" ,dir "--files"
|
||||||
|
,@(mapcar (lambda (glob) (concat "-g " glob)) globs)) " ")))
|
||||||
(org-roam--shell-command-files command)))
|
(org-roam--shell-command-files command)))
|
||||||
|
|
||||||
(declare-function org-roam--directory-files-recursively "org-roam-compat")
|
(declare-function org-roam--directory-files-recursively "org-roam-compat")
|
||||||
@ -298,7 +337,7 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
|
|||||||
"Return all Org-roam files under DIR, using Elisp based implementation."
|
"Return all Org-roam files under DIR, using Elisp based implementation."
|
||||||
(let ((regex (concat "\\.\\(?:"(mapconcat
|
(let ((regex (concat "\\.\\(?:"(mapconcat
|
||||||
#'regexp-quote org-roam-file-extensions
|
#'regexp-quote org-roam-file-extensions
|
||||||
"\\|" )"\\)\\(?:\\.gpg\\)?\\'"))
|
"\\|" )"\\)\\(?:\\.gpg\\|\\.age\\)?\\'"))
|
||||||
result)
|
result)
|
||||||
(dolist (file (org-roam--directory-files-recursively dir regex nil nil t) result)
|
(dolist (file (org-roam--directory-files-recursively dir regex nil nil t) result)
|
||||||
(when (and (file-readable-p file)
|
(when (and (file-readable-p file)
|
||||||
@ -313,8 +352,10 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
|
|||||||
(require 'org-roam-utils)
|
(require 'org-roam-utils)
|
||||||
(require 'org-roam-db)
|
(require 'org-roam-db)
|
||||||
(require 'org-roam-node)
|
(require 'org-roam-node)
|
||||||
|
(require 'org-roam-id)
|
||||||
(require 'org-roam-capture)
|
(require 'org-roam-capture)
|
||||||
(require 'org-roam-mode)
|
(require 'org-roam-mode)
|
||||||
|
(require 'org-roam-log)
|
||||||
(require 'org-roam-migrate))
|
(require 'org-roam-migrate))
|
||||||
|
|
||||||
;;; org-roam.el ends here
|
;;; org-roam.el ends here
|
||||||
|
8
tests/roam-files/demoteable.org
Normal file
8
tests/roam-files/demoteable.org
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 97bf31cf-dfee-45d8-87a5-2ae0dabc4734
|
||||||
|
:END:
|
||||||
|
#+title: Demoteable
|
||||||
|
|
||||||
|
* Demoteable h1
|
||||||
|
|
||||||
|
** Demoteable child
|
19
tests/roam-files/family.org
Normal file
19
tests/roam-files/family.org
Normal 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:
|
3
tests/roam-files/promoteable.org
Normal file
3
tests/roam-files/promoteable.org
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Promoteable h1
|
||||||
|
|
||||||
|
** Promoteable child
|
7
tests/roam-files/ref_with_space.org
Normal file
7
tests/roam-files/ref_with_space.org
Normal 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
|
5
tests/roam-files/with-alias.org
Normal file
5
tests/roam-files/with-alias.org
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 57ff3ce7-5bda-4825-8fca-c09f523e87ba
|
||||||
|
:ROAM_ALIASES: Batman
|
||||||
|
:END:
|
||||||
|
#+title: Bruce Wayne
|
16
tests/roam-files/with-times.org
Normal file
16
tests/roam-files/with-times.org
Normal 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:
|
63
tests/test-org-roam-capture.el
Normal file
63
tests/test-org-roam-capture.el
Normal 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
120
tests/test-org-roam-db.el
Normal 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
79
tests/test-org-roam-id.el
Normal 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
|
39
tests/test-org-roam-mode.el
Normal file
39
tests/test-org-roam-mode.el
Normal 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") "/tmp/regex")
|
||||||
|
:to-equal
|
||||||
|
"rg --follow --only-matching --vimgrep --pcre2 --ignore-case --glob \"*.org\" --glob \"*.org.gpg\" --glob \"*.org.age\" --file /tmp/regex /tmp/org\\ roam")))
|
||||||
|
|
||||||
|
(provide 'test-org-roam-mode)
|
||||||
|
|
||||||
|
;;; test-org-roam-mode.el ends here
|
164
tests/test-org-roam-node.el
Normal file
164
tests/test-org-roam-node.el
Normal 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
|
64
tests/test-org-roam-utils.el
Normal file
64
tests/test-org-roam-utils.el
Normal 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
|
@ -24,6 +24,28 @@
|
|||||||
(require 'buttercup)
|
(require 'buttercup)
|
||||||
(require 'org-roam)
|
(require 'org-roam)
|
||||||
|
|
||||||
|
(defvar root-directory default-directory)
|
||||||
|
|
||||||
|
(describe "org-roam-file-p"
|
||||||
|
(it "checks if given file respects criteria"
|
||||||
|
(setq org-roam-directory "/non-existent")
|
||||||
|
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal nil)
|
||||||
|
|
||||||
|
(setq org-roam-directory (expand-file-name "tests/roam-files"))
|
||||||
|
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal t)
|
||||||
|
(expect (org-roam-file-p "tests/roam-files/markdown.md") :to-equal nil)
|
||||||
|
|
||||||
|
(setq org-roam-file-exclude-regexp (regexp-quote "family.org"))
|
||||||
|
(expect (org-roam-file-p "tests/roam-files/family.org") :to-equal nil)))
|
||||||
|
|
||||||
|
(describe "org-roam-buffer-p"
|
||||||
|
(it "checks if current buffer respects criteria"
|
||||||
|
(setq org-roam-directory (expand-file-name "tests/roam-files")
|
||||||
|
org-roam-file-exclude-regexp nil)
|
||||||
|
(find-file "tests/roam-files/family.org" nil)
|
||||||
|
(expect (org-roam-buffer-p) :to-equal t)
|
||||||
|
(cd root-directory)))
|
||||||
|
|
||||||
(describe "org-roam-list-files"
|
(describe "org-roam-list-files"
|
||||||
(before-each
|
(before-each
|
||||||
(setq org-roam-directory (expand-file-name "tests/roam-files")
|
(setq org-roam-directory (expand-file-name "tests/roam-files")
|
||||||
@ -31,52 +53,29 @@
|
|||||||
org-roam-file-extensions '("org")
|
org-roam-file-extensions '("org")
|
||||||
org-roam-file-exclude-regexp nil))
|
org-roam-file-exclude-regexp nil))
|
||||||
|
|
||||||
|
(after-all
|
||||||
|
(org-roam-db--close)
|
||||||
|
(delete-file org-roam-db-location))
|
||||||
|
|
||||||
(it "gets files correctly"
|
(it "gets files correctly"
|
||||||
(expect (length (org-roam-list-files))
|
(expect (length (org-roam-list-files)) :to-equal 9))
|
||||||
:to-equal 3))
|
|
||||||
|
|
||||||
(it "respects org-roam-file-extensions"
|
(it "respects org-roam-file-extensions"
|
||||||
(setq org-roam-file-extensions '("md"))
|
(setq org-roam-file-extensions '("md"))
|
||||||
(expect (length (org-roam-list-files)) :to-equal 1)
|
(expect (length (org-roam-list-files)) :to-equal 1)
|
||||||
(setq org-roam-file-extensions '("org" "md"))
|
(setq org-roam-file-extensions '("org" "md"))
|
||||||
(expect (length (org-roam-list-files)) :to-equal 4))
|
(expect (length (org-roam-list-files)) :to-equal 10))
|
||||||
|
|
||||||
(it "respects org-roam-file-exclude-regexp"
|
(it "respects org-roam-file-exclude-regexp"
|
||||||
(setq org-roam-file-exclude-regexp (regexp-quote "foo.org"))
|
(setq org-roam-file-exclude-regexp (regexp-quote "foo.org"))
|
||||||
(expect (length (org-roam-list-files)) :to-equal 2)))
|
(expect (length (org-roam-list-files)) :to-equal 8)))
|
||||||
|
|
||||||
(describe "org-roam-db-sync"
|
(describe "org-roam--list-files-search-globs"
|
||||||
(before-all
|
|
||||||
(setq org-roam-directory (expand-file-name "tests/roam-files")
|
|
||||||
org-roam-db-location (expand-file-name "org-roam.db" temporary-file-directory)
|
|
||||||
org-roam-file-extensions '("org")
|
|
||||||
org-roam-file-exclude-regexp nil)
|
|
||||||
(org-roam-db-sync))
|
|
||||||
|
|
||||||
(after-all
|
(it "returns the correct list of globs"
|
||||||
(org-roam-db--close)
|
(expect (org-roam--list-files-search-globs org-roam-file-extensions)
|
||||||
(delete-file org-roam-db-location))
|
|
||||||
|
|
||||||
(it "has the correct number of files"
|
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from files]))
|
|
||||||
:to-equal
|
|
||||||
3))
|
|
||||||
|
|
||||||
(it "has the correct number of nodes"
|
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from nodes]))
|
|
||||||
:to-equal
|
|
||||||
2))
|
|
||||||
|
|
||||||
(it "has the correct number of links"
|
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links]))
|
|
||||||
:to-equal
|
|
||||||
1))
|
|
||||||
|
|
||||||
(it "respects ROAM_EXCLUDE"
|
|
||||||
;; The excluded node has ID "53fadc75-f48e-461e-be06-44a1e88b2abe"
|
|
||||||
(expect (mapcar #'car (org-roam-db-query [:select id :from nodes]))
|
|
||||||
:to-have-same-items-as
|
:to-have-same-items-as
|
||||||
'("884b2341-b7fe-434d-848c-5282c0727861" "440795d0-70c1-4165-993d-aebd5eef7a24"))))
|
'("\"*.org\"" "\"*.org.gpg\"" "\"*.org.age\""))))
|
||||||
|
|
||||||
(provide 'test-org-roam)
|
(provide 'test-org-roam)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user