mirror of
https://github.com/org-roam/org-roam
synced 2025-08-01 12:17:21 -05:00
Compare commits
273 Commits
Author | SHA1 | Date | |
---|---|---|---|
cce2db8b5a | |||
2147adf95c | |||
d2654f6023 | |||
78b518efd3 | |||
1b5e55b6c4 | |||
4b45f1dbf5 | |||
e0aee184a7 | |||
eae97487dc | |||
f5a9dfab9b | |||
7844827757 | |||
74f12ee8aa | |||
055669817a | |||
1fc08b4428 | |||
cfe3b19a73 | |||
1bc1559743 | |||
265182a698 | |||
4b4ebf76c7 | |||
3bc174a6f0 | |||
8091f4598e | |||
1267a43043 | |||
8ff09b4b6d | |||
2499c7e220 | |||
d816250614 | |||
47763f49fd | |||
9961a22a8c | |||
f390593cfb | |||
59c18c0e8c | |||
3df3b6519c | |||
b47b76aa41 | |||
abb36d11ef | |||
e55a38530d | |||
80bc19cbda | |||
85b3e488b2 | |||
5a9f765a49 | |||
1c7c5b3b9b | |||
4266a81b51 | |||
36940e1eef | |||
176aac67e6 | |||
376ff71616 | |||
232921b9a1 | |||
9e2998c580 | |||
e44b84b791 | |||
5e63bf32ed | |||
e62bda799a | |||
46975107a2 | |||
b388fd3db2 | |||
e0cefa7377 | |||
fca1777648 | |||
1722fae9af | |||
3727f015cd | |||
a85205e7bc | |||
b4927abbd7 | |||
ad5fca5440 | |||
3efe315ff1 | |||
d68d1f8ebb | |||
c70f2d5f54 | |||
d3206b797a | |||
dee540b62f | |||
46fd2a9a68 | |||
c1bfa99ace | |||
9bc80ff9f7 | |||
1912beebc3 | |||
f8f7e6009c | |||
689f559080 | |||
3ca2d9f4ca | |||
cd0850f1c1 | |||
11e15594cc | |||
f6e84caf72 | |||
11d239d661 | |||
7df50c14ec | |||
a723199d68 | |||
1bbfb0cdc9 | |||
69d4f05a13 | |||
4cad2cf6e6 | |||
e698ed7f53 | |||
0132546e56 | |||
a8e2544435 | |||
1ad3539c54 | |||
5b773b687b | |||
08aa5c630d | |||
e05ee1240d | |||
65d99e998c | |||
ea3f5d00a0 | |||
7680663205 | |||
d0819aeffb | |||
bd4b9d41e8 | |||
4142300501 | |||
487025aa2f | |||
bd3c97bb30 | |||
265a3054be | |||
8bb2465e61 | |||
c3a5544da9 | |||
963692f353 | |||
d01f7b2daf | |||
8a99febd0b | |||
b5786edb30 | |||
dce8c47d6e | |||
27a63b59b1 | |||
339336a27f | |||
a35454bb7e | |||
228af5b6be | |||
89b941a207 | |||
258d6f8a52 | |||
dc65e58405 | |||
de4f5477d8 | |||
9e138e259a | |||
ba80a31fe0 | |||
6175739b33 | |||
35b20de45f | |||
06afa27725 | |||
e1873a6a16 | |||
e33c144298 | |||
ea1ba21825 | |||
d7fc91e047 | |||
a4a2ac8d19 | |||
f79ee9e850 | |||
a71176ee40 | |||
6bdde3a634 | |||
b33300a23d | |||
8c7bc09f9b | |||
0a9ca736e4 | |||
3506f16648 | |||
772505ba70 | |||
6392a8b5df | |||
580a320c66 | |||
0e79bbb75a | |||
4af4d2e4d5 | |||
18939fcccd | |||
1b13c426aa | |||
bee8e506c2 | |||
c280f249a9 | |||
ba1782d361 | |||
e327fb3f0c | |||
40dc3a5af8 | |||
05c9e8e2e7 | |||
df20754fb0 | |||
dddbe286de | |||
92500b1338 | |||
772504c488 | |||
6e97003967 | |||
dd3fd592bb | |||
67495e269a | |||
72faa591fb | |||
c7a44b9f12 | |||
5120f8eac3 | |||
e73bc78274 | |||
4ca2606a28 | |||
f9a4f3b7f7 | |||
8f28bd4ccf | |||
dfb8449680 | |||
48ccb084f0 | |||
f27e5f2384 | |||
e4f77eb586 | |||
2e3119e027 | |||
b06e296e88 | |||
04acbda916 | |||
b86d2c8637 | |||
7dd371c023 | |||
58c07f74bc | |||
bc28c85dfc | |||
b607e56c5f | |||
ba835ef624 | |||
649af54640 | |||
22b9d4bd22 | |||
df29da1b6d | |||
de36d15d0f | |||
3e0a49de03 | |||
3add2c5a8b | |||
4b6f580375 | |||
23a8b0d722 | |||
1433dbc316 | |||
def3d27d25 | |||
6fae1d8100 | |||
07672213b6 | |||
5406827451 | |||
214a8f771f | |||
57f5e73192 | |||
1352809451 | |||
8b37135aa2 | |||
159e11c842 | |||
63b2eaaf86 | |||
919d08732c | |||
97dfc4b980 | |||
4556f727ff | |||
6775f15ad1 | |||
8f8ccf6797 | |||
81dd880357 | |||
c14ac7b613 | |||
08667d9c7d | |||
f544bd9ca1 | |||
66aff57cdb | |||
f238e3fe02 | |||
98fc273a0f | |||
a4df95b518 | |||
6f1154c90e | |||
486ba9c5a8 | |||
d28a83c992 | |||
62ed117eb6 | |||
a44b847596 | |||
e64890c80e | |||
4eaf69465e | |||
0950ae3cc6 | |||
0cab668d9e | |||
6095d01ef4 | |||
bd425e4427 | |||
65ead3c9ed | |||
be1d1f1d7b | |||
f5d5b83b49 | |||
8a3945945b | |||
7f09c76baf | |||
f6e75f995a | |||
6ba9ffe9c8 | |||
5e0b7440a3 | |||
d16d001b9e | |||
f67e0b025a | |||
b836f9fc35 | |||
e138056115 | |||
63e0558d96 | |||
3fccaef967 | |||
6eb7238daf | |||
fc79901682 | |||
46afa483a9 | |||
f63f29ac05 | |||
e357693297 | |||
b7afb02015 | |||
4c6e4df474 | |||
b1e2209dfc | |||
8f83ffc2a3 | |||
09a23c377b | |||
d1a47e090e | |||
7d1dd831db | |||
c77c1b7316 | |||
55d7edd5ee | |||
1f02b0c5dd | |||
d96ae119ab | |||
b7a7741bb0 | |||
4de88b3c4f | |||
b74cc14377 | |||
4c3d5b90a7 | |||
f98e7d22a5 | |||
a03ad54460 | |||
a88076a704 | |||
9296470d17 | |||
4da30a7134 | |||
150ae65564 | |||
0c2aaad3df | |||
d086d1675d | |||
685aa2afcd | |||
92d25b287e | |||
962ef23cce | |||
5e76c67cf6 | |||
b382b1f21a | |||
f1fb9f4680 | |||
5b96cf806f | |||
a8d696e6e8 | |||
19f16e9c64 | |||
4b38b07c41 | |||
b4d89c6a0c | |||
d780b6ffd1 | |||
5f6ff4282c | |||
a0559a2709 | |||
de1ac9d5cc | |||
b2dc9b33f6 | |||
f9a903f52d | |||
c54c206694 | |||
d2843b816f | |||
c2c25f7d83 | |||
cba79b941a | |||
a2a858a0fe | |||
43ff60fec7 | |||
fe3f0e3b6c | |||
d02d48e559 | |||
22f596d275 |
4
.dir-locals.el
Normal file
4
.dir-locals.el
Normal file
@ -0,0 +1,4 @@
|
||||
;;; Directory Local Variables
|
||||
;;; For more information see (info "(emacs) Directory Variables")
|
||||
|
||||
((emacs-lisp-mode . ((eval . (require 'org-roam-dev)))))
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [jethrokuan, zaeph]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,14 +1,15 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Something's not working.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: 'jethrokuan'
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
#### Steps to Reproduce
|
||||
|
||||
<!--
|
||||
Example:
|
||||
|
||||
@ -18,13 +19,25 @@ Example:
|
||||
...
|
||||
-->
|
||||
|
||||
#### Backtrace
|
||||
<!--
|
||||
Will help us track and understand issues faster.
|
||||
How to provide a backtrace:
|
||||
1. M-x toggle-debug-on-error
|
||||
2. Trigger error. The debugger buffer should pop up.
|
||||
3. Copy the contents of the debugger buffer and paste here
|
||||
-->
|
||||
|
||||
#### Expected Results
|
||||
|
||||
<!-- Example: File A is there -->
|
||||
|
||||
#### Actual Results
|
||||
|
||||
<!-- Example: File A is missing -->
|
||||
|
||||
### Versions
|
||||
- Emacs (`C-h v emacs-version`): vX.X.X
|
||||
### Environment
|
||||
|
||||
<!-- Please M-x org-roam-diagnostics and paste results here -->
|
||||
|
||||
- Org-roam commit: https://github.com/jethrokuan/org-roam/commit/commithashhere
|
||||
|
7
.github/ISSUE_TEMPLATE/feature_request.md
vendored
7
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Create a feature request to improve Org-roam
|
||||
title: ''
|
||||
labels: 'enhancement'
|
||||
assignees: 'jethrokuan'
|
||||
title: ""
|
||||
labels: "enhancement"
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
### Brief Abstract
|
||||
@ -13,4 +13,5 @@ assignees: 'jethrokuan'
|
||||
### Proposed Implementation (if any)
|
||||
|
||||
### Please check the following:
|
||||
|
||||
- [ ] No similar feature requests
|
||||
|
31
.github/workflows/docs.yml
vendored
Normal file
31
.github/workflows/docs.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
# * docs.yml --- Build the documentation and publish to Github Pages
|
||||
|
||||
name: "Docs"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo apt-get install texinfo
|
||||
|
||||
- name: Build docs
|
||||
continue-on-error: false
|
||||
run: make html
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages # The branch the action should deploy to.
|
||||
FOLDER: doc # The folder the action should deploy.
|
||||
CLEAN: true
|
19
.github/workflows/stale.yml
vendored
Normal file
19
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'Stale issue message'
|
||||
stale-pr-message: 'Stale pull request message'
|
||||
stale-issue-label: 'no-issue-activity'
|
||||
stale-pr-label: 'no-pr-activity'
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -29,7 +29,6 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -38,7 +37,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
emacs_version:
|
||||
- 26.3
|
||||
- snapshot
|
||||
steps:
|
||||
- uses: purcell/setup-emacs@master
|
||||
@ -57,7 +55,7 @@ jobs:
|
||||
# as failures, so linting and testing are run as separate steps.
|
||||
|
||||
- name: Lint
|
||||
continue-on-error: true
|
||||
continue-on-error: false
|
||||
run: ./makem.sh -vv --sandbox $SANDBOX_DIR lint
|
||||
|
||||
- name: Test
|
||||
|
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,2 +1,15 @@
|
||||
/.sandbox/
|
||||
**/*.elc
|
||||
/doc/dir
|
||||
/doc/*.info
|
||||
/doc/*.pdf
|
||||
/doc/*.epub
|
||||
/doc/META_INF/
|
||||
/doc/OEBPS/
|
||||
/doc/dir
|
||||
/doc/epub.xml
|
||||
/doc/org-roam/
|
||||
/doc/mimetype
|
||||
/doc/stats/
|
||||
/config.mk
|
||||
/doc/manual/
|
||||
|
233
CHANGELOG.md
233
CHANGELOG.md
@ -1,93 +1,200 @@
|
||||
# Changelog
|
||||
|
||||
## 1.1.1 (18-05-2020)
|
||||
|
||||
In this release, we added two new features:
|
||||
|
||||
1. `org-roam-doctor`: a linting system that helps you discover possible problems with your Org-roam files. This is in the spirit of keeping notes in top quality.
|
||||
2. A tagging system: one can now use sub-directories, and the `#+ROAM_TAG` key add additional meta data to notes. For more information, see [here](https://org-roam.github.io/org-roam/manual/Tags.html#Tags).
|
||||
|
||||
As usual, this release comes with a multitude of bug-fixes and refactorings.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- [#523](https://github.com/org-roam/org-roam/pull/523) remove `org-roam-completion-fuzzy-match` in favor of using completion mechanism's configuration options directly
|
||||
- [#547](https://github.com/org-roam/org-roam/pull/547) Deprecate `org-roam-db--maybe-update`, in favour of `org-roam-db--update-maybe`
|
||||
- [#604](https://github.com/org-roam/org-roam/pull/604) Deprecate `org-roam-title-include-subdirs`, `org-roam-title-subdir-format` `org-roam-title-subdir-separator`, for a more general tagging system built on subdirectories
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#509](https://github.com/org-roam/org-roam/pull/509) fix backup files being tracked in database
|
||||
- [#509](https://github.com/org-roam/org-roam/pull/509) fix external org files being tracked in database
|
||||
- [#537](https://github.com/org-roam/org-roam/pull/537) quote graphviz node and edge configuration options to allow multi-word configurations
|
||||
- [#545](https://github.com/org-roam/org-roam/pull/545) fix `org-roam--extract-links` to ensure that multiple citations (`cite:key1,key2`) are split correctly
|
||||
- [#547](https://github.com/org-roam/org-roam/pull/547) Fix unlinked citations
|
||||
- [#660](https://github.com/org-roam/org-roam/pull/660) fix rename-file advice not working for renaming to directories
|
||||
- [#660](https://github.com/org-roam/org-roam/pull/660) fix links breaking within file on file movement
|
||||
|
||||
### Features
|
||||
|
||||
- [#538](https://github.com/org-roam/org-roam/pull/538) Optionally use text in first headline as title
|
||||
- [#553](https://github.com/org-roam/org-roam/pull/553) Add prefix argument to `org-roam-db-build-cache` for forcing rebuilds
|
||||
- [#560](https://github.com/org-roam/org-roam/pull/560) Apply 'error face to distinguish broken links
|
||||
- [#570](https://github.com/org-roam/org-roam/pull/570) Add `org-roam-doctor` to diagnose org-roam files
|
||||
- [#625](https://github.com/org-roam/org-roam/pull/625) Add `org-roam-title-sources` to control how titles are retrieved within notes
|
||||
- [#604](https://github.com/org-roam/org-roam/pull/604) Add a tagging system. `org-roam-tag-sources` controls how tags are retrieved from notes
|
||||
|
||||
### Internal Changes
|
||||
|
||||
- [#547](https://github.com/org-roam/org-roam/pull/547) Added `type` column to the `refs` table
|
||||
- [#606](https://github.com/org-roam/org-roam/pull/606) Added `org-roam-dev.el` for developer coding standards
|
||||
- [#622](https://github.com/org-roam/org-roam/pull/622) Online documentation now points to the Org-based documentation
|
||||
|
||||
## 1.1.0 (21-04-2020)
|
||||
|
||||
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:
|
||||
|
||||
1. The codebase has been modularized into separate files, to ease future maintenance and adding of new features (mainly by [@progfolio](https://github.com/progfolio)). Because of these changes, we had to rename many functions and variables: the old names are kept for backwards compatibility, but you are encouraged to use the new function names. You'll receive a warning when you're calling the function with its obsolete name.
|
||||
2. [@kljohann](https://github.com/kljohann) did some fantastic work on graph generation: allowing building images for connected components within the graph up to a specified distance
|
||||
3. We also started supporting `org-ref` natively: cite links now show up in both the graph and the org-roam buffer.
|
||||
|
||||
In the coming months, you can expect work on bigger projects (e.g. revamping the org-roam buffer).
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- [#385](https://github.com/org-roam/org-roam/pull/385) Deprecate `org-roam-graph-node-shape` in favour of `org-roam-graph-node-extra-config`.
|
||||
- [#473](https://github.com/org-roam/org-roam/pull/473) Deprecate `org-roam-date-filename-format` and `org-roam-date-title-format`, in favour of `org-roam-dailies-capture-templates`.
|
||||
|
||||
### New Features
|
||||
|
||||
- [#350](https://github.com/org-roam/org-roam/pull/350) Add `org-roam-db-location` to customize location of org-roam database.
|
||||
- [#359](https://github.com/org-roam/org-roam/pull/359) Add `org-roam-verbose` to allow or silence printing of information.
|
||||
- [#374](https://github.com/org-roam/org-roam/pull/374) Add support for `org-ref` `cite:` links
|
||||
- [#380](https://github.com/org-roam/org-roam/pull/380) Allow `org-roam-buffer-position` to also be `top` or `bottom`
|
||||
- [#385](https://github.com/org-roam/org-roam/pull/385) Add `org-roam-graph-node-extra-config` to configure Graphviz nodes
|
||||
- [#398](https://github.com/org-roam/org-roam/pull/398), [#418](https://github.com/org-roam/org-roam/pull/418) Add graph building for connected components
|
||||
- [#435](https://github.com/org-roam/org-roam/pull/435) Add `org-roam-graph-edge-extra-config` to configure Graphviz edges
|
||||
- [#439](https://github.com/org-roam/org-roam/pull/439) Add support for `org-ref` citations to display as edges in graph. Add `org-roam-graph-edge-cites-extra-config` to configure these edges
|
||||
- [#465](https://github.com/org-roam/org-roam/pull/465) Add `org-roam-file-extensions` to allow detection of org files with different file extensions
|
||||
- [#488](https://github.com/org-roam/org-roam/pull/488) Allow a function for `org-roam-graph-viewer`
|
||||
- [#491](https://github.com/org-roam/org-roam/pull/491) Use TITLE as description when linking before first heading
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#470](https://github.com/org-roam/org-roam/pull/470) Add workaround for undocumented `file-truename` behaviour in `org-roam--org-roam-file-p`.
|
||||
|
||||
### Internal Changes
|
||||
|
||||
- [#363](https://github.com/org-roam/org-roam/pull/363), [#473](https://github.com/org-roam/org-roam/pull/473) Modularize org-roam features.
|
||||
- [#497](https://github.com/org-roam/org-roam/pull/497) Simplify `org-roam--list-files` implementation
|
||||
|
||||
## 1.0.0 (23-03-2020)
|
||||
|
||||
Org-roam is now on MELPA! We have squashed most of the bugs, and Org-roam has
|
||||
been stable for the most part.
|
||||
|
||||
### New Features
|
||||
|
||||
- [#269](https://github.com/org-roam/org-roam/pull/269) Add `org-roam-graphviz-extra-options`
|
||||
- [#257](https://github.com/org-roam/org-roam/pull/257) Add a company-backend `company-org-roam`
|
||||
- [#284](https://github.com/org-roam/org-roam/pull/284), [#289](https://github.com/org-roam/org-roam/pull/289) Configurable `org-roam-completion-system` with options `'default`, `'ido`, `'ivy` and `'helm`
|
||||
- [#289](https://github.com/org-roam/org-roam/pull/289) Add customizable `org-roam-fuzzy-match` to allow fuzzy-matching of candidates
|
||||
- [#290](https://github.com/org-roam/org-roam/pull/290) Add `org-roam-date-title-format` and `org-roam-date-filename-format` for customizing Org-roam's date files
|
||||
- [#296](https://github.com/org-roam/org-roam/pull/296) Allow multiple exclusion matchers in `org-roam-graph-exclude-matcher`
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#293](https://github.com/org-roam/org-roam/pull/293) Fix capture templates not working as expected for `org-roam-find-file`
|
||||
- [#275](https://github.com/org-roam/org-roam/pull/275) Fix database rebuild when `org-roam-directory` is set locally
|
||||
|
||||
## 1.0.0-rc1 (06-03-2020)
|
||||
|
||||
This is a pre-release before the push to MELPA. It contains large
|
||||
internal changes, with little user-facing changes. Most notably, the
|
||||
backing storage has been changed to a SQLite database, and a
|
||||
templating system using `org-capture` is introduced.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- [#200](https://github.com/org-roam/org-roam/pull/200) Move Org-roam cache into a SQLite database.
|
||||
- [#203](https://github.com/org-roam/org-roam/pull/203) Roam protocol is deprecated, in favour of extending org-roam-protocol.
|
||||
|
||||
### New Features
|
||||
|
||||
- [#182](https://github.com/org-roam/org-roam/pull/182) Support file name aliases via `#+ROAM_ALIAS`.
|
||||
- [#216](https://github.com/org-roam/org-roam/pull/216) Adds templating functionality by extending org-capture.
|
||||
- [#232](https://github.com/org-roam/org-roam/pull/232) Adds a prefix key to `org-roam-show-graph`, to generate graph without opening it.
|
||||
- [#233](https://github.com/org-roam/org-roam/pull/233) Adds `org-roam-graph-exclude-matcher`, which allows exclusion of nodes from graph.
|
||||
- [#247](https://github.com/org-roam/org-roam/pull/247) Add `org-roam-backlink` face, which allows customizing backlinks appearance
|
||||
- [#259](https://github.com/org-roam/org-roam/pull/259) Add optional initial-prompt to `org-roam-find-file`
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#207](https://github.com/org-roam/org-roam/pull/207), [#221](https://github.com/org-roam/org-roam/pull/221) small bugfixes to Org-roam graph generation
|
||||
- [#230](https://github.com/org-roam/org-roam/pull/230) remove nonspacing marks from filenames, to prevent cross-platform errors
|
||||
|
||||
### New Contributors
|
||||
|
||||
- [@acowley][https://github.com/acowley]
|
||||
- [@teesloane][https://github.com/teesloane]
|
||||
|
||||
## 0.1.2 (2020-02-21)
|
||||
|
||||
### Breaking Changes
|
||||
* [#143][gh-143] `org-roam-mode` is now a global mode. The installation instructions have changed accordingly.
|
||||
* [#103][gh-103] Change `org-roam-file-format` to a function: `org-roam-file-name-function` to allow more flexible file name customizaton. Also changes `org-roam-use-timestamp-as-filename` to `org-roam-filename-noconfirm` to better describe what it does.
|
||||
|
||||
- [#143](https://github.com/org-roam/org-roam/pull/143) `org-roam-mode` is now a global mode. The installation instructions have changed accordingly.
|
||||
- [#103](https://github.com/org-roam/org-roam/pull/103) Change `org-roam-file-format` to a function: `org-roam-file-name-function` to allow more flexible file name customizaton. Also changes `org-roam-use-timestamp-as-filename` to `org-roam-filename-noconfirm` to better describe what it does.
|
||||
|
||||
### New Features
|
||||
* [#145][gh-145] `org-roam-show-graph`: Fallback to Emacs SVG viewer
|
||||
* [#141][gh-141] add variable `org-roam-new-file-directory` for new Org-roam files
|
||||
* [#138][gh-138] add `org-roam-switch-to-buffer`
|
||||
* [#124][gh-124], [#141][gh-141] Maintain cache consistency on file rename and delete
|
||||
* [#87][gh-87], [#90][gh-90] Support encrypted Org files
|
||||
* [#110][gh-110] Add prefix to `org-roam-insert`, for inserting titles down-cased
|
||||
* [#99][gh-99] Add keybinding so that `<return>` or `mouse-1` in the backlinks buffer visits the source file of the backlink at point
|
||||
|
||||
- [#145](https://github.com/org-roam/org-roam/pull/145) `org-roam-show-graph`: Fallback to Emacs SVG viewer
|
||||
- [#141](https://github.com/org-roam/org-roam/pull/141) add variable `org-roam-new-file-directory` for new Org-roam files
|
||||
- [#138](https://github.com/org-roam/org-roam/pull/138) add `org-roam-switch-to-buffer`
|
||||
- [#124](https://github.com/org-roam/org-roam/pull/124), [#141](https://github.com/org-roam/org-roam/pull/141) Maintain cache consistency on file rename and delete
|
||||
- [#87](https://github.com/org-roam/org-roam/pull/87), [#90](https://github.com/org-roam/org-roam/pull/90) Support encrypted Org files
|
||||
- [#110](https://github.com/org-roam/org-roam/pull/110) Add prefix to `org-roam-insert`, for inserting titles down-cased
|
||||
- [#99](https://github.com/org-roam/org-roam/pull/99) Add keybinding so that `<return>` or `mouse-1` in the backlinks buffer visits the source file of the backlink at point
|
||||
|
||||
### Changes
|
||||
|
||||
* [#108][gh-108] Locally overwrite the link following behaviour in the org-roam-buffer to open files in the same window `org-roam` was called from
|
||||
- [#108](https://github.com/org-roam/org-roam/pull/108) Locally overwrite the link following behaviour in the org-roam-buffer to open files in the same window `org-roam` was called from
|
||||
|
||||
### Bugfixes
|
||||
* [#86][gh-86] Fix `org-roam--parse-content` incorrect `:to` computation for nested files
|
||||
* [#98][gh-98] Fix `org-roam--find-file` picking up temporary files
|
||||
* [#136][gh-136] Misc bugfixes
|
||||
|
||||
- [#86](https://github.com/org-roam/org-roam/pull/86) Fix `org-roam--parse-content` incorrect `:to` computation for nested files
|
||||
- [#98](https://github.com/org-roam/org-roam/pull/98) Fix `org-roam--find-file` picking up temporary files
|
||||
- [#136](https://github.com/org-roam/org-roam/pull/136) Misc bugfixes
|
||||
|
||||
### Internal
|
||||
* [#122][gh-122], [#128][gh-128] Improve performance of post-command-hook
|
||||
* [#92][gh-92], [#105][gh-105] Add tests for core functionality
|
||||
|
||||
- [#122](https://github.com/org-roam/org-roam/pull/122), [#128](https://github.com/org-roam/org-roam/pull/128) Improve performance of post-command-hook
|
||||
- [#92](https://github.com/org-roam/org-roam/pull/92), [#105](https://github.com/org-roam/org-roam/pull/105) Add tests for core functionality
|
||||
|
||||
### New Contributors
|
||||
* [@frigge](https://github.com/frigge)
|
||||
* [@juergenhoetzel](https://github.com/juergenhoetzel)
|
||||
* [@chip2n](https://github.com/chip2n)
|
||||
* [@l3kn](https://github.com/l3kn)
|
||||
* [@jdormit](https://github.com/jdormit)
|
||||
* [@herbertjones](https://github.com/herbertjones)
|
||||
* [@CeleritasCelery](https://github.com/CeleritasCelery)
|
||||
* [@daniel-koudouna](https://github.com/daniel-koudouna)
|
||||
|
||||
- [@frigge](https://github.com/frigge)
|
||||
- [@juergenhoetzel](https://github.com/juergenhoetzel)
|
||||
- [@chip2n](https://github.com/chip2n)
|
||||
- [@l3kn](https://github.com/l3kn)
|
||||
- [@jdormit](https://github.com/jdormit)
|
||||
- [@herbertjones](https://github.com/herbertjones)
|
||||
- [@CeleritasCelery](https://github.com/CeleritasCelery)
|
||||
- [@daniel-koudouna](https://github.com/daniel-koudouna)
|
||||
|
||||
## 0.1.1 (2020-02-15)
|
||||
|
||||
Mostly a documentation/cleanup release.
|
||||
|
||||
### New Features
|
||||
* [#62][gh-62] Add the options `org-roam-use-timestamps-as-filename` and `org-roam-file-format`, more in documentation.
|
||||
|
||||
- [#62](https://github.com/org-roam/org-roam/pull/62) Add the options `org-roam-use-timestamps-as-filename` and `org-roam-file-format`, more in documentation.
|
||||
|
||||
### Breaking Changes
|
||||
* [#62][gh-62] The ID (file-name) workflow is no longer first-class, but a fallback when titles don't exist.
|
||||
|
||||
- [#62](https://github.com/org-roam/org-roam/pull/62) The ID (file-name) workflow is no longer first-class, but a fallback when titles don't exist.
|
||||
|
||||
### Changes
|
||||
* [#66][gh-66], [#68][gh-68]: Improved the quality of the package in preparation of submission to MELPA
|
||||
* [#73][gh-73]: Added CI to the project via Github Issues (Thanks [@alphapapa](https://github.com/alphapapa/) for scripts and setup)
|
||||
* [#69][gh-69], [#72][gh-72], [#75][gh-75]: Major cleanup and de-duplication of code
|
||||
|
||||
- [#66](https://github.com/org-roam/org-roam/pull/66), [#68](https://github.com/org-roam/org-roam/pull/68): Improved the quality of the package in preparation of submission to MELPA
|
||||
- [#73](https://github.com/org-roam/org-roam/pull/73): Added CI to the project via Github Issues (Thanks [@alphapapa](https://github.com/alphapapa/) for scripts and setup)
|
||||
- [#69](https://github.com/org-roam/org-roam/pull/69), [#72](https://github.com/org-roam/org-roam/pull/72), [#75](https://github.com/org-roam/org-roam/pull/75): Major cleanup and de-duplication of code
|
||||
|
||||
### Bugfixes
|
||||
* [#67][gh-67]: Fixed `org-roam--make-file` not creating files with extensions
|
||||
* [#71][gh-71], [#78][gh-78]: Fixed `org-roam-insert` not inserting correct paths
|
||||
* [#82][gh-82]: Fixed nested Org-roam files not being detected as part of Org-roam
|
||||
|
||||
[gh-62]: https://github.com/jethrokuan/org-roam/pull/66
|
||||
[gh-66]: https://github.com/jethrokuan/org-roam/pull/66
|
||||
[gh-67]: https://github.com/jethrokuan/org-roam/pull/67
|
||||
[gh-68]: https://github.com/jethrokuan/org-roam/pull/68
|
||||
[gh-69]: https://github.com/jethrokuan/org-roam/pull/69
|
||||
[gh-71]: https://github.com/jethrokuan/org-roam/pull/71
|
||||
[gh-72]: https://github.com/jethrokuan/org-roam/pull/72
|
||||
[gh-73]: https://github.com/jethrokuan/org-roam/pull/73
|
||||
[gh-75]: https://github.com/jethrokuan/org-roam/pull/75
|
||||
[gh-78]: https://github.com/jethrokuan/org-roam/pull/78
|
||||
[gh-82]: https://github.com/jethrokuan/org-roam/pull/82
|
||||
[gh-86]: https://github.com/jethrokuan/org-roam/pull/86
|
||||
[gh-87]: https://github.com/jethrokuan/org-roam/pull/87
|
||||
[gh-90]: https://github.com/jethrokuan/org-roam/pull/90
|
||||
[gh-92]: https://github.com/jethrokuan/org-roam/pull/92
|
||||
[gh-98]: https://github.com/jethrokuan/org-roam/pull/98
|
||||
[gh-99]: https://github.com/jethrokuan/org-roam/pull/99
|
||||
[gh-103]: https://github.com/jethrokuan/org-roam/pull/103
|
||||
[gh-105]: https://github.com/jethrokuan/org-roam/pull/105
|
||||
[gh-108]: https://github.com/jethrokuan/org-roam/pull/108
|
||||
[gh-110]: https://github.com/jethrokuan/org-roam/pull/110
|
||||
[gh-122]: https://github.com/jethrokuan/org-roam/pull/122
|
||||
[gh-124]: https://github.com/jethrokuan/org-roam/pull/124
|
||||
[gh-128]: https://github.com/jethrokuan/org-roam/pull/128
|
||||
[gh-136]: https://github.com/jethrokuan/org-roam/pull/136
|
||||
[gh-138]: https://github.com/jethrokuan/org-roam/pull/138
|
||||
[gh-141]: https://github.com/jethrokuan/org-roam/pull/141
|
||||
[gh-142]: https://github.com/jethrokuan/org-roam/pull/142
|
||||
[gh-143]: https://github.com/jethrokuan/org-roam/pull/143
|
||||
- [#67](https://github.com/org-roam/org-roam/pull/67): Fixed `org-roam--make-file` not creating files with extensions
|
||||
- [#71](https://github.com/org-roam/org-roam/pull/71), [#78](https://github.com/org-roam/org-roam/pull/78): Fixed `org-roam-insert` not inserting correct paths
|
||||
- [#82](https://github.com/org-roam/org-roam/pull/82): Fixed nested Org-roam files not being detected as part of Org-roam
|
||||
|
||||
# Local Variables:
|
||||
# eval: (auto-fill-mode -1)
|
||||
# End:
|
||||
<!-- Local Variables: -->
|
||||
<!-- eval: (auto-fill-mode -1) -->
|
||||
<!-- End: -->
|
||||
|
14
Makefile
14
Makefile
@ -54,3 +54,17 @@ endif
|
||||
.DEFAULT: init
|
||||
init:
|
||||
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS)
|
||||
|
||||
docs:
|
||||
@$(MAKE) -C doc all
|
||||
|
||||
html:
|
||||
@$(MAKE) -C doc html-dir
|
||||
|
||||
install: install-docs
|
||||
|
||||
install-docs: docs
|
||||
@$(MAKE) -C doc install-docs
|
||||
|
||||
install-info: info
|
||||
@$(MAKE) -C doc install-info
|
||||
|
74
README.md
74
README.md
@ -1,50 +1,57 @@
|
||||
[![License GPL 3][badge-license]](http://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
[](https://org-roam.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://img.shields.io/github/v/release/jethrokuan/org-roam)
|
||||
[](https://img.shields.io/github/v/release/org-roam/org-roam)
|
||||
[](https://melpa.org/#/org-roam)
|
||||
|
||||
## Synopsis
|
||||
|
||||
Org-roam is a rudimentary [Roam][roamresearch] replica built around
|
||||
the all-powerful [Org-mode][org].
|
||||
Org-roam is a [Roam][roamresearch] replica built on top of the
|
||||
all-powerful [Org-mode][org].
|
||||
|
||||
Like Roam, Org-roam offers a powerful and effortless non-hierarchical
|
||||
note-taking approach. With Org-roam, notes flow naturally, making
|
||||
note-taking fun and easy. Org-roam *enables* a note-taking workflow that
|
||||
is not fluid with vanilla Org-mode (more in [this blog
|
||||
post](https://blog.jethro.dev/posts/how_to_take_smart_notes_org/)).
|
||||
Org-roam is a solution for effortless non-hierarchical note-taking
|
||||
with Org-mode. With Org-roam, notes flow naturally, making note-taking
|
||||
fun and easy. Org-roam should also work as a plug-and-play solution
|
||||
for anyone already using Org-mode for their personal wiki.
|
||||
|
||||
Org-roam aims to implement the core features of Roam, leveraging the
|
||||
mature ecosystem around Org-mode where possible. Eventually, we hope
|
||||
to further introduce features enabled by the Emacs ecosystem.
|
||||
|
||||
The goal of the project is to implement core features of Roam around
|
||||
Org-mode, and eventually introduce features enabled by the Emacs
|
||||
ecosystem.
|
||||
[@technovangelist](https://github.com/technovangelist/) has produced a video
|
||||
describing Org-roam and the concepts behind it:
|
||||
|
||||
Visit [the documentation
|
||||
page](https://org-roam.readthedocs.io/en/latest/) for a tutorial and
|
||||
more links.
|
||||
[](http://www.youtube.com/watch?v=Lg61ocfxk3c "Making Connections in your Notes")
|
||||
|
||||
As of February 2020, it is in a very early stage of development.
|
||||
Important links:
|
||||
|
||||
- **[Documentation][docs]**
|
||||
- **[Discourse][discourse]**
|
||||
- **[Slack][slack]**
|
||||
|
||||
## A Preview
|
||||
|
||||
Here's a screenshot of `org-roam`. The `org-roam` buffer shows
|
||||
backlinks for the active org buffer in the left window, as well as the
|
||||
surrounding content in the backlink file. The backlink database is
|
||||
built asynchronously in the background, and is not noticeable to the
|
||||
end user. The graph is generated from the link structure, and can be
|
||||
used to navigate to the respective files.
|
||||
Here's a screencast of Org-roam. The `org-roam-buffer` (window on the
|
||||
right) shows backlinks for the active Org-roam buffer (window on the
|
||||
left), as well as the surrounding content in the backlink file. The
|
||||
database is built once, and updated incrementally. The graph is
|
||||
generated from the link structure, and can be used to navigate to the
|
||||
respective files.
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
The recommended method is using use-package and straight, or a similar package manager.
|
||||
You can install `org-roam` using `package.el`:
|
||||
|
||||
```
|
||||
M-x package-install RET org-roam RET
|
||||
```
|
||||
|
||||
Here's a sample configuration with using `use-package`:
|
||||
|
||||
```emacs-lisp
|
||||
(use-package org-roam
|
||||
:after org
|
||||
:hook
|
||||
(after-init . org-roam-mode)
|
||||
:straight (:host github :repo "jethrokuan/org-roam" :branch "develop")
|
||||
:custom
|
||||
(org-roam-directory "/path/to/org-files/")
|
||||
:bind (:map org-roam-mode-map
|
||||
@ -55,11 +62,17 @@ The recommended method is using use-package and straight, or a similar package m
|
||||
(("C-c n i" . org-roam-insert))))
|
||||
```
|
||||
|
||||
For more detailed installation instructions (including instructions for
|
||||
Spacemacs users), please see [the installation
|
||||
documentation](https://org-roam.readthedocs.io/en/develop/installation/).
|
||||
`org-roam-graph` by default expects to find the `dot` executable
|
||||
from the `graphviz` package in the `exec-path`.
|
||||
Ensure `graphviz` is installed and found if you want to use this
|
||||
feature or customize your configuration for `org-roam-graph` to use a
|
||||
different tool.
|
||||
|
||||
## Knowledge Bases using Org-Roam
|
||||
For more detailed installation and configuration instructions (including for
|
||||
Doom and Spacemacs users), please see [the
|
||||
documentation][docs].
|
||||
|
||||
## Knowledge Bases using Org-roam
|
||||
|
||||
- [Jethro Kuan](https://braindump.jethro.dev/)
|
||||
([Source](https://github.com/jethrokuan/braindump/tree/master/org))
|
||||
@ -82,3 +95,6 @@ General Public License, Version 3
|
||||
[roamresearch]: https://www.roamresearch.com/
|
||||
[org]: https://orgmode.org/
|
||||
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
|
||||
[docs]: https://org-roam.github.io/org-roam/manual/
|
||||
[discourse]: https://org-roam.discourse.group/
|
||||
[slack]: https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg
|
||||
|
106
default.mk
Normal file
106
default.mk
Normal file
@ -0,0 +1,106 @@
|
||||
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||
|
||||
## User options ######################################################
|
||||
#
|
||||
# You can override these settings in "config.mk" or on the command
|
||||
# line.
|
||||
#
|
||||
# You might also want to set LOAD_PATH. If you do, then it must
|
||||
# contain "-L .".
|
||||
#
|
||||
# If you don't do so, then the default is set in the "Load-Path"
|
||||
# section below. The default assumes that all dependencies are
|
||||
# installed either at "../<DEPENDENCY>", or when using package.el
|
||||
# at "ELPA_DIR/<DEPENDENCY>-<HIGHEST-VERSION>".
|
||||
|
||||
sharedir ?= $(HOME)/.local/share
|
||||
lispdir ?= $(sharedir)/emacs/site-lisp/org-roam
|
||||
infodir ?= $(sharedir)/info
|
||||
docdir ?= $(sharedir)/doc/org-roam
|
||||
statsdir ?= $(TOP)/doc/stats
|
||||
|
||||
CP ?= install -p -m 644
|
||||
MKDIR ?= install -p -m 755 -d
|
||||
RMDIR ?= rm -rf
|
||||
TAR ?= tar
|
||||
SED ?= sed
|
||||
|
||||
EMACSBIN ?= emacs
|
||||
BATCH = $(EMACSBIN) -Q --batch $(LOAD_PATH)
|
||||
|
||||
INSTALL_INFO ?= $(shell command -v ginstall-info || printf install-info)
|
||||
MAKEINFO ?= makeinfo
|
||||
MANUAL_HTML_ARGS ?= --css-ref /assets/page.css
|
||||
|
||||
## Files #############################################################
|
||||
|
||||
PKG = org-roam
|
||||
PACKAGES = org-roam
|
||||
|
||||
TEXIPAGES = $(addsuffix .texi,$(PACKAGES))
|
||||
INFOPAGES = $(addsuffix .info,$(PACKAGES))
|
||||
HTMLFILES = $(addsuffix .html,$(PACKAGES))
|
||||
HTMLDIRS = $(PACKAGES)
|
||||
PDFFILES = $(addsuffix .pdf,$(PACKAGES))
|
||||
EPUBFILES = $(addsuffix .epub,$(PACKAGES))
|
||||
|
||||
ELS = org-roam-buffer.el
|
||||
ELS += org-roam-capture.el
|
||||
ELS += org-roam-compat.el
|
||||
ELS += org-roam-completion.el
|
||||
ELS += org-roam-dailies.el
|
||||
ELS += org-roam-db.el
|
||||
ELS += org-roam.el
|
||||
ELS += org-roam-graph.el
|
||||
ELS += org-roam-macs.el
|
||||
ELS += org-roam-protocol.el
|
||||
ELCS = $(ELS:.el=.elc)
|
||||
ELMS = org-roam.el $(filter-out $(addsuffix .el,$(PACKAGES)),$(ELS))
|
||||
ELGS = org-roam-autoloads.el org-roam-version.el
|
||||
|
||||
## Versions ##########################################################
|
||||
|
||||
VERSION ?= $(shell test -e $(TOP).git && git describe --tags --abbrev=0 | cut -c2-)
|
||||
|
||||
EMACS_VERSION = 26.1
|
||||
|
||||
EMACSOLD := $(shell $(BATCH) --eval \
|
||||
"(and (version< emacs-version \"$(EMACS_VERSION)\") (princ \"true\"))")
|
||||
ifeq "$(EMACSOLD)" "true"
|
||||
$(error At least version $(EMACS_VERSION) of Emacs is required)
|
||||
endif
|
||||
|
||||
## Load-Path #########################################################
|
||||
|
||||
ifndef LOAD_PATH
|
||||
|
||||
ELPA_DIR ?= $(HOME)/.emacs.d/elpa
|
||||
|
||||
SYSTYPE := $(shell $(EMACSBIN) -Q --batch --eval "(princ system-type)")
|
||||
ifeq ($(SYSTYPE), windows-nt)
|
||||
CYGPATH := $(shell cygpath --version 2>/dev/null)
|
||||
endif
|
||||
|
||||
LOAD_PATH = -L $(TOP)
|
||||
|
||||
# When making changes here, then don't forget to adjust "Makefile",
|
||||
# ".travis.yml", ".github/ISSUE_TEMPLATE/bug_report.md",
|
||||
# `magit-emacs-Q-command' and the "Installing from the Git Repository"
|
||||
# info node accordingly. Also don't forget to "rgrep \b<pkg>\b".
|
||||
|
||||
endif # ifndef LOAD_PATH
|
||||
|
||||
ifndef ORG_LOAD_PATH
|
||||
ORG_LOAD_PATH = $(LOAD_PATH)
|
||||
ORG_LOAD_PATH += -L $(TOP)../ox-texinfo-plus
|
||||
ORG_LOAD_PATH += -L $(TOP)../org-mode/contrib/lisp
|
||||
ORG_LOAD_PATH += -L $(TOP)../org-mode/lisp
|
||||
endif
|
||||
|
||||
## Publish ###########################################################
|
||||
|
||||
PUBLISH_TARGETS ?= html html-dir pdf epub
|
||||
|
||||
DOCBOOK_XSL ?= /usr/share/xml/docbook/stylesheet/docbook-xsl/epub/docbook.xsl
|
||||
|
||||
EPUBTRASH = epub.xml META-INF OEBPS
|
0
doc/.nojekyll
Normal file
0
doc/.nojekyll
Normal file
37
doc/AUTHORS.md
Normal file
37
doc/AUTHORS.md
Normal file
@ -0,0 +1,37 @@
|
||||
Authors
|
||||
=======
|
||||
|
||||
The following people have contributed to Org-Roam.
|
||||
|
||||
Names below are sorted alphabetically.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
- Jethro Kuan <jethrokuan95@gmail.com>
|
||||
|
||||
Maintainers
|
||||
----------
|
||||
|
||||
- Jethro Kuan <jethrokuan95@gmail.com>
|
||||
- Leo Vivier <leo.vivier+dev@gmail.com>
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
- Alexey Shmalko <rasen.dubi@gmail.com>
|
||||
- James Ravn <james@r-vn.org>
|
||||
- Jethro Kuan <jethrokuan95@gmail.com>
|
||||
- Johann Klähn <johann@jklaehn.de>
|
||||
- Josh English <josh@joshenglish.com>
|
||||
- Jürgen Hötzel <juergen@archlinux.org>
|
||||
- Langston Barrett <langston.barrett@gmail.com>
|
||||
- Leo Vivier <leo.vivier+dev@gmail.com>
|
||||
- Michael Glaesemann <grzm@seespotcode.net>
|
||||
- Michael Herold <github@michaeljherold.com>
|
||||
- Noboru <noboru.ota@gmail.com>
|
||||
- N V <44036031+progfolio@users.noreply.github.com>
|
||||
- Rafael Accácio Nogueira <raccacio@poli.ufrj.br>
|
||||
- Roland Coeurjoly <rolandcoeurjoly@gmail.com>
|
||||
- Sayan <dit7ya@users.noreply.github.com>
|
||||
- Tim Quelch <tim@quelch.name>
|
130
doc/Makefile
Normal file
130
doc/Makefile
Normal file
@ -0,0 +1,130 @@
|
||||
-include ../config.mk
|
||||
include ../default.mk
|
||||
|
||||
###################################################################
|
||||
MANUAL_HTML_ARGS = --css-ref assets/page.css
|
||||
|
||||
.PHONY: texi install clean AUTHORS.md stats
|
||||
|
||||
all: info
|
||||
|
||||
## Build #############################################################
|
||||
|
||||
info: $(INFOPAGES) dir
|
||||
html: $(HTMLFILES)
|
||||
pdf: $(PDFFILES)
|
||||
epub: $(EPUBFILES)
|
||||
|
||||
%.info: %.texi
|
||||
@printf "Generating $@\n"
|
||||
@$(MAKEINFO) --no-split $< -o $@
|
||||
|
||||
dir: org-roam.info
|
||||
@printf "Generating dir\n"
|
||||
@echo $^ | xargs -n 1 $(INSTALL_INFO) --dir=$@
|
||||
|
||||
%.html: %.texi
|
||||
@printf "Generating $@\n"
|
||||
@$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) $<
|
||||
|
||||
html-dir:
|
||||
@printf "Generating org-roam/*.html\n"
|
||||
@$(MAKEINFO) --html $(MANUAL_HTML_ARGS) org-roam.texi
|
||||
mv org-roam manual
|
||||
cp -r assets manual
|
||||
cp -r images manual
|
||||
|
||||
%.pdf: %.texi
|
||||
@printf "Generating $@\n"
|
||||
@texi2pdf --clean $< > /dev/null
|
||||
|
||||
%.epub: %.texi
|
||||
@printf "Generating $@\n"
|
||||
@$(MAKEINFO) --docbook $< -o epub.xml
|
||||
@xsltproc $(DOCBOOK_XSL) epub.xml 2> /dev/null
|
||||
@echo "application/epub+zip" > mimetype
|
||||
@zip -X --quiet --recurse-paths -0 $@ mimetype
|
||||
@zip -X --quiet --recurse-paths -9 --no-dir-entries $@ META-INF OEBPS
|
||||
@$(RMDIR) $(EPUBTRASH)
|
||||
|
||||
## Install ###########################################################
|
||||
|
||||
install: install-info install-docs
|
||||
|
||||
install-docs: install-info
|
||||
@$(MKDIR) $(DESTDIR)$(docdir)
|
||||
$(CP) AUTHORS.md $(DESTDIR)$(docdir)
|
||||
|
||||
install-info: info
|
||||
@$(MKDIR) $(DESTDIR)$(infodir)
|
||||
$(CP) $(INFOPAGES) $(DESTDIR)$(infodir)
|
||||
|
||||
## Clean #############################################################
|
||||
|
||||
clean:
|
||||
@printf "Cleaning doc/*...\n"
|
||||
@$(RMDIR) dir $(INFOPAGES) $(HTMLFILES) $(HTMLDIRS) $(PDFFILES)
|
||||
@$(RMDIR) $(EPUBFILES) $(EPUBTRASH)
|
||||
|
||||
## Release management ################################################
|
||||
|
||||
ORG_ARGS = --batch -Q $(ORG_LOAD_PATH)
|
||||
ORG_ARGS += -l ox-extra -l ox-texinfo+
|
||||
ORG_ARGS += --eval "(or (require 'org-man nil t) (require 'ol-man))"
|
||||
ORG_EVAL = --eval "(ox-extras-activate '(ignore-headlines))"
|
||||
ORG_EVAL += --eval "(setq indent-tabs-mode nil)"
|
||||
ORG_EVAL += --eval "(setq org-src-preserve-indentation nil)"
|
||||
ORG_EVAL += --funcall org-texinfo-export-to-texinfo
|
||||
|
||||
# This target first bumps version strings in the Org source. The
|
||||
# necessary tools might be missing so other targets do not depend
|
||||
# on this target and it has to be run explicitly when appropriate.
|
||||
#
|
||||
# AMEND=t make texi Update manual to be amended to HEAD.
|
||||
# VERSION=N make texi Update manual for release.
|
||||
#
|
||||
texi:
|
||||
@$(EMACSBIN) $(ORG_ARGS) $(PKG).org $(ORG_EVAL)
|
||||
@printf "\n" >> $(PKG).texi
|
||||
@rm -f $(PKG).texi~
|
||||
|
||||
stats:
|
||||
@printf "Generating statistics\n"
|
||||
@gitstats -c style=/assets/stats.css -c max_authors=999 $(TOP) $(statsdir)
|
||||
|
||||
authors: AUTHORS.md
|
||||
|
||||
AUTHORS.md:
|
||||
@printf "Generating AUTHORS.md..."
|
||||
@test -e $(TOP).git \
|
||||
&& (printf "$$AUTHORS_HEADER\n" > $@ \
|
||||
&& git log --pretty=format:'- %aN <%aE>' | sort -u >> $@ \
|
||||
&& printf "done\n" ; ) \
|
||||
|| printf "FAILED (non-fatal)\n"
|
||||
|
||||
# Templates ##########################################################
|
||||
|
||||
define AUTHORS_HEADER
|
||||
Authors
|
||||
=======
|
||||
|
||||
The following people have contributed to Org-Roam.
|
||||
|
||||
Names below are sorted alphabetically.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
- Jethro Kuan <jethrokuan95@gmail.com>
|
||||
|
||||
Maintainers
|
||||
----------
|
||||
|
||||
- Jethro Kuan <jethrokuan95@gmail.com>
|
||||
- Leo Vivier <leo.vivier+dev@gmail.com>
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
endef
|
||||
export AUTHORS_HEADER
|
442
doc/assets/page.css
Normal file
442
doc/assets/page.css
Normal file
@ -0,0 +1,442 @@
|
||||
/* Import Inter font */
|
||||
/* More info at https://github.com/xz/fonts */
|
||||
@import url("https://fonts.xz.style/serve/inter.css");
|
||||
|
||||
:root {
|
||||
--nc-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
--nc-font-mono: "Courier New", Courier, "Ubuntu Mono", "Liberation Mono",
|
||||
monospace;
|
||||
--nc-tx-1: #000000;
|
||||
--nc-tx-2: #1a1a1a;
|
||||
--nc-bg-1: #ffffff;
|
||||
--nc-bg-2: #f6f8fa;
|
||||
--nc-bg-3: #e5e7eb;
|
||||
--nc-lk-1: #0070f3;
|
||||
--nc-lk-2: #0366d6;
|
||||
--nc-lk-tx: #ffffff;
|
||||
--nc-ac-1: #79ffe1;
|
||||
--nc-ac-tx: #0c4047;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--nc-tx-1: #ffffff;
|
||||
--nc-tx-2: #eeeeee;
|
||||
--nc-bg-1: #000000;
|
||||
--nc-bg-2: #111111;
|
||||
--nc-bg-3: #222222;
|
||||
--nc-lk-1: #3291ff;
|
||||
--nc-lk-2: #0070f3;
|
||||
--nc-lk-tx: #ffffff;
|
||||
--nc-ac-1: #7928ca;
|
||||
--nc-ac-tx: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
/* Reset margins and padding */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
address,
|
||||
area,
|
||||
article,
|
||||
aside,
|
||||
audio,
|
||||
blockquote,
|
||||
datalist,
|
||||
details,
|
||||
dl,
|
||||
fieldset,
|
||||
figure,
|
||||
form,
|
||||
input,
|
||||
iframe,
|
||||
img,
|
||||
meter,
|
||||
nav,
|
||||
ol,
|
||||
optgroup,
|
||||
option,
|
||||
output,
|
||||
p,
|
||||
pre,
|
||||
progress,
|
||||
ruby,
|
||||
section,
|
||||
table,
|
||||
textarea,
|
||||
ul,
|
||||
video {
|
||||
/* Margins for most elements */
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
html,
|
||||
input,
|
||||
select,
|
||||
button {
|
||||
/* Set body font family and some finicky elements */
|
||||
font-family: var(--nc-font-sans);
|
||||
}
|
||||
|
||||
body {
|
||||
/* Center body in page */
|
||||
margin: 0 auto;
|
||||
max-width: 750px;
|
||||
padding: 2rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: hidden;
|
||||
background: var(--nc-bg-1);
|
||||
|
||||
/* Main body text */
|
||||
color: var(--nc-tx-2);
|
||||
font-size: 1.03rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
::selection {
|
||||
/* Set background color for selected text */
|
||||
background: var(--nc-ac-1);
|
||||
color: var(--nc-ac-tx);
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1;
|
||||
color: var(--nc-tx-1);
|
||||
padding-top: 0.875rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
color: var(--nc-tx-1);
|
||||
padding-bottom: 2px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid var(--nc-bg-2);
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.85rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.55rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--nc-lk-1);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--nc-lk-2);
|
||||
}
|
||||
|
||||
abbr:hover {
|
||||
/* Set the '?' cursor while hovering an abbreviation */
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 1.5rem;
|
||||
background: var(--nc-bg-2);
|
||||
border-left: 5px solid var(--nc-bg-3);
|
||||
}
|
||||
|
||||
abbr {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
blockquote *:last-child {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
header {
|
||||
background: var(--nc-bg-2);
|
||||
border-bottom: 1px solid var(--nc-bg-3);
|
||||
padding: 2rem 1.5rem;
|
||||
|
||||
/* This sets the right and left margins to cancel out the body's margins. It's width is still the same, but the background stretches across the page's width. */
|
||||
|
||||
margin: -2rem calc(0px - (50vw - 50%)) 2rem;
|
||||
|
||||
/* Shorthand for:
|
||||
|
||||
margin-top: -2rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
margin-left: calc(0px - (50vw - 50%));
|
||||
margin-right: calc(0px - (50vw - 50%)); */
|
||||
|
||||
padding-left: calc(50vw - 50%);
|
||||
padding-right: calc(50vw - 50%);
|
||||
}
|
||||
|
||||
header h1,
|
||||
header h2,
|
||||
header h3 {
|
||||
padding-bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
header > *:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
header > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.button,
|
||||
button,
|
||||
input[type="submit"],
|
||||
input[type="reset"],
|
||||
input[type="button"] {
|
||||
font-size: 1rem;
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
background: var(--nc-lk-1);
|
||||
color: var(--nc-lk-tx);
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
color: var(--nc-lk-tx);
|
||||
}
|
||||
|
||||
.button[disabled],
|
||||
button[disabled],
|
||||
input[type="submit"][disabled],
|
||||
input[type="reset"][disabled],
|
||||
input[type="button"][disabled] {
|
||||
cursor: default;
|
||||
opacity: 0.5;
|
||||
|
||||
/* Set the [X] cursor while hovering a disabled link */
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.button:focus,
|
||||
.button:hover,
|
||||
button:focus,
|
||||
button:hover,
|
||||
input[type="submit"]:focus,
|
||||
input[type="submit"]:hover,
|
||||
input[type="reset"]:focus,
|
||||
input[type="reset"]:hover,
|
||||
input[type="button"]:focus,
|
||||
input[type="button"]:hover {
|
||||
background: var(--nc-lk-2);
|
||||
}
|
||||
|
||||
code,
|
||||
pre,
|
||||
kbd,
|
||||
samp {
|
||||
/* Set the font family for monospaced elements */
|
||||
font-family: var(--nc-font-mono);
|
||||
}
|
||||
|
||||
code,
|
||||
samp,
|
||||
kbd,
|
||||
pre {
|
||||
/* The main preformatted style. This is changed slightly across different cases. */
|
||||
background: var(--nc-bg-2);
|
||||
border: 1px solid var(--nc-bg-3);
|
||||
border-radius: 4px;
|
||||
padding: 3px 6px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
kbd {
|
||||
/* Makes the kbd element look like a keyboard key */
|
||||
border-bottom: 3px solid var(--nc-bg-3);
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 1rem 1.4rem;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
pre code {
|
||||
/* When <code> is in a <pre>, reset it's formatting to blend in */
|
||||
background: inherit;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code pre {
|
||||
/* When <pre> is in a <code>, reset it's formatting to blend in */
|
||||
display: inline;
|
||||
background: inherit;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
details {
|
||||
/* Make the <details> look more "clickable" */
|
||||
padding: 0.6rem 1rem;
|
||||
background: var(--nc-bg-2);
|
||||
border: 1px solid var(--nc-bg-3);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
summary {
|
||||
/* Makes the <summary> look more like a "clickable" link with the pointer cursor */
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
details[open] {
|
||||
/* Adjust the <details> padding while open */
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
details[open] summary {
|
||||
/* Adjust the <details> padding while open */
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
details[open] > *:last-child {
|
||||
/* Resets the bottom margin of the last element in the <details> while <details> is opened. This prevents double margins/paddings. */
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd::before {
|
||||
/* Add an arrow to data table definitions */
|
||||
content: "→ ";
|
||||
}
|
||||
|
||||
hr {
|
||||
/* Reset the border of the <hr> separator, then set a better line */
|
||||
border: 0;
|
||||
border-bottom: 1px solid var(--nc-bg-3);
|
||||
margin: 1rem auto;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin-top: 1rem;
|
||||
padding: 2rem;
|
||||
border: 1px solid var(--nc-bg-3);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: auto 0.5rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
/* Don't let the <textarea> extend off the screen naturally or when dragged by the user */
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
/* Replace the browser default padding */
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol,
|
||||
ol ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 3px 6px;
|
||||
background: var(--nc-ac-1);
|
||||
color: var(--nc-ac-tx);
|
||||
}
|
||||
|
||||
textarea,
|
||||
select,
|
||||
input {
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 0.5rem;
|
||||
background: var(--nc-bg-2);
|
||||
color: var(--nc-tx-2);
|
||||
|
||||
/* Set a border of the same color as the main background. It isn't visible on idle, but prevents the cell from growing in size when a darker border is set on focus. */
|
||||
border: 1px solid var(--nc-bg-2);
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
textarea:focus,
|
||||
select:focus,
|
||||
input[type]:focus {
|
||||
border: 1px solid var(--nc-bg-3);
|
||||
|
||||
/* Reset any browser default outlines */
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Customizations */
|
||||
.menu-comment {
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1.2rem;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
---
|
||||
title: "Comparing Org-Roam With Other Packages"
|
||||
metaTitle: "Comparing Org-Roam With Other Packages"
|
||||
metaDescription: "Comparing Org-Roam With Other Packages"
|
||||
---
|
||||
|
||||
# Org-brain
|
||||
|
||||
# Zetteldeft
|
||||
|
||||
# Org-zettelkasten
|
@ -1,121 +0,0 @@
|
||||
To ensure that Org-roam remains manageable, the number of
|
||||
configuration options is deliberately kept small. However, we have
|
||||
attempted to accommodate as many usage styles as possible.
|
||||
|
||||
In this section, we'll go over the main customization options
|
||||
available to Org-Roam. This section is *crucial*. We need to exploit
|
||||
the flexibility of Emacs, and mould our tools exactly to our liking.
|
||||
|
||||
All of Org-roam's customization options can be viewed via `M-x
|
||||
customize-group org-roam`.
|
||||
|
||||
## Setting the Org-roam Directory
|
||||
|
||||
Perhaps the single most important variable to set is
|
||||
`org-roam-directory`. Set `org-roam-directory` to the folder
|
||||
containing all your Org files:
|
||||
|
||||
```emacs-lisp
|
||||
(setq org-roam-directory "/path/to/org/")
|
||||
```
|
||||
|
||||
Every Org file, at any level of nesting, within `/path/to/org/` is
|
||||
considered part of the Org-roam ecosystem.
|
||||
|
||||
## Org-roam Buffer
|
||||
|
||||
The Org-roam buffer defaults to popping up from the right. You may
|
||||
choose to set it to pop up from the left with `(setq
|
||||
org-roam-buffer-position 'left)`.
|
||||
|
||||
The Org-roam buffer name can also be renamed: e.g. `(setq
|
||||
org-roam-buffer "*my-buffer-name*")`.
|
||||
|
||||
The Org-roam buffer width is adjustable via `org-roam-buffer-width`.
|
||||
The value of `org-roam-buffer-width` set as a percentage of the total
|
||||
frame width. For example:
|
||||
|
||||
```emacs-lisp
|
||||
(setq org-roam-buffer-width 0.4)
|
||||
```
|
||||
|
||||
Will result in the Org-roam buffer taking up 40% of the screen width.
|
||||
I have found this to be a good number.
|
||||
|
||||
## Org-roam Links
|
||||
|
||||
By default, links are inserted with the title as the link description.
|
||||
This can make them hard to distinguish from external links. If you
|
||||
wish, you may choose add special indicators for Org-roam links by
|
||||
tweaking `org-roam-link-title-format`, for example:
|
||||
|
||||
```emacs-lisp
|
||||
(setq org-roam-link-title-format "R:%s")
|
||||
```
|
||||
|
||||
## Org-roam Files
|
||||
|
||||
These customization options revolve around the Org files created and
|
||||
managed by Org-roam.
|
||||
|
||||
### Automatically Creating Files Using Timestamp
|
||||
|
||||
A common hassle is ensuring that files are uniquely named within the
|
||||
Org-roam directory. Org-roam's default workflow utilizes the title of
|
||||
Org files in all of its main commands (`org-roam-insert`,
|
||||
`org-roam-find-file`). Hence, having any unique file name is a decent
|
||||
option, and the default workflow uses the timestamp as the filename.
|
||||
|
||||
The format of the filename is controlled by the function
|
||||
`org-roam-file-name-function`, which defaults to a format like
|
||||
`YYYYMMDDHHMMSS_title_here.org`. You may choose to define your own
|
||||
function to change this.
|
||||
|
||||
If you wish to be prompted to change the file name on creation, set
|
||||
`org-roam-filename-noconfirm` to `nil`:
|
||||
|
||||
```emacs-lisp
|
||||
(setq org-roam-filename-noconfirm nil)
|
||||
```
|
||||
|
||||
It is then the user's responsibility to ensure that the file names are
|
||||
unique.
|
||||
|
||||
### Autopopulating Titles
|
||||
|
||||
The default workflow uses the title of the Org file in several
|
||||
commands. The title is specified via the `#+TITLE:` attribute,
|
||||
typically near the top of the file. The option
|
||||
`org-roam-autopopulate-title` defaults to `t`. When true, the title
|
||||
attribute is automatically inserted into the files created via
|
||||
Org-roam commands. Setting it to `nil` will disable this behaviour.
|
||||
|
||||
### Encryption
|
||||
|
||||
Encryption (via GPG) can be enabled for all new files by setting
|
||||
`org-roam-encrypt-files` to `t`. When enabled, new files are created
|
||||
with the .org.gpg extension and decryption are handled automatically
|
||||
by EasyPG. Note that this causes Emacs to ask for password when the
|
||||
cache is built (if you have an encrypted file in `org-roam-directory`)
|
||||
as well as each time a new file is created. It might be a good idea to
|
||||
cache the password in order to make this more managable.
|
||||
|
||||
## Org-roam Graph Viewer
|
||||
|
||||
Org-roam generates an SVG image using
|
||||
[Graphviz](https://graphviz.org/). To setup graph navigation, see the
|
||||
[Graph Setup](graph_setup.md) page.
|
||||
|
||||
Org-roam tries its best to locate the Graphviz executable from your
|
||||
PATH, but if it fails to do so, you may set it manually:
|
||||
|
||||
```
|
||||
(setq org-roam-graphviz-executable "/path/to/dot")
|
||||
```
|
||||
|
||||
Org-roam also attempts to use Firefox (located on PATH) to view the
|
||||
SVG, you may choose to set it to any compatible program:
|
||||
|
||||
```
|
||||
(setq org-roam-graph-viewer "/path/to/image-viewer")
|
||||
```
|
126
doc/ecosystem.md
126
doc/ecosystem.md
@ -1,126 +0,0 @@
|
||||
A number of packages work well combined with Org-Roam:
|
||||
|
||||
## Deft
|
||||
|
||||
[Deft][deft] provides a nice interface for browsing and filtering
|
||||
org-roam notes.
|
||||
|
||||
```emacs-lisp
|
||||
(use-package deft
|
||||
:after org
|
||||
:bind
|
||||
("C-c n d" . deft)
|
||||
:custom
|
||||
(deft-recursive t)
|
||||
(deft-use-filter-string-for-filename t)
|
||||
(deft-default-extension "org")
|
||||
(deft-directory "/path/to/org-roam-files/"))
|
||||
```
|
||||
|
||||
If the title of the Org file is not the first line, you might not get
|
||||
nice titles. You may choose to patch this to use `org-roam`'s
|
||||
functionality. Here I'm using [el-patch](https://github.com/raxod502/el-patch):
|
||||
|
||||
```emacs-lisp
|
||||
(use-package el-patch
|
||||
:straight (:host github
|
||||
:repo "raxod502/el-patch"
|
||||
:branch "develop"))
|
||||
|
||||
(eval-when-compile
|
||||
(require 'el-patch))
|
||||
|
||||
(use-package deft
|
||||
;; same as above...
|
||||
:config/el-patch
|
||||
(defun deft-parse-title (file contents)
|
||||
"Parse the given FILE and CONTENTS and determine the title.
|
||||
If `deft-use-filename-as-title' is nil, the title is taken to
|
||||
be the first non-empty line of the FILE. Else the base name of the FILE is
|
||||
used as title."
|
||||
(el-patch-swap (if deft-use-filename-as-title
|
||||
(deft-base-filename file)
|
||||
(let ((begin (string-match "^.+$" contents)))
|
||||
(if begin
|
||||
(funcall deft-parse-title-function
|
||||
(substring contents begin (match-end 0))))))
|
||||
(org-roam--get-title-or-slug file))))
|
||||
```
|
||||
|
||||
The Deft interface can slow down quickly when the number of files get
|
||||
huge. [Notdeft][notdeft] is a fork of Deft that uses an external
|
||||
search engine and indexer.
|
||||
|
||||
## Org-journal
|
||||
|
||||
[Org-journal](https://github.com/bastibe/org-journal) is a more
|
||||
powerful alternative to the simple function `org-roam-today`. It
|
||||
provides better journaling capabilities, and a nice calendar interface
|
||||
to see all dated entries.
|
||||
|
||||
```emacs-lisp
|
||||
(use-package org-journal
|
||||
:bind
|
||||
("C-c n j" . org-journal-new-entry)
|
||||
:custom
|
||||
(org-journal-date-prefix "#+TITLE: ")
|
||||
(org-journal-file-format "%Y-%m-%d.org")
|
||||
(org-journal-dir "/path/to/org-roam-files/")
|
||||
(org-journal-date-format "%A, %d %B %Y"))
|
||||
```
|
||||
|
||||
## Note-taking Add-ons
|
||||
|
||||
These are some plugins that make note-taking in Org-mode more
|
||||
enjoyable.
|
||||
|
||||
### Org-download
|
||||
|
||||
[Org-download][org-download] lets you screenshot and yank images from
|
||||
the web into your notes:
|
||||
|
||||

|
||||
|
||||
```emacs-lisp
|
||||
(use-package org-download
|
||||
:after org
|
||||
:bind
|
||||
(:map org-mode-map
|
||||
(("s-Y" . org-download-screenshot)
|
||||
("s-y" . org-download-yank))))
|
||||
```
|
||||
|
||||
### mathpix.el
|
||||
|
||||
[mathpix.el][mathpix-el] uses [Mathpix's](https://mathpix.com/) API to convert clips into
|
||||
latex equations:
|
||||
|
||||

|
||||
|
||||
```emacs-lisp
|
||||
(use-package mathpix.el
|
||||
:straight (:host github :repo "jethrokuan/mathpix.el")
|
||||
:custom ((mathpix-app-id "app-id")
|
||||
(mathpix-app-key "app-key"))
|
||||
:bind
|
||||
("C-x m" . mathpix-screenshot))
|
||||
```
|
||||
|
||||
### Org-noter / Interleave
|
||||
|
||||
[Org-noter][org-noter] and [Interleave][interleave] are both projects
|
||||
that allow synchronised annotation of documents (PDF, EPUB etc.)
|
||||
within Org-mode.
|
||||
|
||||
### Org-ref
|
||||
|
||||
[Org-ref][org-ref] does citation and bibliography management in
|
||||
Org-mode, and a great tool for scientific notes.
|
||||
|
||||
[deft]: https://jblevins.org/projects/deft/
|
||||
[notdeft]: https://github.com/hasu/notdeft
|
||||
[org-download]: https://github.com/abo-abo/org-download
|
||||
[mathpix-el]: https://github.com/jethrokuan/mathpix.el
|
||||
[org-noter]: https://github.com/weirdNox/org-noter
|
||||
[interleave]: https://github.com/rudolfochrist/interleave
|
||||
[org-ref]: https://github.com/jkitchin/org-ref
|
@ -1,78 +0,0 @@
|
||||
The setup is similar to that of org-protocol. Here `roam://` links are
|
||||
defined, and need to be associated with an application.
|
||||
|
||||
The gist of the setup is setting up a Bash script to trim off the
|
||||
`roam://` prefix from the link, causing the desktop application to
|
||||
call `emacsclient path/to/org-roam-file.org`.
|
||||
|
||||
## Linux
|
||||
|
||||
Create a desktop application. I place mine in
|
||||
`~/.local/share/applications/roam.desktop`:
|
||||
|
||||
```
|
||||
[Desktop Entry]
|
||||
Name=Org-Roam Client
|
||||
Exec=/home/jethro/.local/bin/launch_emacs %u
|
||||
Icon=emacs-icon
|
||||
Type=Application
|
||||
Terminal=false
|
||||
MimeType=x-scheme-handler/roam
|
||||
```
|
||||
|
||||
Note the `Exec` key is set to a bash script poorly named
|
||||
`launch_emacs`. You can set it to whatever you want.
|
||||
|
||||
Create the corresponding bash script, and make it executable. Here's
|
||||
how it looks like:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
emacsclient "${1#*:}"
|
||||
```
|
||||
|
||||
Finally, associate `roam://` links with the desktop application by
|
||||
running in your shell:
|
||||
|
||||
```bash
|
||||
xdg-mime default roam.desktop x-scheme-handler/roam
|
||||
```
|
||||
|
||||
## Mac OS
|
||||
|
||||
One solution to this, recommended in [Issue
|
||||
#115](https://github.com/jethrokuan/org-roam/issues/115), is to use
|
||||
[Platypus](https://github.com/sveinbjornt/Platypus). Here are the
|
||||
instructions for setting up with Platypus and Chrome:
|
||||
|
||||
1. Create an executable `launch-emacs.sh` script:
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env bash
|
||||
/usr/local/bin/emacsclient --no-wait "${1#*:}"
|
||||
```
|
||||
|
||||
2. Install and launch Platypus (with [Homebrew](https://brew.sh/)):
|
||||
|
||||
```sh
|
||||
brew cask install playtpus
|
||||
```
|
||||
|
||||
3. Playtpus settings:
|
||||
|
||||
- App Name: `OrgRoam`
|
||||
- Script Type: `env` and `/usr/bin/env`
|
||||
- Script Path: `/path/to/your/launch-emacs.sh`
|
||||
- Tick Accept dropped items and click Settings
|
||||
- Tick Accept dropped files
|
||||
- Tick Register as URI scheme handler
|
||||
- Add `roam` as a protocol
|
||||
- Create the app
|
||||
|
||||
To disable the "confirm" prompt in Chrome, you can also make Chrome
|
||||
show a checkbox to tick, so that the `OrgRoam` app will be used
|
||||
without confirmation. To do this, run in a shell:
|
||||
|
||||
```sh
|
||||
defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -bool true
|
||||
```
|
15
doc/htmlxref.cnf
Normal file
15
doc/htmlxref.cnf
Normal file
@ -0,0 +1,15 @@
|
||||
# https://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Configuration.html
|
||||
|
||||
EMACS = https://www.gnu.org/software/emacs/manual
|
||||
|
||||
auth mono ${EMACS}/html_mono/auth.html
|
||||
auth node ${EMACS}/html_node/auth/
|
||||
|
||||
ediff mono ${EMACS}/html_mono/ediff.html
|
||||
ediff node ${EMACS}/html_node/ediff/
|
||||
|
||||
elisp mono ${EMACS}/html_mono/elisp.html
|
||||
elisp node ${EMACS}/html_node/elisp/
|
||||
|
||||
emacs mono ${EMACS}/html_mono/emacs.html
|
||||
emacs node ${EMACS}/html_node/emacs/
|
BIN
doc/images/org-ref-citelink.png
Normal file
BIN
doc/images/org-ref-citelink.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 279 KiB |
BIN
doc/images/org-roam-bibtex.gif
Normal file
BIN
doc/images/org-roam-bibtex.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
BIN
doc/images/roam-ref.gif
Normal file
BIN
doc/images/roam-ref.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 MiB |
3
doc/index.html
Normal file
3
doc/index.html
Normal file
@ -0,0 +1,3 @@
|
||||
<html>
|
||||
<h1>--> <a href="manual/index.html">MANUAL HERE</a> <--</h1>
|
||||
</html>
|
41
doc/index.md
41
doc/index.md
@ -1,41 +0,0 @@
|
||||
![org-roam][org-roam-intro-image]
|
||||
|
||||
## What is Org-Roam?
|
||||
|
||||
Org-roam is a rudimentary [Roam][roamresearch] replica built around
|
||||
the all-powerful [Org-mode][org].
|
||||
|
||||
Like Roam, Org-roam offers a powerful and effortless non-hierarchical
|
||||
note-taking approach. With Org-roam, notes flow naturally, making
|
||||
note-taking fun and easy. To understand more about Roam, I recommend
|
||||
the following links:
|
||||
|
||||
- [Building a second brain in
|
||||
Roam](https://reddit.com/r/RoamResearch/comments/eho7de/building_a_second_brain_in_roamand_why_you_might)
|
||||
- [Roam: Why I Love It and How I Use
|
||||
It](https://www.nateliason.com/blog/roam)
|
||||
|
||||
The goal of the project is to implement core features of Roam around
|
||||
Org-mode, and eventually introduce features enabled by the Emacs
|
||||
ecosystem.
|
||||
|
||||
## Why build Org-Roam?
|
||||
|
||||
With Org-roam, you:
|
||||
|
||||
1. Never have to leave Emacs.
|
||||
2. Can leverage all the powerful features of Org-mode: LaTeX, tables,
|
||||
and the whole to-do ecosystem (org-agenda etc.)
|
||||
3. Be in full control your second brain, and access it offline. Never
|
||||
share your data with anyone
|
||||
|
||||
There are several packages that are similar to Org-roam, see the
|
||||
[Comparison](comparison.md) page for a detailed comparison.
|
||||
|
||||
## Project Status
|
||||
|
||||
As of February 2020, it is in a very early stage of development.
|
||||
|
||||
[org-roam-intro-image]: images/org-roam-intro.png
|
||||
[roamresearch]: https://www.roamresearch.com/
|
||||
[org]: https://orgmode.org/
|
@ -1,93 +0,0 @@
|
||||
## Installation
|
||||
|
||||
The recommended method is using [use-package][use-package] and
|
||||
[straight][straight], or a similar package manager.
|
||||
|
||||
```
|
||||
(use-package org-roam
|
||||
:after org
|
||||
:hook
|
||||
(after-init . org-roam-mode)
|
||||
:straight (:host github :repo "jethrokuan/org-roam" :branch "develop")
|
||||
:custom
|
||||
(org-roam-directory "/path/to/org-files/")
|
||||
:bind (:map org-roam-mode-map
|
||||
(("C-c n l" . org-roam)
|
||||
("C-c n f" . org-roam-find-file)
|
||||
("C-c n g" . org-roam-show-graph))
|
||||
:map org-mode-map
|
||||
(("C-c n i" . org-roam-insert))))
|
||||
```
|
||||
|
||||
If not using package.el, you can also clone it into your Emacs
|
||||
directory and add it to your load path:
|
||||
|
||||
```
|
||||
git clone https://github.com/jethrokuan/org-roam/ ~/.emacs.d/elisp/org-roam
|
||||
```
|
||||
|
||||
```
|
||||
(use-package org-roam
|
||||
:after org
|
||||
:load-path "elisp/"
|
||||
:hook
|
||||
(after-init . org-roam-mode)
|
||||
:straight (:host github :repo "jethrokuan/org-roam" :branch "develop")
|
||||
:custom
|
||||
(org-roam-directory "/path/to/org-files/")
|
||||
:bind (:map org-roam-mode-map
|
||||
(("C-c n l" . org-roam)
|
||||
("C-c n f" . org-roam-find-file)
|
||||
("C-c n g" . org-roam-show-graph))
|
||||
:map org-mode-map
|
||||
(("C-c n i" . org-roam-insert))))
|
||||
```
|
||||
|
||||
Or without use-package:
|
||||
|
||||
```
|
||||
(add-to-list 'load-path "./elisp")
|
||||
(require 'org-roam)
|
||||
```
|
||||
|
||||
There are a number of important configuration options, that greatly
|
||||
affect the Roam workflow. Do look through them at the
|
||||
[Configuration](configuration.md) page.
|
||||
|
||||
[use-package]: https://github.com/jwiegley/use-package
|
||||
[straight]: https://github.com/raxod502/straight.el
|
||||
|
||||
## Spacemacs
|
||||
If you are using Spacemacs, you can easily install org-roam by creating a simple layer that wraps org-roam. Paste the following into a new file `/.emacs.d/private/org-roam/packages.el`.
|
||||
```
|
||||
(defconst org-roam-packages
|
||||
'((org-roam :location
|
||||
(recipe :fetcher github :repo "jethrokuan/org-roam" :branch "develop"))))
|
||||
|
||||
(defun org-roam/init-org-roam ()
|
||||
(use-package org-roam
|
||||
:after org
|
||||
:hook
|
||||
(after-init . org-roam-mode)
|
||||
:custom
|
||||
(org-roam-directory "/path/to/org-files/")
|
||||
:init
|
||||
(progn
|
||||
(spacemacs/declare-prefix "ar" "org-roam")
|
||||
(spacemacs/set-leader-keys
|
||||
"arl" 'org-roam
|
||||
"art" 'org-roam-today
|
||||
"arf" 'org-roam-find-file
|
||||
"arg" 'org-roam-show-graph)
|
||||
|
||||
(spacemacs/declare-prefix-for-mode 'org-mode "mr" "org-roam")
|
||||
(spacemacs/set-leader-keys-for-major-mode 'org-mode
|
||||
"rl" 'org-roam
|
||||
"rt" 'org-roam-today
|
||||
"rb" 'org-roam-switch-to-buffer
|
||||
"rf" 'org-roam-find-file
|
||||
"ri" 'org-roam-insert
|
||||
"rg" 'org-roam-show-graph))))
|
||||
```
|
||||
|
||||
Next, append `org-roam` to the `dotspacemacs-configuration-layers` list in your `.spacemacs` configuration file. Reload (`SPC f e R`) or restart Emacs to load `org-roam`. It's functions are available under the prefix `SPC a r` and `, r` when visiting an org-mode buffer.
|
@ -1,20 +0,0 @@
|
||||
## Recommended Books
|
||||
- [How to Take Smart Notes][1]
|
||||
|
||||
## Articles
|
||||
- [How to Take Smart Notes in Org-mode - Jethro Kuan][7]
|
||||
- [The Zettelkasten Method - LessWrong 2.0][3]
|
||||
- [Building a second brain in Roam][4]
|
||||
- [Roam: Why I Love It and How I Use It][5]
|
||||
- [Adam Keesling's Twitter Thread][6]
|
||||
|
||||
## What to Do With Your Notes
|
||||
- [How to Use Roam to Outline a New Article in Under 20 Minutes][2]
|
||||
|
||||
[1]: https://www.goodreads.com/book/show/34507927-how-to-take-smart-notes?ac=1&from_search=true&qid=6L8iEE1FIA&rank=1
|
||||
[2]: https://www.youtube.com/watch?v=RvWic15iXjk
|
||||
[3]: https://www.lesswrong.com/posts/NfdHG6oHBJ8Qxc26s/the-zettelkasten-method-1
|
||||
[4]: https://reddit.com/r/RoamResearch/comments/eho7de/building_a_second_brain_in_roamand_why_you_might
|
||||
[5]: https://www.nateliason.com/blog/roam
|
||||
[6]: https://twitter.com/adam_keesling/status/1196864424725774336?s=20
|
||||
[7]: https://blog.jethro.dev/posts/how_to_take_smart_notes_org/
|
974
doc/org-roam.org
Normal file
974
doc/org-roam.org
Normal file
@ -0,0 +1,974 @@
|
||||
#+TITLE: Org-roam User Manual
|
||||
:PREAMBLE:
|
||||
#+AUTHOR: Jethro Kuan
|
||||
#+EMAIL: jethrokuan95@gmail.com
|
||||
#+DATE: 2020-2020
|
||||
#+LANGUAGE: en
|
||||
|
||||
#+TEXINFO_DIR_CATEGORY: Emacs
|
||||
#+TEXINFO_DIR_TITLE: Org-roam: (org-roam).
|
||||
#+TEXINFO_DIR_DESC: Rudimentary Roam Replica for Emacs.
|
||||
#+SUBTITLE: for version 1.1.1
|
||||
|
||||
#+OPTIONS: H:4 num:3 toc:2 creator:t
|
||||
#+PROPERTY: header-args :eval never
|
||||
#+TEXINFO: @noindent
|
||||
|
||||
This manual is for Org-roam version 1.1.1.
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||
|
||||
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
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This document 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.
|
||||
#+END_QUOTE
|
||||
|
||||
:END:
|
||||
|
||||
* Introduction
|
||||
|
||||
Org-roam is a [[https://roamresearch.com/][Roam Research]] replica built around the
|
||||
all-powerful [[https://orgmode.org/][Org-mode]].
|
||||
|
||||
Org-roam is a solution for effortless non-hierarchical note-taking
|
||||
with Org-mode. With Org-roam, notes flow naturally, making note-taking
|
||||
fun and easy. Org-roam should also work as a plug-and-play solution
|
||||
for anyone already using Org-mode for their personal wiki.
|
||||
|
||||
To understand more about Roam, a collection of links are available in
|
||||
[[*Note-taking Workflows][Note-taking Workflows]].
|
||||
|
||||
Org-roam aims to implement the core features of Roam, leveraging the
|
||||
mature ecosystem around Org-mode where possible. Eventually, we hope
|
||||
to further introduce features enabled by the Emacs ecosystem.
|
||||
|
||||
Org-roam provides several benefits over other tooling:
|
||||
|
||||
- Privacy and Security :: Edit your personal wiki completely offline, entirely in your control. Encrypt your notes with GPG.
|
||||
- Longevity of Plain Text :: Unlike web solutions like Roam research, the notes are first and foremost plain Org-mode files -- Org-roam simply builds up an auxilliary database to give the personal wiki superpowers. Having your notes in plain-text is crucial for the longevity of your wiki. Never have to worry about proprietary web solutions being taken down. Edit your plain-text notes in notepad if all other editors cease to exist
|
||||
- Free and Open Source :: Org-roam is free and open-source, which means that if you feel unhappy with any part of Org-roam, you may choose to extend Org-roam, or open a PR.
|
||||
- Leverages the Org-mode ecosystem :: Over the years, Emacs and Org-mode has developed into a mature system for plain-text organization. Building upon Org-mode already puts Org-roam light-years ahead of many other solutions.
|
||||
- Built on Emacs :: Emacs is also a fantastic interface for editing text, and we can inherit many of the powerful text-navigation and editing packages available to Emacs.
|
||||
* Installation
|
||||
** _ :ignore:
|
||||
Org-roam can be installed using Emacs' package manager or manually from its development repository.
|
||||
|
||||
** Installing from MELPA
|
||||
|
||||
Org-roam is available from Melpa and Melpa-Stable. If you haven't used Emacs' package manager before, you may familiarize yourself with it by reading the documentation in the Emacs manual, see info:emacs#Packages. Then, add one of the archives to =package-archives=:
|
||||
|
||||
- To use Melpa:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(require 'package)
|
||||
(add-to-list 'package-archives
|
||||
'("melpa" . "http://melpa.org/packages/") t)
|
||||
#+END_SRC
|
||||
|
||||
- To use Melpa-Stable:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(require 'package)
|
||||
(add-to-list 'package-archives
|
||||
'("melpa-stable" . "http://stable.melpa.org/packages/") 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
|
||||
using:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
M-x package-install RET org-roam RET
|
||||
#+END_EXAMPLE
|
||||
|
||||
Now see [[*Post-Installation Tasks][Post-Installation Tasks]].
|
||||
|
||||
** TODO Installing from the Git Repository
|
||||
|
||||
** TODO Post-Installation Tasks
|
||||
|
||||
* Getting Started
|
||||
|
||||
This short tutorial describes the essential commands used in Org-roam, to help
|
||||
you get started.
|
||||
|
||||
First, it is important to understand how Org-roam was designed. Org-roam was
|
||||
built to support a workflow that was not possible with vanilla Org-mode. This
|
||||
flow is modelled after the [[https://zettelkasten.de/][Zettelkasten Method]], and many of [[https://roamresearch.com][Roam Research's]]
|
||||
workflows. Org-roam does not magically make note-taking better -- this often
|
||||
requires a radical change in your current note-taking workflow. To understand
|
||||
more about the methods and madness, see [[*Note-taking Workflows][Note-taking Workflows]].
|
||||
|
||||
To begin using Org-roam, one should set the =org-roam-directory= to the directory
|
||||
containing your notes. For this tutorial, create an empty directory, and set the
|
||||
=org-roam-directory=:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(make-directory "~/org-roam")
|
||||
(setq org-roam-directory "~/org-roam")
|
||||
#+END_SRC
|
||||
|
||||
We encourage using a flat hierarchy for storing notes, but some prefer using
|
||||
folders for storing specific kinds of notes (e.g. websites, papers). This is
|
||||
fine; Org-roam searches recursively within =org-roam-directory= for any notes.
|
||||
Instead of relying on the file hierarchy for any form of categorization, we
|
||||
solely rely on links between files to establish connections between notes.
|
||||
|
||||
Next, we need to enable the global minor mode =org-roam-mode=. This sets up Emacs
|
||||
with several hooks, builds a cache and keeps it consistent. We recommend
|
||||
starting =org-roam-mode= on startup:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-hook 'after-init-hook 'org-roam-mode)
|
||||
#+END_SRC
|
||||
|
||||
To build the cache manually, one can run =M-x org-roam-db-build-cache=. The cache
|
||||
is a sqlite database named =org-roam.db=, which defaults to residing in the root
|
||||
=org-roam-directory=. Cache builds may take a while the first time, but is often
|
||||
instantaneous in subsequent runs.
|
||||
|
||||
Let us now create our first note. Call =M-x org-roam-find-file=. This shows a list
|
||||
of titles for notes that reside in =org-roam-directory=. It should show nothing
|
||||
right now, since there are no notes in the directory. Entering the title of the
|
||||
note you wish to create, and pressing =RET= should begin the note creation
|
||||
process. This process uses =org-capture='s templating system, and can be freely
|
||||
customized (see [[*The Templating System][The Templating System]]). Using the default template, pressing =C-c
|
||||
C-c= finishes the note capture. Running =M-x org-roam-find-file= again should show
|
||||
the note you have created, and selecting that entry will bring you to that note.
|
||||
|
||||
The crux of Org-roam is making it easy to create notes, and link them together.
|
||||
To link notes together, we call =M-x org-roam-insert=. This brings up a prompt
|
||||
with a list of title for existing notes. Selecting an existing entry will create
|
||||
and insert a link to the current file. Entering a non-existent title will create
|
||||
a new note with that title. Good usage of Org-roam requires liberally linking
|
||||
files: this facilitates building up a dense knowledge graph of inter-connected
|
||||
notes.
|
||||
|
||||
Org-roam provides an interface to view backlinks. It shows backlinks for the
|
||||
currently active Org-roam note, along with some surrounding context. To toggle
|
||||
the visibility of this buffer, call =M-x org-roam=.
|
||||
|
||||
For a visual representation of the notes and their connections, Org-roam also
|
||||
provides graphing capabilities, using Graphviz. It generates graphs with notes
|
||||
as nodes, and links between them as edges. The generated graph can be used to
|
||||
navigate to the files, but this requires some additional setup (see [[*Roam Protocol][Roam
|
||||
Protocol]]).
|
||||
|
||||
* Anatomy of an Org-roam File
|
||||
|
||||
The bulk of Org-roam's functionality is built on top of vanilla
|
||||
Org-mode. However, to support additional functionality, Org-roam adds
|
||||
several Org-roam-specific keywords. These functionality are not crucial
|
||||
to effective use of Org-roam.
|
||||
|
||||
** Titles
|
||||
|
||||
To easily find a note, a title needs to be prescribed to a note. A note can have
|
||||
many titles: this allows a note to be referred to by different names, which is
|
||||
especially useful for topics or concepts with acronyms. For example, for a note
|
||||
like "World War 2", it may be desirable to also refer to it using the acronym
|
||||
"WWII".
|
||||
|
||||
Org-roam calls =org-roam--extract-titles= to extract titles. It uses the
|
||||
variable =org-roam-title-sources=, to control how the titles are extracted. The
|
||||
title extraction methods supported are:
|
||||
|
||||
1. ='title=: This extracts the title using the file =#+TITLE= property
|
||||
2. ='headline=: This extracts the title from the first headline in the Org file
|
||||
3. ='alias=: This extracts a list of titles using the =#ROAM_ALIAS= property.
|
||||
The aliases are space-delimited, and can be multi-worded using quotes
|
||||
|
||||
Take for example the following org file:
|
||||
|
||||
#+BEGIN_SRC org
|
||||
#+TITLE: World War 2
|
||||
#+ROAM_ALIAS: "WWII" "World War II"
|
||||
|
||||
* Headline
|
||||
#+END_SRC
|
||||
|
||||
| Method | Titles |
|
||||
|-------------+--------------------------|
|
||||
| ='title= | '("World War 2") |
|
||||
| ='headline= | '("Headline") |
|
||||
| ='alias= | '("WWII" "World War II") |
|
||||
|
||||
One can freely control which extraction methods to use by customizing
|
||||
=org-roam-title-sources=: see the doc-string for the variable for more
|
||||
information. If all methods of title extraction return no results, the file-name
|
||||
is used in place of the titles for completions.
|
||||
|
||||
If you wish to add your own title extraction method, you may push a symbol
|
||||
='foo= into =org-roam-title-sources=, and define a
|
||||
=org-roam--extract-titles-foo= which accepts no arguments. See
|
||||
=org-roam--extract-titles-title= for an example.
|
||||
|
||||
** Tags
|
||||
|
||||
Tags are used as meta-data for files: they facilitate interactions with notes
|
||||
where titles are insufficient. For example, tags allow for categorization of
|
||||
notes: differentiating between bibliographical and structure notes during interactive commands.
|
||||
|
||||
Org-roam calls =org-roam--extract-tags= to extract tags from files. It uses the
|
||||
variable =org-roam-tag-sources=, to control how tags are extracted. The tag
|
||||
extraction methods supported are:
|
||||
|
||||
1. ='prop=: This extracts tags from the =#+ROAM_TAGS= property. Tags are space delimited, and can be multi-word using double quotes.
|
||||
2. ='all-directories=: All sub-directories relative to =org-roam-directory= are
|
||||
extracted as tags. That is, if a file is located at relative path
|
||||
=foo/bar/file.org=, the file will have tags =foo= and =bar=.
|
||||
3. ='last-directory=: Extracts the last directory relative to
|
||||
=org-roam-directory= as the tag. That is, if a file is located at relative
|
||||
path =foo/bar/file.org=, the file will have tag =bar=.
|
||||
|
||||
By default, only the ='prop= extraction method is enabled. To enable the other
|
||||
extraction methods, you may modify =org-roam-tag-sources=:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-roam-tag-sources '(prop last-directory))
|
||||
#+END_SRC
|
||||
|
||||
If you wish to add your own tag extraction method, you may push a symbol ='foo=
|
||||
into =org-roam-tag-sources=, and define a =org-roam--extract-tags-foo= which
|
||||
accepts the absolute file path as its argument. See
|
||||
=org-roam--extract-tags-prop= for an example.
|
||||
|
||||
** File Refs
|
||||
|
||||
Refs are unique identifiers for files. Each note can only have 1 ref.
|
||||
For example, a note for a website may contain a ref:
|
||||
|
||||
#+BEGIN_SRC org
|
||||
#+TITLE: Google
|
||||
#+ROAM_KEY: https://www.google.com/
|
||||
#+END_SRC
|
||||
|
||||
These keys come in useful for when taking website notes, using the
|
||||
=roam-ref= protocol (see [[*Roam Protocol][Roam Protocol]]).
|
||||
|
||||
Alternatively, add a ref for notes for a specific paper, using its
|
||||
[[https://github.com/jkitchin/org-ref][org-ref]] citation key:
|
||||
|
||||
#+BEGIN_SRC org
|
||||
#+TITLE: Neural Ordinary Differential Equations
|
||||
#+ROAM_KEY: cite:chen18_neural_ordin_differ_equat
|
||||
#+END_SRC
|
||||
|
||||
The backlinks buffer will show any cites of this key: e.g.
|
||||
|
||||
#+CAPTION: org-ref-citelink
|
||||
[[file:images/org-ref-citelink.png]]
|
||||
* The Templating System
|
||||
|
||||
Rather than creating blank files on =org-roam-insert= and =org-roam-find-file=, it
|
||||
may be desirable to prefill the file with templated content. This may include:
|
||||
|
||||
- Time of creation
|
||||
- File it was created from
|
||||
- Clipboard content
|
||||
- Any other data you may want to input manually
|
||||
|
||||
This requires a complex template insertion system. Fortunately, Org ships with a
|
||||
powerful one: =org-capture=. However, org-capture was not designed for such use.
|
||||
Org-roam abuses =org-capture=, extending its syntax. To first understand how
|
||||
org-roam's templating system works, it may be useful to look into basic usage of
|
||||
=org-capture=.
|
||||
|
||||
Org-roam's templates can be customized by modifying the variable
|
||||
=org-roam-capture-templates=.
|
||||
|
||||
** Template Walkthrough
|
||||
|
||||
To demonstrate the additions made to org-capture templates. Here, we walkthrough
|
||||
the default template, reproduced below.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
("d" "default" plain (function org-roam--capture-get-point)
|
||||
"%?"
|
||||
:file-name "%<%Y%m%d%H%M%S>-${slug}"
|
||||
:head "#+TITLE: ${title}\n"
|
||||
:unnarrowed t)
|
||||
#+END_SRC
|
||||
|
||||
1. The template has short key ="d"=. If you have only one template,
|
||||
org-roam automatically chooses this template for you.
|
||||
2. The template is given a description of ="default"=.
|
||||
3. =plain= text is inserted. Other options include Org headings via
|
||||
=entry=.
|
||||
4. =(function org-roam--capture-get-point)= should not be changed.
|
||||
5. ="%?"= is the template inserted on each call to =org-roam-capture--capture=.
|
||||
This template means don't insert any content, but place the cursor
|
||||
here.
|
||||
6. =:file-name= is the file-name template for a new note, if it doesn't
|
||||
yet exist. This creates a file at path that looks like
|
||||
=/path/to/org-roam-directory/20200213032037-foo.org=.
|
||||
7. =:head= contains the initial template to be inserted (once only), at
|
||||
the beginning of the file. Here, the title global attribute is
|
||||
inserted.
|
||||
8. =:unnarrowed t= tells org-capture to show the contents for the whole
|
||||
file, rather than narrowing to just the entry.
|
||||
|
||||
Other options you may want to learn about include =:immediate-finish=.
|
||||
|
||||
** Org-roam Template Expansion
|
||||
|
||||
Org-roam's template definitions also extend org-capture's template syntax, to
|
||||
allow prefilling of strings. We have seen a glimpse of this in [[*Template Walkthrough][Template
|
||||
Walkthrough]].
|
||||
|
||||
In org-roam templates, the =${var}= syntax allows for the expansion of
|
||||
variables, stored in =org-roam-capture--info=. For example, during
|
||||
=org-roam-insert=, the user is prompted for a title. Upon entering a
|
||||
non-existent title, the =title= key in =org-roam-capture--info= is set to the
|
||||
provided title. =${title}= is then expanded into the provided title during the
|
||||
org-capture process. Any variables that do not contain strings, are prompted for
|
||||
values using =completing-read=.
|
||||
|
||||
After doing this expansion, the org-capture's template expansion system
|
||||
is used to fill up the rest of the template. You may read up more on
|
||||
this on [[https://orgmode.org/manual/Template-expansion.html#Template-expansion][org-capture's documentation page]].
|
||||
|
||||
To illustrate this dual expansion process, take for example the template string:
|
||||
="%<%Y%m%d%H%M%S>-${title}"=, with the title ="Foo"=. The template is first
|
||||
expanded into =%<%Y%m%d%H%M%S>-Foo=. Then org-capture expands =%<%Y%m%d%H%M%S>=
|
||||
with timestamp: e.g. =20200213032037-Foo=.
|
||||
|
||||
All of the flexibility afforded by Emacs and Org-mode are available. For
|
||||
example, if you want to encode a UTC timestamp in the filename, you can take
|
||||
advantage of org-mode's =%(EXP)= template expansion to call =format-time-string=
|
||||
directly to provide its third argument to specify UTC.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
("d" "default" plain (function org-roam--capture-get-point)
|
||||
"%?"
|
||||
:file-name "%(format-time-string \"%Y-%m-%d--%H-%M-%SZ--${slug}\" (current-time) t)"
|
||||
:head "#+TITLE: ${title}\n"
|
||||
:unnarrowed t)
|
||||
#+END_SRC
|
||||
|
||||
* Concepts and Configuration
|
||||
The number of configuration options is deliberately kept small, to keep
|
||||
the Org-roam codebase manageable. However, we attempt to accommodate as
|
||||
many usage styles as possible.
|
||||
|
||||
All of Org-roam's customization options can be viewed via
|
||||
=M-x customize-group org-roam=.
|
||||
|
||||
** Directories and Files
|
||||
|
||||
This section concerns the placement and creation of files.
|
||||
|
||||
- Variable: org-roam-directory
|
||||
|
||||
This is the default path to Org-roam files. All Org files, at any level of
|
||||
nesting, are considered part of the Org-roam.
|
||||
|
||||
- Variable: org-roam-db-location
|
||||
|
||||
Location of the Org-roam database. If this is non-nil, the Org-roam sqlite
|
||||
database is saved here.
|
||||
|
||||
It is the user’s responsibility to set this correctly, especially when used
|
||||
with multiple Org-roam instances.
|
||||
|
||||
** The Org-roam Buffer
|
||||
|
||||
The Org-roam buffer displays backlinks for the currently active Org-roam note.
|
||||
|
||||
- User Option: org-roam-buffer
|
||||
|
||||
The name of the org-roam buffer. Defaults to =*org-roam*=.
|
||||
|
||||
- User Option: org-roam-buffer-position
|
||||
|
||||
The position of the Org-roam buffer side window. Valid values are ='left=,
|
||||
='right=, ='top=, ='bottom=.
|
||||
|
||||
- User Option: org-roam-buffer-width
|
||||
|
||||
Width of =org-roam-buffer=. Has an effect only if =org-roam-buffer-position= is
|
||||
='left= or ='right=.
|
||||
|
||||
- User Option: org-roam-buffer-height
|
||||
|
||||
Height of =org-roam-buffer=. Has an effect only if =org-roam-buffer-position= is
|
||||
='top= or ='bottom=.
|
||||
|
||||
- User Option: org-roam-buffer-no-delete-other-windows
|
||||
|
||||
The =no-delete-window= parameter for the org-roam buffer. Setting it to ='t= prevents the window from being deleted when calling =delete-other-windows=.
|
||||
|
||||
** Org-roam Links
|
||||
|
||||
Org-roam links are regular =file:= links in Org-mode. By default, links are
|
||||
inserted with the title as the link description with =org-roam-insert=.
|
||||
|
||||
- User Option: org-roam-link-title-format
|
||||
|
||||
To distinguish between org-roam links and regular links, one may choose to use
|
||||
special indicators for Org-roam links. Defaults to ="%s"=.
|
||||
|
||||
If your version of Org is at least =9.2=, consider styling the link differently,
|
||||
by customizing the =org-roam-link=, and =org-roam-link-current= faces.
|
||||
|
||||
** Org-roam Files
|
||||
|
||||
Org-roam files are created and prefilled using Org-roam's templating
|
||||
system. The templating system is customizable (see [[*The Templating System][The Templating System]]).
|
||||
|
||||
* Navigating Around
|
||||
|
||||
** Index File
|
||||
|
||||
As your collection grows, you might want to create an index where you keep links
|
||||
to your main files.
|
||||
|
||||
In Org-roam, you can define the path to your index file by setting
|
||||
=org-roam-index-file=.
|
||||
|
||||
- Variable: org-roam-index-file
|
||||
|
||||
Path to the Org-roam index file.
|
||||
|
||||
The path can be a string or a function. If it is a string, it should be the
|
||||
path (absolute or relative to =org-roam-directory=) to the index file. If it
|
||||
is is a function, the function should return the path to the index file.
|
||||
Otherwise, the index is assumed to be a note in =org-roam-index= whose
|
||||
title is ="Index"=.
|
||||
|
||||
- Function: org-roam-find-index
|
||||
|
||||
Opens the Index file in the current =org-roam-directory=.
|
||||
|
||||
* Encryption
|
||||
|
||||
One may wish to keep private, encrypted files. Org-roam supports encryption (via
|
||||
GPG), which can be enabled for all new files by setting =org-roam-encrypt-files=
|
||||
to =t=. When enabled, new files are created with the =.org.gpg= extension and
|
||||
decryption are handled automatically by EasyPG.
|
||||
|
||||
Note that Emacs will prompt for a password for encrypted files during
|
||||
cache updates if it requires reading the encrypted file. To reduce the
|
||||
number of password prompts, you may wish to cache the password.
|
||||
|
||||
- Variable: org-roam-encrypt-files
|
||||
|
||||
Whether to encrypt new files. If true, create files with .org.gpg extension.
|
||||
|
||||
* Graphing
|
||||
|
||||
Org-roam provides graphing capabilities to explore interconnections between
|
||||
notes. This is done by performing SQL queries and generating images using
|
||||
[[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*Roam Protocol][Roam Protocol]].
|
||||
|
||||
The entry point to graph creation is =org-roam-graph=.
|
||||
|
||||
- Function: org-roam-graph & optional arg file node-query
|
||||
|
||||
Build and possibly display a graph for FILE from NODE-QUERY.
|
||||
If FILE is nil, default to current buffer’s file name.
|
||||
ARG may be any of the following values:
|
||||
|
||||
- =nil= show the graph.
|
||||
- =C-u= show the graph for FILE.
|
||||
- =C-u N= show the graph for FILE limiting nodes to N steps.
|
||||
- =C-u C-u= build the graph.
|
||||
- =C-u -= build the graph for FILE.
|
||||
- =C-u -N= build the graph for FILE limiting nodes to N steps.
|
||||
|
||||
- User Option: org-roam-graph-executable
|
||||
|
||||
Path to the graphing executable (in this case, Graphviz). Set this if Org-roam is unable to find the Graphviz executable on your system.
|
||||
|
||||
You may also choose to use =neato= in place of =dot=, which generates a more
|
||||
compact graph layout.
|
||||
|
||||
- User Option: org-roam-graph-viewer
|
||||
|
||||
Org-roam defaults to using Firefox (located on PATH) to view the SVG, but you may choose to set it to:
|
||||
|
||||
1. A string, which is a path to the program used
|
||||
2. a function accepting a single argument: the graph file path.
|
||||
|
||||
=nil= uses =view-file= to view the graph.
|
||||
|
||||
** Graph Options
|
||||
|
||||
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 for customizable options.
|
||||
|
||||
- User Option: org-roam-graph-extra-config
|
||||
|
||||
Extra options passed to graphviz for the digraph (The "G" attributes).
|
||||
Example: ='=(("rankdir" . "LR"))=
|
||||
|
||||
- User Option: org-roam-graph-node-extra-config
|
||||
|
||||
Extra options for nodes in the graphviz output (The "N" attributes).
|
||||
Example: ='(("color" . "skyblue"))=
|
||||
|
||||
- User Option: org-roam-graph-edge-extra-config
|
||||
|
||||
Extra options for edges in the graphviz output (The "E" attributes).
|
||||
Example: ='(("dir" . "back"))=
|
||||
|
||||
- User Option: org-roam-graph-edge-cites-extra-config
|
||||
|
||||
Extra options for citation edges in the graphviz output.
|
||||
Example: ='(("color" . "red"))=
|
||||
|
||||
** Excluding Nodes and Edges
|
||||
|
||||
One may want to exclude certain files to declutter the graph.
|
||||
|
||||
- User Option: org-roam-graph-exclude-matcher
|
||||
|
||||
Matcher for excluding nodes from the generated graph. Any nodes and links for
|
||||
file paths matching this string is excluded from the graph.
|
||||
|
||||
If value is a string, the string is the only matcher.
|
||||
|
||||
If value is a list, all file paths matching any of the strings
|
||||
are excluded.
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
(setq org-roam-graph-exclude-matcher '("private" "dailies"))
|
||||
#+END_EXAMPLE
|
||||
|
||||
This setting excludes all files whose path contain "private" or "dailies".
|
||||
|
||||
* Org-roam Completion System
|
||||
|
||||
Org-roam offers completion when choosing note titles etc. The completion
|
||||
system is configurable. The default setting,
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-roam-completion-system 'default)
|
||||
#+END_SRC
|
||||
|
||||
uses Emacs' standard =completing-read=. If you prefer
|
||||
[[https://emacs-helm.github.io/helm/][Helm]], use
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-roam-completion-system 'helm)
|
||||
#+END_SRC
|
||||
|
||||
Other options include ='ido=, and ='ivy=.
|
||||
|
||||
* Roam Protocol
|
||||
** _ :ignore:
|
||||
Org-roam extending =org-protocol= with 2 protocols: the =roam-file=
|
||||
and =roam-ref= protocol.
|
||||
|
||||
** Installation
|
||||
|
||||
To enable Org-roam's protocol extensions, you have to add the following to your init file:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(require 'org-roam-protocol)
|
||||
#+END_SRC
|
||||
|
||||
The instructions for setting up =org-protocol== are reproduced below.
|
||||
|
||||
We will also need to create a desktop application for =emacsclient=. The
|
||||
instructions for various platforms are shown below.
|
||||
|
||||
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.
|
||||
|
||||
For MacOS, one solution is to use [[https://github.com/sveinbjornt/Platypus][Platypus]]. Here are the instructions for
|
||||
setting up with Platypus and Chrome:
|
||||
|
||||
1. Install and launch Platypus (with [[https://brew.sh/][Homebrew]]):
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
brew cask install platypus
|
||||
#+END_SRC
|
||||
|
||||
2. Create a script =launch_emacs.sh=:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
#!/usr/bin/env bash
|
||||
/usr/local/bin/emacsclient --no-wait $1
|
||||
#+END_SRC
|
||||
|
||||
3. Create a Platypus app with the following settings:
|
||||
|
||||
#+begin_example
|
||||
| Setting | Value |
|
||||
|--------------------------------+---------------------------|
|
||||
| App Name | "OrgProtocol" |
|
||||
| Script Type | "env" · "/usr/bin/env" |
|
||||
| Script Path | "path/to/launch-emacs.sh" |
|
||||
| Interface | None |
|
||||
| Accept dropped items | true |
|
||||
| Remain running after execution | false |
|
||||
#+end_example
|
||||
|
||||
|
||||
Inside =Settings=:
|
||||
|
||||
#+begin_example
|
||||
| Setting | Value |
|
||||
|--------------------------------+----------------|
|
||||
| Accept dropped files | true |
|
||||
| Register as URI scheme handler | true |
|
||||
| Protocol | "org-protocol" |
|
||||
#+end_example
|
||||
|
||||
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.
|
||||
|
||||
|
||||
** The =roam-file= protocol
|
||||
|
||||
This is a simple protocol that opens the path specified by the =file=
|
||||
key (e.g. =org-protocol://roam-file?file=/tmp/file.org=). This is used
|
||||
in the generated graph.
|
||||
|
||||
** The =roam-ref= Protocol
|
||||
|
||||
This protocol finds or creates a new note with a given =ROAM_KEY= (see [[*Anatomy of an Org-roam File][Anatomy of an Org-roam File]]):
|
||||
|
||||
[[file:images/roam-ref.gif]]
|
||||
|
||||
To use this, create a Firefox bookmarklet as follows:
|
||||
|
||||
#+BEGIN_SRC javascript
|
||||
javascript:location.href =
|
||||
'org-protocol://roam-ref?template=r&ref='
|
||||
+ encodeURIComponent(location.href)
|
||||
+ '&title='
|
||||
+ encodeURIComponent(document.title)
|
||||
#+END_SRC
|
||||
|
||||
or as a keybinding in =qutebrowser=, adding the following to the =autoconfig.yml= file:
|
||||
|
||||
#+BEGIN_SRC yaml
|
||||
settings:
|
||||
bindings.commands:
|
||||
global:
|
||||
normal:
|
||||
gc: open javascript:void(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]]). These templates
|
||||
should contain a =#+ROAM_KEY: ${ref}= in it.
|
||||
|
||||
* Diagnosing and Repairing Files
|
||||
|
||||
Org-roam provides a utility for diagnosing and repairing problematic files via
|
||||
=org-roam-doctor=. By default, =org-roam-doctor= runs the check across all Org-roam
|
||||
files, and this can take some time. To run the check only for the current file,
|
||||
run =C-u M-x org-roam-doctor=.
|
||||
|
||||
- Function: org-roam-doctor &optional this-buffer
|
||||
|
||||
Perform a check on Org-roam files to ensure cleanliness. If THIS-BUFFER, run
|
||||
the check only for the current buffer.
|
||||
|
||||
The checks run are defined in =org-roam-doctor--checkers=. Each checker is an instance of =org-roam-doctor-checker=. To define a checker, use =make-org-roam-doctor-checker=. Here is a sample definition:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(make-org-roam-doctor-checker
|
||||
:name 'org-roam-doctor-broken-links
|
||||
:description "Fix broken links."
|
||||
:actions '(("d" . ("Unlink" . org-roam-doctor--remove-link))
|
||||
("r" . ("Replace link" . org-roam-doctor--replace-link))
|
||||
("R" . ("Replace link (keep label)" . org-roam-doctor--replace-link-keep-label))))
|
||||
#+END_SRC
|
||||
|
||||
The =:name= property is the name of the function run. The function takes in the
|
||||
Org parse tree, and returns a list of =(point error-message)=. =:description= is a
|
||||
short description of what the checker does. =:actions= is an alist containing
|
||||
elements of the form =(char . (prompt . function))=. These actions are defined per
|
||||
checker, to perform autofixes for the errors. For each error detected,
|
||||
=org-roam-doctor= will move the point to the current error, and pop-up a help
|
||||
window displaying the error message, as well as the list of actions that can be
|
||||
taken provided in =:actions=.
|
||||
|
||||
* _ Copying
|
||||
:PROPERTIES:
|
||||
:COPYING: t
|
||||
:END:
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||
|
||||
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 version 3 of the License, or (at your option) any
|
||||
later version.
|
||||
|
||||
This document 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.
|
||||
#+END_QUOTE
|
||||
|
||||
* Appendix
|
||||
** Note-taking Workflows
|
||||
- Books ::
|
||||
- [[https://www.goodreads.com/book/show/34507927-how-to-take-smart-notes][How To Take Smart Notes]]
|
||||
- Articles ::
|
||||
- [[https://www.lesswrong.com/posts/NfdHG6oHBJ8Qxc26s/the-zettelkasten-method-1][The Zettelkasten Method - LessWrong 2.0]]
|
||||
- [[https://reddit.com/r/RoamResearch/comments/eho7de/building_a_second_brain_in_roamand_why_you_might][Building a Second Brain in Roam...And Why You Might Want To : RoamResearch]]
|
||||
- [[https://www.nateliason.com/blog/roam][Roam Research: Why I Love It and How I Use It - Nat Eliason]]
|
||||
- [[https://twitter.com/adam_keesling/status/1196864424725774336?s=20][Adam Keesling's Twitter Thread]]
|
||||
- [[https://blog.jethro.dev/posts/how_to_take_smart_notes_org/][How To Take Smart Notes With Org-mode · Jethro Kuan]]
|
||||
- Threads ::
|
||||
- [[https://news.ycombinator.com/item?id=22473209][Ask HN: How to Take Good Notes]]
|
||||
- Videos ::
|
||||
- [[https://www.youtube.com/watch?v=RvWic15iXjk][How to Use Roam to Outline a New Article in Under 20 Minutes]]
|
||||
** Ecosystem
|
||||
A number of packages work well combined with Org-Roam:
|
||||
|
||||
*** Deft
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: deft
|
||||
:END:
|
||||
|
||||
[[https://jblevins.org/projects/deft/][Deft]] provides a nice interface
|
||||
for browsing and filtering org-roam notes.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package deft
|
||||
:after org
|
||||
:bind
|
||||
("C-c n d" . deft)
|
||||
:custom
|
||||
(deft-recursive t)
|
||||
(deft-use-filter-string-for-filename t)
|
||||
(deft-default-extension "org")
|
||||
(deft-directory "/path/to/org-roam-files/"))
|
||||
#+END_SRC
|
||||
|
||||
If the title of the Org file is not the first line, you might not get
|
||||
nice titles. You may choose to patch this to use =org-roam='s
|
||||
functionality. Here I'm using
|
||||
[[https://github.com/raxod502/el-patch][el-patch]]:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package el-patch
|
||||
:straight (:host github
|
||||
:repo "raxod502/el-patch"
|
||||
:branch "develop"))
|
||||
|
||||
(eval-when-compile
|
||||
(require 'el-patch))
|
||||
|
||||
(use-package deft
|
||||
;; same as above...
|
||||
:config/el-patch
|
||||
(defun deft-parse-title (file contents)
|
||||
"Parse the given FILE and CONTENTS and determine the title.
|
||||
If `deft-use-filename-as-title' is nil, the title is taken to
|
||||
be the first non-empty line of the FILE. Else the base name of the FILE is
|
||||
used as title."
|
||||
(el-patch-swap (if deft-use-filename-as-title
|
||||
(deft-base-filename file)
|
||||
(let ((begin (string-match "^.+$" contents)))
|
||||
(if begin
|
||||
(funcall deft-parse-title-function
|
||||
(substring contents begin (match-end 0))))))
|
||||
(org-roam--get-title-or-slug file))))
|
||||
#+END_SRC
|
||||
|
||||
The Deft interface can slow down quickly when the number of files get
|
||||
huge. [[https://github.com/hasu/notdeft][Notdeft]] is a fork of Deft
|
||||
that uses an external search engine and indexer.
|
||||
|
||||
*** Org-journal
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: org-journal
|
||||
:END:
|
||||
|
||||
[[https://github.com/bastibe/org-journal][Org-journal]] is a more
|
||||
powerful alternative to the simple function =org-roam-dailies-today=. It
|
||||
provides better journaling capabilities, and a nice calendar interface
|
||||
to see all dated entries.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package org-journal
|
||||
:bind
|
||||
("C-c n j" . org-journal-new-entry)
|
||||
:custom
|
||||
(org-journal-date-prefix "#+TITLE: ")
|
||||
(org-journal-file-format "%Y-%m-%d.org")
|
||||
(org-journal-dir "/path/to/org-roam-files/")
|
||||
(org-journal-date-format "%A, %d %B %Y"))
|
||||
#+END_SRC
|
||||
|
||||
*** Note-taking Add-ons
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: note-taking-add-ons
|
||||
:END:
|
||||
|
||||
These are some plugins that make note-taking in Org-mode more enjoyable.
|
||||
|
||||
**** Org-download
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: org-download
|
||||
:END:
|
||||
|
||||
[[https://github.com/abo-abo/org-download][Org-download]] lets you
|
||||
screenshot and yank images from the web into your notes:
|
||||
|
||||
#+CAPTION: org-download
|
||||
[[file:images/org-download.gif]]
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package org-download
|
||||
:after org
|
||||
:bind
|
||||
(:map org-mode-map
|
||||
(("s-Y" . org-download-screenshot)
|
||||
("s-y" . org-download-yank))))
|
||||
#+END_SRC
|
||||
|
||||
**** mathpix.el
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: mathpix.el
|
||||
:END:
|
||||
|
||||
[[https://github.com/jethrokuan/mathpix.el][mathpix.el]] uses
|
||||
[[https://mathpix.com/][Mathpix's]] API to convert clips into latex
|
||||
equations:
|
||||
|
||||
#+CAPTION: mathpix
|
||||
[[file:images/mathpix.gif]]
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package mathpix.el
|
||||
:straight (:host github :repo "jethrokuan/mathpix.el")
|
||||
:custom ((mathpix-app-id "app-id")
|
||||
(mathpix-app-key "app-key"))
|
||||
:bind
|
||||
("C-x m" . mathpix-screenshot))
|
||||
#+END_SRC
|
||||
|
||||
**** Org-noter / Interleave
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: org-noter-interleave
|
||||
:END:
|
||||
|
||||
[[https://github.com/weirdNox/org-noter][Org-noter]] and
|
||||
[[https://github.com/rudolfochrist/interleave][Interleave]] are both
|
||||
projects that allow synchronised annotation of documents (PDF, EPUB
|
||||
etc.) within Org-mode.
|
||||
|
||||
**** Bibliography
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: bibliography
|
||||
:END:
|
||||
|
||||
[[https://github.com/zaeph/org-roam-bibtex][org-roam-bibtex]] offers
|
||||
tight integration between
|
||||
[[https://github.com/jkitchin/org-ref][org-ref]],
|
||||
[[https://github.com/tmalsburg/helm-bibtex][helm-bibtex]] and
|
||||
=org-roam=. This helps you manage your bibliographic notes under
|
||||
=org-roam=.
|
||||
|
||||
**** Spaced Repetition
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: spaced-repetition
|
||||
:END:
|
||||
|
||||
[[https://github.com/l3kn/org-fc/][Org-fc]] is a spaced repetition
|
||||
system that scales well with a large number of files. Other alternatives
|
||||
include
|
||||
[[https://orgmode.org/worg/org-contrib/org-drill.html][org-drill]], and
|
||||
[[https://github.com/abo-abo/pamparam][pamparam]].
|
||||
|
||||
* FAQ
|
||||
** How do I have more than one Org-roam directory?
|
||||
|
||||
Emacs supports directory-local variables, allowing the value of
|
||||
=org-roam-directory= to be different in different directories. It does this by
|
||||
checking for a file named =.dir-locals.el=.
|
||||
|
||||
To add support for multiple directories, override the =org-roam-directory=
|
||||
variable using directory-local variables. This is what =.dir-locals.el= may
|
||||
contain:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
((nil . ((org-roam-directory . "/path/to/here/"))))
|
||||
#+END_SRC
|
||||
|
||||
All files within that directory will be treated as their own separate
|
||||
set of Org-roam files. Remember to run =org-roam-db-build-cache= from a
|
||||
file within that directory, at least once.
|
||||
|
||||
* _ :ignore:
|
||||
# Local Variables:
|
||||
# eval: (refill-mode +1)
|
||||
# before-save-hook: org-make-toc
|
||||
# after-save-hook: (lambda nil (progn (require 'ox-texinfo nil t) (org-texinfo-export-to-info)))
|
||||
# indent-tabs-mode: nil
|
||||
# org-src-preserve-indentation: nil
|
||||
# End:
|
1287
doc/org-roam.texi
Normal file
1287
doc/org-roam.texi
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
mkdocs-material==4.6.2
|
||||
pymdown-extensions==6.3
|
69
doc/tour.md
69
doc/tour.md
@ -1,69 +0,0 @@
|
||||
Org-roam was built to support a workflow that was not possible with
|
||||
vanilla Org-mode. This flow is modelled after the [Zettelkasten
|
||||
method][zettelkasten], and many of [Roam Research][roam]'s workflows.
|
||||
Understanding this flow is crucial! Org-roam doesn't auto-magically
|
||||
make your note-taking better -- it's changing the note-taking workflow
|
||||
that does.
|
||||
|
||||
To understand more the methods and madness, the [Note-Taking
|
||||
Workflow][appendix:ntw] page contains a page of useful references.
|
||||
I've also written [a post][jethro-blog-post] about how I use Org-roam.
|
||||
|
||||
Without further ado, let's begin!
|
||||
|
||||
## Building the Cache
|
||||
|
||||
Assuming you've set `org-roam-directory` appropriately, running `M-x
|
||||
org-roam--build-cache-async` should build up the caches that will
|
||||
allow you to begin using Org-roam. I do this on startup:
|
||||
|
||||
```emacs-lisp
|
||||
(add-hook 'after-init-hook 'org-roam--build-cache-async)
|
||||
```
|
||||
|
||||
## Finding a Note
|
||||
|
||||
`org-roam-find-file` shows you the list of notes you currently have in
|
||||
Org-roam. Selecting the title will bring you to the corresponding
|
||||
note. Entering a title of a note that does not yet exist will create a
|
||||
new note with that title.
|
||||
|
||||

|
||||
|
||||
## Inserting Links
|
||||
|
||||
Within your Org-roam notes, you are encouraged to liberally insert
|
||||
links to existing (or new) Org-roam notes with `org-roam-insert`.
|
||||
Entering a non-existent title will also create a new note with that
|
||||
title.
|
||||
|
||||

|
||||
|
||||
It is crucial for good usage of Org-roam to insert links liberally,
|
||||
where you want them the notes to resurface!
|
||||
|
||||
## The Org-roam Buffer
|
||||
|
||||
All of Org-roam's operations are designed such that the built cache is
|
||||
a consistent view of the inter-connectivity between your notes. The
|
||||
Org-roam buffer shows backlinks: i.e. the files that link to the
|
||||
currently viewed file, along with some surrounding context. The
|
||||
Org-roam buffer will always show the backlinks for the current
|
||||
Org-roam file in view.
|
||||
|
||||

|
||||
|
||||
## Exporting the Graph
|
||||
|
||||
It's also possible to export the links as a graph, using graphviz. The
|
||||
generated graph is navigable in Emacs, but requires some additional
|
||||
setup, which I describe in the [Graph Appendix][appendix:graph-setup]
|
||||
page.
|
||||
|
||||

|
||||
|
||||
[zettelkasten]: https://zettelkasten.de/
|
||||
[appendix:ntw]: notetaking_workflow.md
|
||||
[appendix:graph-setup]: graph_setup.md
|
||||
[roam]: https://www.roamresearch.com/
|
||||
[jethro-blog-post]: https://blog.jethro.dev/posts/how_to_take_smart_notes_org/
|
7
makem.sh
7
makem.sh
@ -155,7 +155,8 @@ function elisp-checkdoc-file {
|
||||
(when makem-checkdoc-errors-p
|
||||
(kill-emacs 1))))
|
||||
|
||||
(setq checkdoc-spellcheck-documentation-flag t)
|
||||
(setq sentence-end-double-space nil)
|
||||
(setq checkdoc-spellcheck-documentation-flag nil)
|
||||
(makem-checkdoc-files-and-exit)
|
||||
EOF
|
||||
echo $file
|
||||
@ -325,7 +326,7 @@ function dirnames {
|
||||
|
||||
function filter-files-exclude-default {
|
||||
# Filter out paths (STDIN) which should be excluded by default.
|
||||
egrep -v "(/\.cask/|-autoloads.el|.dir-locals)"
|
||||
egrep -v "(/\.cask/|-autoloads.el|-macs.el|.dir-locals)"
|
||||
}
|
||||
|
||||
function filter-files-exclude-args {
|
||||
@ -694,7 +695,7 @@ function lint {
|
||||
lint-checkdoc
|
||||
lint-compile
|
||||
lint-declare
|
||||
lint-indent
|
||||
# lint-indent
|
||||
lint-package
|
||||
lint-regexps
|
||||
}
|
||||
|
15
mkdocs.yml
15
mkdocs.yml
@ -1,17 +1,24 @@
|
||||
site_name: "Org-Roam: Roam + Org-Mode = ♥"
|
||||
repo_url: https://github.com/jethrokuan/org-roam/
|
||||
site_name: "Org-roam"
|
||||
repo_url: https://github.com/org-roam/org-roam/
|
||||
edit_uri: edit/master/doc/
|
||||
copyright: "Copyright (C) 2020 Jethro Kuan and contributors"
|
||||
docs_dir: doc
|
||||
extra:
|
||||
social:
|
||||
- type: 'slack'
|
||||
link: 'https://join.slack.com/t/orgroam/shared_invite/zt-clh0g0tx-j8xg1kVxnrWdKt16gmSGPQ'
|
||||
nav:
|
||||
- Home: index.md
|
||||
- A Tour of Org-Roam: tour.md
|
||||
- A Tour of Org-roam: tour.md
|
||||
- Installation: installation.md
|
||||
- Configuration: configuration.md
|
||||
- Anatomy of an Org-roam file: anatomy.md
|
||||
- The Templating System: templating.md
|
||||
- Ecosystem: ecosystem.md
|
||||
- Similar Packages: comparison.md
|
||||
- "Appendix: Note-taking Workflow": notetaking_workflow.md
|
||||
- "Appendix: Graph Setup": graph_setup.md
|
||||
- "Appendix: Roam Protocol": roam_protocol.md
|
||||
- "Appendix: Org Export": org_export.md
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- pymdownx.betterem:
|
||||
|
276
org-roam-buffer.el
Normal file
276
org-roam-buffer.el
Normal file
@ -0,0 +1,276 @@
|
||||
;;; org-roam-buffer.el --- Metadata buffer -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides the org-roam-buffer functionality for org-roam
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
(eval-when-compile (require 'subr-x))
|
||||
(require 'cl-lib)
|
||||
(require 'dash)
|
||||
(require 's)
|
||||
|
||||
(defvar org-roam-directory)
|
||||
(defvar org-link-frame-setup)
|
||||
(defvar org-return-follows-link)
|
||||
(defvar org-roam-backlinks-mode)
|
||||
(defvar org-roam-last-window)
|
||||
(defvar org-ref-cite-types) ;; in org-ref-core.el
|
||||
|
||||
(declare-function org-roam-db--ensure-built "org-roam-db")
|
||||
(declare-function org-roam--extract-ref "org-roam")
|
||||
(declare-function org-roam--get-title-or-slug "org-roam")
|
||||
(declare-function org-roam--get-backlinks "org-roam")
|
||||
(declare-function org-roam-backlinks-mode "org-roam")
|
||||
|
||||
(defcustom org-roam-buffer-position 'right
|
||||
"Position of `org-roam' buffer.
|
||||
Valid values are
|
||||
* left,
|
||||
* right,
|
||||
* top,
|
||||
* bottom."
|
||||
:type '(choice (const left)
|
||||
(const right)
|
||||
(const top)
|
||||
(const bottom))
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-buffer-width 0.33
|
||||
"Width of `org-roam' buffer.
|
||||
Has an effect if and only if `org-roam-buffer-position' is `left' or `right'."
|
||||
:type 'number
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-buffer-height 0.27
|
||||
"Height of `org-roam' buffer.
|
||||
Has an effect if and only if `org-roam-buffer-position' is `top' or `bottom'."
|
||||
:type 'number
|
||||
:group 'org-roam)
|
||||
|
||||
|
||||
(defcustom org-roam-buffer "*org-roam*"
|
||||
"Org-roam buffer name."
|
||||
:type 'string
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-buffer-prepare-hook '(org-roam-buffer--insert-title
|
||||
org-roam-buffer--insert-backlinks
|
||||
org-roam-buffer--insert-citelinks)
|
||||
"Hook run in the `org-roam-buffer' before it is displayed."
|
||||
:type 'hook
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-buffer-no-delete-other-windows nil
|
||||
"The `no-delete-other-windows' parameter of the `org-roam-buffer' window.
|
||||
When non-nil, the window will not be closed when deleting other windows."
|
||||
:type 'boolean
|
||||
:group 'org-roam)
|
||||
|
||||
(defvar org-roam-buffer--current nil
|
||||
"Currently displayed file in `org-roam' buffer.")
|
||||
|
||||
(defun org-roam-buffer--insert-title ()
|
||||
"Insert the org-roam-buffer title."
|
||||
(insert (propertize (org-roam--get-title-or-slug
|
||||
(buffer-file-name org-roam-buffer--current))
|
||||
'font-lock-face
|
||||
'org-document-title)))
|
||||
|
||||
(defun org-roam-buffer--pluralize (string number)
|
||||
"Conditionally pluralize STRING if NUMBER is above 1."
|
||||
(let ((l (pcase number
|
||||
((pred (listp)) (length number))
|
||||
((pred (integerp)) number)
|
||||
(wrong-type (signal 'wrong-type-argument
|
||||
`((listp integerp)
|
||||
,wrong-type))))))
|
||||
(concat string (when (> l 1) "s"))))
|
||||
|
||||
(defun org-roam-buffer--insert-citelinks ()
|
||||
"Insert citation backlinks for the current buffer."
|
||||
(if-let* ((ref (with-temp-buffer
|
||||
(insert-buffer-substring org-roam-buffer--current)
|
||||
(org-roam--extract-ref)))
|
||||
(org-ref-p (require 'org-ref nil t)) ; Ensure that org-ref is present
|
||||
(key-backlinks (org-roam--get-backlinks (cdr ref)))
|
||||
(grouped-backlinks (--group-by (nth 0 it) key-backlinks)))
|
||||
(progn
|
||||
(insert (let ((l (length key-backlinks)))
|
||||
(format "\n\n* %d %s\n"
|
||||
l (org-roam-buffer--pluralize "Cite backlink" l))))
|
||||
(dolist (group grouped-backlinks)
|
||||
(let ((file-from (car group))
|
||||
(bls (cdr group)))
|
||||
(insert (format "** [[file:%s][%s]]\n"
|
||||
file-from
|
||||
(org-roam--get-title-or-slug file-from)))
|
||||
(dolist (backlink bls)
|
||||
(pcase-let ((`(,file-from _ ,props) backlink))
|
||||
(insert (propertize
|
||||
(s-trim (s-replace "\n" " "
|
||||
(plist-get props :content)))
|
||||
'help-echo "mouse-1: visit backlinked note"
|
||||
'file-from file-from
|
||||
'file-from-point (plist-get props :point)))
|
||||
(insert "\n\n"))))))
|
||||
(insert "\n\n* No cite backlinks!")))
|
||||
|
||||
(defun org-roam-buffer--insert-backlinks ()
|
||||
"Insert the org-roam-buffer backlinks string for the current buffer."
|
||||
(if-let* ((file-path (buffer-file-name org-roam-buffer--current))
|
||||
(backlinks (org-roam--get-backlinks file-path))
|
||||
(grouped-backlinks (--group-by (nth 0 it) backlinks)))
|
||||
(progn
|
||||
(insert (let ((l (length backlinks)))
|
||||
(format "\n\n* %d %s\n"
|
||||
l (org-roam-buffer--pluralize "Backlink" l))))
|
||||
(dolist (group grouped-backlinks)
|
||||
(let ((file-from (car group))
|
||||
(bls (cdr group)))
|
||||
(insert (format "** [[file:%s][%s]]\n"
|
||||
file-from
|
||||
(org-roam--get-title-or-slug file-from)))
|
||||
(dolist (backlink bls)
|
||||
(pcase-let ((`(,file-from _ ,props) backlink))
|
||||
(insert (propertize
|
||||
(s-trim (s-replace "\n" " "
|
||||
(plist-get props :content)))
|
||||
'help-echo "mouse-1: visit backlinked note"
|
||||
'file-from file-from
|
||||
'file-from-point (plist-get props :point)))
|
||||
(insert "\n\n"))))))
|
||||
(insert "\n\n* No backlinks!")))
|
||||
|
||||
(defun org-roam-buffer-update ()
|
||||
"Update the `org-roam-buffer'."
|
||||
(org-roam-db--ensure-built)
|
||||
(let* ((source-org-roam-directory org-roam-directory))
|
||||
(with-current-buffer org-roam-buffer
|
||||
;; When dir-locals.el is used to override org-roam-directory,
|
||||
;; org-roam-buffer should have a different local org-roam-directory and
|
||||
;; default-directory, as relative links are relative from the overridden
|
||||
;; org-roam-directory.
|
||||
(setq-local org-roam-directory source-org-roam-directory)
|
||||
(setq-local default-directory source-org-roam-directory)
|
||||
;; Locally overwrite the file opening function to re-use the
|
||||
;; last window org-roam was called from
|
||||
(setq-local org-link-frame-setup
|
||||
(cons '(file . org-roam--find-file) org-link-frame-setup))
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(unless (eq major-mode 'org-mode)
|
||||
(org-mode))
|
||||
(unless org-roam-backlinks-mode
|
||||
(org-roam-backlinks-mode))
|
||||
(make-local-variable 'org-return-follows-link)
|
||||
(setq org-return-follows-link t)
|
||||
(run-hooks 'org-roam-buffer-prepare-hook)
|
||||
(read-only-mode 1)))))
|
||||
|
||||
|
||||
(cl-defun org-roam-buffer--update-maybe (&key redisplay)
|
||||
"Reconstructs `org-roam-buffer'.
|
||||
This needs to be quick or infrequent, because this is run at
|
||||
`post-command-hook'. If REDISPLAY, force an update of
|
||||
`org-roam-buffer'."
|
||||
(let ((buffer (window-buffer)))
|
||||
(when (and (or redisplay
|
||||
(not (eq org-roam-buffer--current buffer)))
|
||||
(eq 'visible (org-roam-buffer--visibility))
|
||||
(buffer-local-value 'buffer-file-truename buffer))
|
||||
(setq org-roam-buffer--current buffer)
|
||||
(org-roam-buffer-update))))
|
||||
|
||||
;;;; Toggling the org-roam buffer
|
||||
(define-inline org-roam-buffer--visibility ()
|
||||
"Return whether the current visibility state of the org-roam buffer.
|
||||
Valid states are 'visible, 'exists and 'none."
|
||||
(declare (side-effect-free t))
|
||||
(inline-quote
|
||||
(cond
|
||||
((get-buffer-window org-roam-buffer) 'visible)
|
||||
((get-buffer org-roam-buffer) 'exists)
|
||||
(t 'none))))
|
||||
|
||||
(defun org-roam-buffer--set-width (width)
|
||||
"Set the width of `org-roam-buffer' to `WIDTH'."
|
||||
(unless (one-window-p)
|
||||
(let ((window-size-fixed)
|
||||
(w (max width window-min-width)))
|
||||
(cond
|
||||
((> (window-width) w)
|
||||
(shrink-window-horizontally (- (window-width) w)))
|
||||
((< (window-width) w)
|
||||
(enlarge-window-horizontally (- w (window-width))))))))
|
||||
|
||||
(defun org-roam-buffer--set-height (height)
|
||||
"Set the height of `org-roam-buffer' to `HEIGHT'."
|
||||
(unless (one-window-p)
|
||||
(let ((window-size-fixed)
|
||||
(h (max height window-min-height)))
|
||||
(cond
|
||||
((> (window-height) h)
|
||||
(shrink-window (- (window-height) h)))
|
||||
((< (window-height) h)
|
||||
(enlarge-window (- h (window-height))))))))
|
||||
|
||||
(defun org-roam-buffer--get-create ()
|
||||
"Set up the `org-roam' buffer at `org-roam-buffer-position'."
|
||||
(let ((window (get-buffer-window))
|
||||
(position
|
||||
(if (member org-roam-buffer-position '(right left top bottom))
|
||||
org-roam-buffer-position
|
||||
(let ((text-quoting-style 'grave))
|
||||
(lwarn '(org-roam) :error
|
||||
"Invalid org-roam-buffer-position: %s. Defaulting to \\='right"
|
||||
org-roam-buffer-position))
|
||||
'right)))
|
||||
(-> (get-buffer-create org-roam-buffer)
|
||||
(display-buffer-in-side-window
|
||||
`((side . ,position)
|
||||
(window-parameters . ((no-delete-other-windows . ,org-roam-buffer-no-delete-other-windows)))))
|
||||
(select-window))
|
||||
(pcase position
|
||||
((or 'right 'left)
|
||||
(org-roam-buffer--set-width (round (* (frame-width) org-roam-buffer-width))))
|
||||
((or 'top 'bottom)
|
||||
(org-roam-buffer--set-height (round (* (frame-height) org-roam-buffer-height)))))
|
||||
(select-window window)))
|
||||
|
||||
(defun org-roam-buffer-toggle-display ()
|
||||
"Toggle display of the `org-roam-buffer'."
|
||||
(interactive)
|
||||
(setq org-roam-last-window (get-buffer-window))
|
||||
(pcase (org-roam-buffer--visibility)
|
||||
('visible (delete-window (get-buffer-window org-roam-buffer)))
|
||||
((or 'exists 'none) (org-roam-buffer--get-create))))
|
||||
|
||||
(provide 'org-roam-buffer)
|
||||
|
||||
;;; org-roam-buffer.el ends here
|
352
org-roam-capture.el
Normal file
352
org-roam-capture.el
Normal file
@ -0,0 +1,352 @@
|
||||
;;; org-roam-capture.el --- Capture functionality -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides capture functionality for org-roam
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
(require 'org-capture)
|
||||
(require 'dash)
|
||||
(require 's)
|
||||
(require 'cl-lib)
|
||||
|
||||
;; Declarations
|
||||
(defvar org-roam-encrypt-files)
|
||||
(defvar org-roam-directory)
|
||||
(declare-function org-roam--get-title-path-completions "org-roam")
|
||||
(declare-function org-roam--get-ref-path-completions "org-roam")
|
||||
(declare-function org-roam--file-path-from-id "org-roam")
|
||||
(declare-function org-roam--format-link "org-roam")
|
||||
(declare-function org-roam--title-to-slug "org-roam")
|
||||
(declare-function org-roam-completion--completing-read "org-roam-completion")
|
||||
|
||||
(defvar org-roam-capture--file-name-default "%<%Y%m%d%H%M%S>"
|
||||
"The default file name format for Org-roam templates.")
|
||||
|
||||
(defvar org-roam-capture--header-default "#+TITLE: ${title}\n"
|
||||
"The default capture header for Org-roam templates.")
|
||||
|
||||
(defvar org-roam-capture--file-path nil
|
||||
"The file path for the Org-roam capture.
|
||||
This variable is set during the Org-roam capture process.")
|
||||
|
||||
(defvar org-roam-capture--info nil
|
||||
"An alist of additional information passed to the Org-roam template.
|
||||
This variable is populated dynamically, and is only non-nil
|
||||
during the Org-roam capture process.")
|
||||
|
||||
(defvar org-roam-capture--context nil
|
||||
"A symbol, that reflects the context for obtaining the exact point in a file.
|
||||
This variable is populated dynamically, and is only active during
|
||||
an Org-roam capture process.
|
||||
|
||||
The `title' context is used in `org-roam-insert' and
|
||||
`org-roam-find-file', where the capture process is triggered upon
|
||||
trying to create a new file without that `title'.
|
||||
|
||||
The `ref' context is used by `org-roam-protocol', where the
|
||||
capture process is triggered upon trying to find or create a new
|
||||
note with the given `ref'.")
|
||||
|
||||
(defvar org-roam-capture-additional-template-props nil
|
||||
"Additional props to be added to the Org-roam template.")
|
||||
|
||||
(defconst org-roam-capture--template-keywords '(:file-name :head)
|
||||
"Keywords used in `org-roam-capture-templates' specific to Org-roam.")
|
||||
|
||||
(defvar org-roam-capture-templates
|
||||
'(("d" "default" plain (function org-roam-capture--get-point)
|
||||
"%?"
|
||||
:file-name "%<%Y%m%d%H%M%S>-${slug}"
|
||||
:head "#+TITLE: ${title}\n"
|
||||
:unnarrowed t))
|
||||
"Capture templates for Org-roam.
|
||||
The capture templates are an extension of
|
||||
`org-capture-templates', and the documentation there also
|
||||
applies.
|
||||
|
||||
`org-capture-templates' are extended in 3 ways:
|
||||
|
||||
1. Template expansion capabilities are extended with additional custom syntax.
|
||||
See `org-roam-capture--fill-template' for more details.
|
||||
|
||||
2. The `:file-name' key is added, which expands to the file-name
|
||||
of the note if it creates a new file. This file-name is
|
||||
relative to `org-roam-directory', and is without the
|
||||
file-extension.
|
||||
|
||||
3. The `:head' key is added, which contains the template that is
|
||||
inserted on initial creation (added only once). This is where
|
||||
insertion of any note metadata should go.")
|
||||
|
||||
(defvar org-roam-capture-ref-templates
|
||||
'(("r" "ref" plain (function org-roam-capture--get-point)
|
||||
""
|
||||
:file-name "${slug}"
|
||||
:head "#+TITLE: ${title}
|
||||
#+ROAM_KEY: ${ref}\n"
|
||||
:unnarrowed t))
|
||||
"The Org-roam templates used during a capture from the roam-ref protocol.
|
||||
Details on how to specify for the template is given in `org-roam-capture-templates'.")
|
||||
|
||||
(defun org-roam-capture--get (keyword)
|
||||
"Gets the value for KEYWORD from the `org-roam-capture-template'."
|
||||
(plist-get (plist-get org-capture-plist :org-roam) keyword))
|
||||
|
||||
(defun org-roam-capture--put (&rest stuff)
|
||||
"Puts properties from STUFF into the `org-roam-capture-template'."
|
||||
(let ((p (plist-get org-capture-plist :org-roam)))
|
||||
(while stuff
|
||||
(setq p (plist-put p
|
||||
(pop stuff) (pop stuff))))
|
||||
(setq org-capture-plist
|
||||
(plist-put org-capture-plist :org-roam p))))
|
||||
|
||||
(defun org-roam-capture--in-process-p ()
|
||||
"Return non-nil if a `org-roam-capture' buffer exists."
|
||||
(cl-some (lambda (buffer)
|
||||
(and (eq (buffer-local-value 'major-mode buffer)
|
||||
'org-mode)
|
||||
(plist-get (buffer-local-value 'org-capture-current-plist buffer)
|
||||
:org-roam)))
|
||||
(buffer-list)))
|
||||
|
||||
(defun org-roam-capture--fill-template (str &optional info)
|
||||
"Expands the template STR, returning the string.
|
||||
This is an extension of org-capture's template expansion.
|
||||
|
||||
First, it expands ${var} occurrences in STR, using the INFO alist.
|
||||
If there is a ${var} with no matching var in the alist, the value
|
||||
of var is prompted for via `completing-read'.
|
||||
|
||||
Next, it expands the remaining template string using
|
||||
`org-capture-fill-template'."
|
||||
(-> str
|
||||
(s-format (lambda (key)
|
||||
(or (s--aget info key)
|
||||
(completing-read (format "%s: " key ) nil))) nil)
|
||||
(org-capture-fill-template)))
|
||||
|
||||
(defun org-roam-capture--insert-link-h ()
|
||||
"Insert the link into the original buffer, after the capture process is done.
|
||||
This is added as a hook to `org-capture-after-finalize-hook'."
|
||||
(when (and (not org-note-abort)
|
||||
(eq (org-roam-capture--get :capture-fn)
|
||||
'org-roam-insert))
|
||||
(when-let ((region (org-roam-capture--get :region))) ;; Remove previously selected text.
|
||||
(delete-region (car region) (cdr region)))
|
||||
(insert (org-roam--format-link (org-roam-capture--get :file-path)
|
||||
(org-roam-capture--get :link-description))))
|
||||
(remove-hook 'org-capture-after-finalize-hook #'org-roam-capture--insert-link-h))
|
||||
|
||||
(defun org-roam-capture--save-file-maybe-h ()
|
||||
"Save the file conditionally.
|
||||
The file is saved if the original value of :no-save is not t and
|
||||
`org-note-abort' is not t. It is added to
|
||||
`org-capture-after-finalize-hook'."
|
||||
(cond
|
||||
((and (org-roam-capture--get :new-file)
|
||||
org-note-abort)
|
||||
(with-current-buffer (org-capture-get :buffer)
|
||||
(set-buffer-modified-p nil)
|
||||
(kill-buffer)))
|
||||
((and (not (org-roam-capture--get :orig-no-save))
|
||||
(not org-note-abort))
|
||||
(with-current-buffer (org-capture-get :buffer)
|
||||
(save-buffer))))
|
||||
(remove-hook 'org-capture-after-finalize-hook #'org-roam-capture--save-file-maybe-h))
|
||||
|
||||
(defun org-roam-capture--new-file ()
|
||||
"Return the path to the new file during an Org-roam capture.
|
||||
|
||||
This function reads the file-name attribute of the currently
|
||||
active Org-roam template.
|
||||
|
||||
If the file path already exists, it throw an error.
|
||||
|
||||
Else, to insert the header content in the file, `org-capture'
|
||||
prepends the `:head' property of the Org-roam capture template.
|
||||
|
||||
To prevent the creation of a new file if the capture process is
|
||||
aborted, we do the following:
|
||||
|
||||
1. Save the original value of the capture template's :no-save.
|
||||
|
||||
2. Set the capture template's :no-save to t.
|
||||
|
||||
3. Add a function on `org-capture-after-finalize-hook' that saves
|
||||
the file if the original value of :no-save is not t and
|
||||
`org-note-abort' is not t."
|
||||
(let* ((name-templ (or (org-roam-capture--get :file-name)
|
||||
org-roam-capture--file-name-default))
|
||||
(new-id (s-trim (org-roam-capture--fill-template
|
||||
name-templ
|
||||
org-roam-capture--info)))
|
||||
(file-path (org-roam--file-path-from-id new-id))
|
||||
(roam-head (or (org-roam-capture--get :head)
|
||||
org-roam-capture--header-default))
|
||||
(org-template (org-capture-get :template))
|
||||
(roam-template (concat roam-head org-template)))
|
||||
(unless (file-exists-p file-path)
|
||||
(make-directory (file-name-directory file-path) t)
|
||||
(org-roam-capture--put :orig-no-save (org-capture-get :no-save)
|
||||
:new-file t)
|
||||
(org-capture-put :template
|
||||
;; Fixes org-capture-place-plain-text throwing 'invalid search bound'
|
||||
;; when both :unnarowed t and "%?" is missing from the template string;
|
||||
;; may become unnecessary when the upstream bug is fixed
|
||||
(if (s-contains-p "%?" roam-template)
|
||||
roam-template
|
||||
(concat roam-template "%?"))
|
||||
:type 'plain
|
||||
:no-save t))
|
||||
file-path))
|
||||
|
||||
(defun org-roam-capture--expand-template ()
|
||||
"Expand capture template with information from `org-roam-capture--info'."
|
||||
(org-capture-put :template
|
||||
(s-format (org-capture-get :template)
|
||||
(lambda (key)
|
||||
(or (s--aget org-roam-capture--info key)
|
||||
(when-let ((v (completing-read (format "%s: " key ) nil)))
|
||||
(push (cons key v) org-roam-capture--info)
|
||||
v))) nil)))
|
||||
|
||||
(defun org-roam-capture--get-point ()
|
||||
"Return exact point to file for org-capture-template.
|
||||
The file to use is dependent on the context:
|
||||
|
||||
If the search is via title, it is assumed that the file does not
|
||||
yet exist, and Org-roam will attempt to create new file.
|
||||
|
||||
If the search is via daily notes, 'time will be passed via
|
||||
`org-roam-capture--info'. This is used to alter the default time
|
||||
in `org-capture-templates'.
|
||||
|
||||
If the search is via ref, it is matched against the Org-roam database.
|
||||
If there is no file with that ref, a file with that ref is created.
|
||||
|
||||
This function is used solely in Org-roam's capture templates: see
|
||||
`org-roam-capture-templates'."
|
||||
(let ((file-path (pcase org-roam-capture--context
|
||||
('capture
|
||||
(or (cdr (assoc 'file org-roam-capture--info))
|
||||
(org-roam-capture--new-file)))
|
||||
('title
|
||||
(org-roam-capture--new-file))
|
||||
('dailies
|
||||
(org-capture-put :default-time (cdr (assoc 'time org-roam-capture--info)))
|
||||
(org-roam-capture--new-file))
|
||||
('ref
|
||||
(let ((completions (org-roam--get-ref-path-completions))
|
||||
(ref (cdr (assoc 'ref org-roam-capture--info))))
|
||||
(or (cdr (assoc ref completions))
|
||||
(org-roam-capture--new-file))))
|
||||
(_ (error "Invalid org-roam-capture-context")))))
|
||||
(org-roam-capture--expand-template)
|
||||
(org-roam-capture--put :file-path file-path)
|
||||
(while org-roam-capture-additional-template-props
|
||||
(let ((prop (pop org-roam-capture-additional-template-props))
|
||||
(val (pop org-roam-capture-additional-template-props)))
|
||||
(org-roam-capture--put prop val)))
|
||||
(set-buffer (org-capture-target-buffer file-path))
|
||||
(widen)
|
||||
(goto-char (point-max))))
|
||||
|
||||
(defun org-roam-capture--convert-template (template)
|
||||
"Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax."
|
||||
(pcase template
|
||||
(`(,_key ,_description) template)
|
||||
(`(,key ,description ,type ,target . ,rest)
|
||||
(let ((converted `(,key ,description ,type ,target
|
||||
,(unless (keywordp (car rest)) (pop rest))))
|
||||
org-roam-plist
|
||||
options)
|
||||
(while rest
|
||||
(let* ((key (pop rest))
|
||||
(val (pop rest))
|
||||
(custom (member key org-roam-capture--template-keywords)))
|
||||
(push val (if custom org-roam-plist options))
|
||||
(push key (if custom org-roam-plist options))))
|
||||
(append converted options `(:org-roam ,org-roam-plist))))
|
||||
(_ (user-error "Invalid capture template format: %s" template))))
|
||||
|
||||
(defun org-roam-capture--find-file-h ()
|
||||
"Opens the newly created template file.
|
||||
This is added as a hook to `org-capture-after-finalize-hook'.
|
||||
Run the hooks defined in `org-roam-capture-after-find-file-hook'."
|
||||
(unless org-note-abort
|
||||
(when-let ((file-path (org-roam-capture--get :file-path)))
|
||||
(find-file file-path))
|
||||
(run-hooks 'org-roam-capture-after-find-file-hook))
|
||||
(remove-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h))
|
||||
|
||||
(defcustom org-roam-capture-after-find-file-hook nil
|
||||
"Hook that is run right after an Org-roam capture process is finalized.
|
||||
Suitable for moving point."
|
||||
:group 'org-roam
|
||||
:type 'hook)
|
||||
|
||||
(defun org-roam-capture--capture (&optional goto keys)
|
||||
"Create a new file, and return the path to the edited file.
|
||||
The templates are defined at `org-roam-capture-templates'. The
|
||||
GOTO and KEYS argument have the same functionality as
|
||||
`org-capture'."
|
||||
(let ((org-capture-templates (mapcar #'org-roam-capture--convert-template org-roam-capture-templates))
|
||||
org-capture-templates-contexts)
|
||||
(when (= (length org-capture-templates) 1)
|
||||
(setq keys (caar org-capture-templates)))
|
||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--save-file-maybe-h)
|
||||
(org-capture goto keys)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-capture ()
|
||||
"Launches an `org-capture' process for a new or existing note.
|
||||
This uses the templates defined at `org-roam-capture-templates'."
|
||||
(interactive)
|
||||
(when (org-roam-capture--in-process-p)
|
||||
(user-error "Nested Org-roam capture processes not supported"))
|
||||
(let* ((completions (org-roam--get-title-path-completions))
|
||||
(title-with-keys (org-roam-completion--completing-read "File: "
|
||||
completions))
|
||||
(res (cdr (assoc title-with-keys completions)))
|
||||
(title (or (plist-get res :title) title-with-keys))
|
||||
(file-path (plist-get res :file-path)))
|
||||
(let ((org-roam-capture--info (list (cons 'title title)
|
||||
(cons 'slug (org-roam--title-to-slug title))
|
||||
(cons 'file file-path)))
|
||||
(org-roam-capture--context 'capture))
|
||||
(setq org-roam-capture-additional-template-props (list :capture-fn 'org-roam-capture))
|
||||
(condition-case err
|
||||
(org-roam-capture--capture)
|
||||
(error (user-error "%s. Please adjust `org-roam-capture-templates'"
|
||||
(error-message-string err)))))))
|
||||
|
||||
(provide 'org-roam-capture)
|
||||
|
||||
;;; org-roam-capture.el ends here
|
101
org-roam-compat.el
Normal file
101
org-roam-compat.el
Normal file
@ -0,0 +1,101 @@
|
||||
;;; org-roam-compat.el --- Compatibility Code -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This file contains code needed for backward compatibility with older Emacsen
|
||||
;; and previous versions of org-roam.
|
||||
;;
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
|
||||
;;; Obsolete aliases (remove after next major release)
|
||||
;;;; Functions
|
||||
(define-obsolete-function-alias 'org-roam--capture-get-point 'org-roam-capture--get-point
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-build-cache 'org-roam-db-build-cache
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-sql 'org-roam-db-query
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--get-db 'org-roam-db--get
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--db-clear 'org-roam-db--clear
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-show-graph 'org-roam-graph-show
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--maybe-update-buffer
|
||||
'org-roam-buffer--update-maybe "org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--current-visibility
|
||||
'org-roam-buffer--visibility "org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-update 'org-roam-buffer-update
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--set-width 'org-roam-buffer--set-width
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--set-height 'org-roam-buffer--set-height
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam--set-up-buffer 'org-roam-buffer--get-create
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-today 'org-roam-dailies-today
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-tomorrow 'org-roam-dailies-tomorrow
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-yesterday 'org-roam-dailies-yesterday
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-date 'org-roam-dailies-date
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-graph-show 'org-roam-graph
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-graph-build 'org-roam-graph
|
||||
"org-roam 1.0.0")
|
||||
(define-obsolete-function-alias 'org-roam-find-index 'org-roam-jump-to-index
|
||||
"org-roam 1.1.0")
|
||||
(define-obsolete-function-alias 'org-roam--pluralize 'org-roam-buffer--pluralize
|
||||
"org-roam 1.1.0")
|
||||
(define-obsolete-function-alias 'org-roam--capture 'org-roam-capture--capture
|
||||
"org-roam 1.1.0")
|
||||
(define-obsolete-function-alias 'org-roam-db--maybe-update 'org-roam-db--update-maybe
|
||||
"org-roam 1.1.0")
|
||||
|
||||
;;;; Variables
|
||||
(define-obsolete-variable-alias 'org-roam-graphviz-extra-options
|
||||
'org-roam-graph-extra-config "org-roam 1.0.0")
|
||||
(define-obsolete-variable-alias 'org-roam-grapher-extra-options
|
||||
'org-roam-graph-extra-config "org-roam 1.0.0")
|
||||
(define-obsolete-variable-alias 'org-roam-graph-node-shape
|
||||
'org-roam-graph-node-extra-config "org-roam 1.0.0")
|
||||
(define-obsolete-variable-alias 'org-roam--db-connection
|
||||
'org-roam-db--connection "org-roam 1.0.0")
|
||||
(define-obsolete-variable-alias 'org-roam--current-buffer
|
||||
'org-roam-buffer--current "org-roam 1.0.0")
|
||||
(define-obsolete-variable-alias 'org-roam-date-title-format
|
||||
'org-roam-dailies-capture-templates "org-roam 1.0.0")
|
||||
(define-obsolete-variable-alias 'org-roam-date-filename-format
|
||||
'org-roam-dailies-capture-templates "org-roam 1.0.0")
|
||||
|
||||
(provide 'org-roam-compat)
|
||||
|
||||
;;; org-roam-compat.el ends here
|
111
org-roam-completion.el
Normal file
111
org-roam-completion.el
Normal file
@ -0,0 +1,111 @@
|
||||
;;; org-roam-completion.el --- Completion features -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides completion for org-roam.
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
(require 'cl-lib)
|
||||
(require 's)
|
||||
|
||||
(defvar helm-pattern)
|
||||
(declare-function helm "ext:helm")
|
||||
(declare-function helm-make-source "ext:helm-source" (name class &rest args) t)
|
||||
|
||||
(defcustom org-roam-completion-system 'default
|
||||
"The completion system to be used by `org-roam'."
|
||||
:type '(radio
|
||||
(const :tag "Default" default)
|
||||
(const :tag "Ido" ido)
|
||||
(const :tag "Ivy" ivy)
|
||||
(const :tag "Helm" helm)
|
||||
(function :tag "Custom function"))
|
||||
:group 'org-roam)
|
||||
|
||||
(defun org-roam-completion--helm-candidate-transformer (candidates _source)
|
||||
"Transforms CANDIDATES for Helm-based completing read.
|
||||
SOURCE is not used."
|
||||
(let ((prefix (propertize "[?] "
|
||||
'face 'helm-ff-prefix)))
|
||||
(cons (propertize helm-pattern
|
||||
'display (concat prefix helm-pattern))
|
||||
candidates)))
|
||||
|
||||
(cl-defun org-roam-completion--completing-read (prompt choices &key
|
||||
require-match initial-input
|
||||
action)
|
||||
"Present a PROMPT with CHOICES and optional INITIAL-INPUT.
|
||||
If REQUIRE-MATCH is t, the user must select one of the CHOICES.
|
||||
Return user choice."
|
||||
(let (res)
|
||||
(setq res
|
||||
(cond
|
||||
((eq org-roam-completion-system 'ido)
|
||||
(let ((candidates (mapcar #'car choices)))
|
||||
(ido-completing-read prompt candidates nil require-match initial-input)))
|
||||
((eq org-roam-completion-system 'default)
|
||||
(completing-read prompt choices nil require-match initial-input))
|
||||
((eq org-roam-completion-system 'ivy)
|
||||
(if (fboundp 'ivy-read)
|
||||
(ivy-read prompt choices
|
||||
:initial-input initial-input
|
||||
:require-match require-match
|
||||
:action (prog1 action
|
||||
(setq action nil))
|
||||
:caller 'org-roam--completing-read)
|
||||
(user-error "Please install ivy from \
|
||||
https://github.com/abo-abo/swiper")))
|
||||
((eq org-roam-completion-system 'helm)
|
||||
(unless (and (fboundp 'helm)
|
||||
(fboundp 'helm-make-source))
|
||||
(user-error "Please install helm from \
|
||||
https://github.com/emacs-helm/helm"))
|
||||
(let ((source (helm-make-source prompt 'helm-source-sync
|
||||
:candidates (mapcar #'car choices)
|
||||
:filtered-candidate-transformer
|
||||
(and (not require-match)
|
||||
#'org-roam-completion--helm-candidate-transformer)))
|
||||
(buf (concat "*org-roam "
|
||||
(s-downcase (s-chop-suffix ":" (s-trim prompt)))
|
||||
"*")))
|
||||
(or (helm :sources source
|
||||
:action (if action
|
||||
(prog1 action
|
||||
(setq action nil))
|
||||
#'identity)
|
||||
:prompt prompt
|
||||
:input initial-input
|
||||
:buffer buf)
|
||||
(keyboard-quit))))))
|
||||
(if action
|
||||
(funcall action res)
|
||||
res)))
|
||||
|
||||
(provide 'org-roam-completion)
|
||||
|
||||
;;; org-roam-completion.el ends here
|
84
org-roam-dailies.el
Normal file
84
org-roam-dailies.el
Normal file
@ -0,0 +1,84 @@
|
||||
;;; org-roam-dailies.el --- Daily notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
||||
;;;
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides functionality for creating daily notes. This is a
|
||||
;; concept borrowed from Roam Research.
|
||||
;;
|
||||
;;; Code:
|
||||
;;; Library Requires
|
||||
(require 'org-capture)
|
||||
(require 'org-roam-capture)
|
||||
(require 'org-roam-macs)
|
||||
|
||||
(defvar org-roam-dailies-capture-templates
|
||||
'(("d" "daily" plain (function org-roam-capture--get-point)
|
||||
""
|
||||
:immediate-finish t
|
||||
:file-name "%<%Y-%m-%d>"
|
||||
:head "#+TITLE: %<%Y-%m-%d>"))
|
||||
"Capture templates for daily notes in Org-roam.")
|
||||
|
||||
;; Declarations
|
||||
(declare-function org-roam--file-path-from-id "org-roam")
|
||||
|
||||
(defun org-roam-dailies--file-for-time (time)
|
||||
"Create and find file for TIME."
|
||||
(let ((org-roam-capture-templates org-roam-dailies-capture-templates)
|
||||
(org-roam-capture--info (list (cons 'time time)))
|
||||
(org-roam-capture--context 'dailies))
|
||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h)
|
||||
(org-roam--with-template-error 'org-roam-dailies-capture-templates
|
||||
(org-roam-capture--capture))))
|
||||
|
||||
(defun org-roam-dailies-today ()
|
||||
"Create and find the daily note for today."
|
||||
(interactive)
|
||||
(org-roam-dailies--file-for-time (current-time)))
|
||||
|
||||
(defun org-roam-dailies-tomorrow (n)
|
||||
"Create and find the daily note for tomorrow.
|
||||
With numeric argument N, use N days in the future."
|
||||
(interactive "p")
|
||||
(org-roam-dailies--file-for-time (time-add (* n 86400) (current-time))))
|
||||
|
||||
(defun org-roam-dailies-yesterday (n)
|
||||
"Create and find the file for yesterday.
|
||||
With numeric argument N, use N days in the past."
|
||||
(interactive "p")
|
||||
(org-roam-dailies-tomorrow (- n)))
|
||||
|
||||
(defun org-roam-dailies-date ()
|
||||
"Create the file for any date using the calendar interface."
|
||||
(interactive)
|
||||
(let ((time (org-read-date nil 'to-time nil "Date: ")))
|
||||
(org-roam-dailies--file-for-time time)))
|
||||
|
||||
(provide 'org-roam-dailies)
|
||||
|
||||
;;; org-roam-dailies.el ends here
|
458
org-roam-db.el
Normal file
458
org-roam-db.el
Normal file
@ -0,0 +1,458 @@
|
||||
;;; org-roam-db.el --- Org-roam database API -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library is provides the underlying database api to org-roam
|
||||
;;
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
(eval-when-compile (require 'subr-x))
|
||||
(require 'emacsql)
|
||||
(require 'emacsql-sqlite)
|
||||
(require 'org-roam-macs)
|
||||
|
||||
(defvar org-roam-directory)
|
||||
(defvar org-roam-verbose)
|
||||
|
||||
(declare-function org-roam--org-roam-file-p "org-roam")
|
||||
(declare-function org-roam--extract-titles "org-roam")
|
||||
(declare-function org-roam--extract-ref "org-roam")
|
||||
(declare-function org-roam--extract-tags "org-roam")
|
||||
(declare-function org-roam--extract-links "org-roam")
|
||||
(declare-function org-roam--list-all-files "org-roam")
|
||||
(declare-function org-roam-buffer--update-maybe "org-roam-buffer")
|
||||
|
||||
;;;; Options
|
||||
(defcustom org-roam-db-location nil
|
||||
"Location of the Org-roam database.
|
||||
If this is non-nil, the Org-roam sqlite database is saved here.
|
||||
|
||||
It is the user's responsibility to set this correctly, especially
|
||||
when used with multiple Org-roam instances."
|
||||
:type 'string
|
||||
:group 'org-roam)
|
||||
|
||||
(defconst org-roam-db--version 5)
|
||||
(defconst org-roam-db--sqlite-available-p
|
||||
(with-demoted-errors "Org-roam initialization: %S"
|
||||
(emacsql-sqlite-ensure-binary)
|
||||
t))
|
||||
|
||||
(defvar org-roam-db--connection (make-hash-table :test #'equal)
|
||||
"Database connection to Org-roam database.")
|
||||
|
||||
;;;; Core Functions
|
||||
(defun org-roam-db--get ()
|
||||
"Return the sqlite db file."
|
||||
(interactive "P")
|
||||
(or org-roam-db-location
|
||||
(expand-file-name "org-roam.db" org-roam-directory)))
|
||||
|
||||
(defun org-roam-db--get-connection ()
|
||||
"Return the database connection, if any."
|
||||
(gethash (file-truename org-roam-directory)
|
||||
org-roam-db--connection))
|
||||
|
||||
(defun org-roam-db ()
|
||||
"Entrypoint to the Org-roam sqlite database.
|
||||
Initializes and stores the database, and the database connection.
|
||||
Performs a database upgrade when required."
|
||||
(unless (and (org-roam-db--get-connection)
|
||||
(emacsql-live-p (org-roam-db--get-connection)))
|
||||
(let* ((db-file (org-roam-db--get))
|
||||
(init-db (not (file-exists-p db-file))))
|
||||
(make-directory (file-name-directory db-file) t)
|
||||
(let ((conn (emacsql-sqlite db-file)))
|
||||
(set-process-query-on-exit-flag (emacsql-process conn) nil)
|
||||
(puthash (file-truename org-roam-directory)
|
||||
conn
|
||||
org-roam-db--connection)
|
||||
(when init-db
|
||||
(org-roam-db--init conn))
|
||||
(let* ((version (caar (emacsql conn "PRAGMA user_version")))
|
||||
(version (org-roam-db--update-maybe conn version)))
|
||||
(cond
|
||||
((> version org-roam-db--version)
|
||||
(emacsql-close conn)
|
||||
(user-error
|
||||
"The Org-roam database was created with a newer Org-roam version. "
|
||||
"You need to update the Org-roam package"))
|
||||
((< version org-roam-db--version)
|
||||
(emacsql-close conn)
|
||||
(error "BUG: The Org-roam database scheme changed %s"
|
||||
"and there is no upgrade path")))))))
|
||||
(org-roam-db--get-connection))
|
||||
|
||||
;;;; Entrypoint: (org-roam-db-query)
|
||||
(defun org-roam-db-query (sql &rest args)
|
||||
"Run SQL query on Org-roam database with ARGS.
|
||||
SQL can be either the emacsql vector representation, or a string."
|
||||
(if (stringp sql)
|
||||
(emacsql (org-roam-db) (apply #'format sql args))
|
||||
(apply #'emacsql (org-roam-db) sql args)))
|
||||
|
||||
;;;; Schemata
|
||||
(defconst org-roam-db--table-schemata
|
||||
'((files
|
||||
[(file :unique :primary-key)
|
||||
(hash :not-null)
|
||||
(meta :not-null)])
|
||||
|
||||
(links
|
||||
[(from :not-null)
|
||||
(to :not-null)
|
||||
(type :not-null)
|
||||
(properties :not-null)])
|
||||
|
||||
(tags
|
||||
[(file :unique :primary-key)
|
||||
(tags)])
|
||||
|
||||
(titles
|
||||
[(file :not-null)
|
||||
titles])
|
||||
|
||||
(refs
|
||||
[(ref :unique :not-null)
|
||||
(file :not-null)
|
||||
(type :not-null)])))
|
||||
|
||||
(defun org-roam-db--init (db)
|
||||
"Initialize database DB with the correct schema and user version."
|
||||
(emacsql-with-transaction db
|
||||
(pcase-dolist (`(,table . ,schema) org-roam-db--table-schemata)
|
||||
(emacsql db [:create-table $i1 $S2] table schema))
|
||||
(emacsql db (format "PRAGMA user_version = %s" org-roam-db--version))))
|
||||
|
||||
(defun org-roam-db--update-maybe (db version)
|
||||
"Upgrades the database schema for DB, if VERSION is old."
|
||||
(emacsql-with-transaction db
|
||||
'ignore
|
||||
(if (< version org-roam-db--version)
|
||||
(progn
|
||||
(org-roam-message (format "Upgrading the Org-roam database from version %d to version %d"
|
||||
version org-roam-db--version))
|
||||
(org-roam-db-build-cache t))))
|
||||
version)
|
||||
|
||||
(defun org-roam-db--close (&optional db)
|
||||
"Closes the database connection for database DB.
|
||||
If DB is nil, closes the database connection for the database in
|
||||
the current `org-roam-directory'."
|
||||
(unless db
|
||||
(setq db (org-roam-db--get-connection)))
|
||||
(when (and db (emacsql-live-p db))
|
||||
(emacsql-close db)))
|
||||
|
||||
(defun org-roam-db--close-all ()
|
||||
"Closes all database connections made by Org-roam."
|
||||
(dolist (conn (hash-table-values org-roam-db--connection))
|
||||
(org-roam-db--close conn)))
|
||||
|
||||
;;;; Database API
|
||||
;;;;; Initialization
|
||||
(defun org-roam-db--initialized-p ()
|
||||
"Whether the cache has been initialized."
|
||||
(and (file-exists-p (org-roam-db--get))
|
||||
(> (caar (org-roam-db-query [:select (funcall count) :from titles]))
|
||||
0)))
|
||||
|
||||
(defun org-roam-db--ensure-built ()
|
||||
"Ensures that Org-roam cache is built."
|
||||
(unless (org-roam-db--initialized-p)
|
||||
(error "[Org-roam] your cache isn't built yet! Please run org-roam-db-build-cache")))
|
||||
|
||||
;;;;; Clearing
|
||||
(defun org-roam-db--clear ()
|
||||
"Clears all entries in the caches."
|
||||
(interactive)
|
||||
(when (file-exists-p (org-roam-db--get))
|
||||
(dolist (table (mapcar #'car org-roam-db--table-schemata))
|
||||
(org-roam-db-query `[:delete :from ,table]))))
|
||||
|
||||
(defun org-roam-db--clear-file (&optional filepath)
|
||||
"Remove any related links to the file at FILEPATH.
|
||||
This is equivalent to removing the node from the graph."
|
||||
(let ((file (file-truename (or filepath
|
||||
(buffer-file-name (buffer-base-buffer))))))
|
||||
(dolist (table (mapcar #'car org-roam-db--table-schemata))
|
||||
(org-roam-db-query `[:delete :from ,table
|
||||
:where (= ,(if (eq table 'links) 'from 'file) $s1)]
|
||||
file))))
|
||||
|
||||
;;;;; Insertion
|
||||
(defun org-roam-db--insert-meta (file hash meta)
|
||||
"Insert HASH and META for a FILE into the Org-roam cache."
|
||||
(org-roam-db-query
|
||||
[:insert :into files
|
||||
:values $v1]
|
||||
(list (vector file hash meta))))
|
||||
|
||||
(defun org-roam-db--insert-links (links)
|
||||
"Insert LINKS into the Org-roam cache."
|
||||
(org-roam-db-query
|
||||
[:insert :into links
|
||||
:values $v1]
|
||||
links))
|
||||
|
||||
(defun org-roam-db--insert-titles (file titles)
|
||||
"Insert TITLES for a FILE into the Org-roam cache."
|
||||
(org-roam-db-query
|
||||
[:insert :into titles
|
||||
:values $v1]
|
||||
(list (vector file titles))))
|
||||
|
||||
(defun org-roam-db--insert-tags (file tags)
|
||||
"Insert TAGS for a FILE into the Org-roam cache."
|
||||
(org-roam-db-query
|
||||
[:insert :into tags
|
||||
:values $v1]
|
||||
(list (vector file tags))))
|
||||
|
||||
(defun org-roam-db--insert-ref (file ref)
|
||||
"Insert REF for FILE into the Org-roam cache."
|
||||
(let ((key (cdr ref))
|
||||
(type (car ref)))
|
||||
(org-roam-db-query
|
||||
[:insert :into refs :values $v1]
|
||||
(list (vector key file type)))))
|
||||
|
||||
;;;;; Fetching
|
||||
(defun org-roam-db--get-current-files ()
|
||||
"Return a hash-table of file to the hash of its file contents."
|
||||
(let* ((current-files (org-roam-db-query [:select * :from files]))
|
||||
(ht (make-hash-table :test #'equal)))
|
||||
(dolist (row current-files)
|
||||
(puthash (car row) (cadr row) ht))
|
||||
ht))
|
||||
|
||||
(defun org-roam-db--get-titles (file)
|
||||
"Return the titles of FILE from the cache."
|
||||
(caar (org-roam-db-query [:select [titles] :from titles
|
||||
:where (= file $s1)]
|
||||
file
|
||||
:limit 1)))
|
||||
|
||||
(defun org-roam-db--connected-component (file)
|
||||
"Return all files reachable from/connected to FILE, including the file itself.
|
||||
If the file does not have any connections, nil is returned."
|
||||
(let* ((query "WITH RECURSIVE
|
||||
links_of(file, link) AS
|
||||
(WITH roamlinks AS (SELECT * FROM links WHERE \"type\" = '\"roam\"'),
|
||||
citelinks AS (SELECT * FROM links
|
||||
JOIN refs ON links.\"to\" = refs.\"ref\"
|
||||
AND links.\"type\" = '\"cite\"')
|
||||
SELECT \"from\", \"to\" FROM roamlinks UNION
|
||||
SELECT \"to\", \"from\" FROM roamlinks UNION
|
||||
SELECT \"file\", \"from\" FROM citelinks UNION
|
||||
SELECT \"from\", \"file\" FROM citelinks),
|
||||
connected_component(file) AS
|
||||
(SELECT link FROM links_of WHERE file = $s1
|
||||
UNION
|
||||
SELECT link FROM links_of JOIN connected_component USING(file))
|
||||
SELECT * FROM connected_component;")
|
||||
(files (mapcar 'car-safe (emacsql (org-roam-db) query file))))
|
||||
files))
|
||||
|
||||
(defun org-roam-db--links-with-max-distance (file max-distance)
|
||||
"Return all files connected to FILE in at most MAX-DISTANCE steps.
|
||||
This includes the file itself. If the file does not have any
|
||||
connections, nil is returned."
|
||||
(let* ((query "WITH RECURSIVE
|
||||
links_of(file, link) AS
|
||||
(WITH roamlinks AS (SELECT * FROM links WHERE \"type\" = '\"roam\"'),
|
||||
citelinks AS (SELECT * FROM links
|
||||
JOIN refs ON links.\"to\" = refs.\"ref\"
|
||||
AND links.\"type\" = '\"cite\"')
|
||||
SELECT \"from\", \"to\" FROM roamlinks UNION
|
||||
SELECT \"to\", \"from\" FROM roamlinks UNION
|
||||
SELECT \"file\", \"from\" FROM citelinks UNION
|
||||
SELECT \"from\", \"file\" FROM citelinks),
|
||||
-- Links are traversed in a breadth-first search. In order to calculate the
|
||||
-- distance of nodes and to avoid following cyclic links, the visited nodes
|
||||
-- are tracked in 'trace'.
|
||||
connected_component(file, trace) AS
|
||||
(VALUES($s1, json_array($s1))
|
||||
UNION
|
||||
SELECT lo.link, json_insert(cc.trace, '$[' || json_array_length(cc.trace) || ']', lo.link) FROM
|
||||
connected_component AS cc JOIN links_of AS lo USING(file)
|
||||
WHERE (
|
||||
-- Avoid cycles by only visiting each file once.
|
||||
(SELECT count(*) FROM json_each(cc.trace) WHERE json_each.value == lo.link) == 0
|
||||
-- Note: BFS is cut off early here.
|
||||
AND json_array_length(cc.trace) < ($s2 + 1)))
|
||||
SELECT DISTINCT file, min(json_array_length(trace)) AS distance
|
||||
FROM connected_component GROUP BY file ORDER BY distance;")
|
||||
;; In principle the distance would be available in the second column.
|
||||
(files (mapcar 'car-safe (emacsql (org-roam-db) query file max-distance))))
|
||||
files))
|
||||
|
||||
;;;;; Updating
|
||||
(defun org-roam-db--update-meta ()
|
||||
"Update the metadata of the current buffer into the cache."
|
||||
(let* ((file (file-truename (buffer-file-name)))
|
||||
(attr (file-attributes file))
|
||||
(atime (file-attribute-access-time attr))
|
||||
(mtime (file-attribute-modification-time attr))
|
||||
(hash (secure-hash 'sha1 (current-buffer))))
|
||||
(org-roam-db-query [:delete :from files
|
||||
:where (= file $s1)]
|
||||
file)
|
||||
(org-roam-db--insert-meta file hash (list :atime atime :mtime mtime))))
|
||||
|
||||
(defun org-roam-db--update-titles ()
|
||||
"Update the title of the current buffer into the cache."
|
||||
(let* ((file (file-truename (buffer-file-name)))
|
||||
(title (org-roam--extract-titles)))
|
||||
(org-roam-db-query [:delete :from titles
|
||||
:where (= file $s1)]
|
||||
file)
|
||||
(org-roam-db--insert-titles file title)))
|
||||
|
||||
(defun org-roam-db--update-tags ()
|
||||
"Update the tags of the current buffer into the cache."
|
||||
(let* ((file (file-truename (buffer-file-name)))
|
||||
(tags (org-roam--extract-tags)))
|
||||
(org-roam-db-query [:delete :from tags
|
||||
:where (= file $s1)]
|
||||
file)
|
||||
(org-roam-db--insert-tags file tags)))
|
||||
|
||||
(defun org-roam-db--update-refs ()
|
||||
"Update the ref of the current buffer into the cache."
|
||||
(let ((file (file-truename (buffer-file-name))))
|
||||
(org-roam-db-query [:delete :from refs
|
||||
:where (= file $s1)]
|
||||
file)
|
||||
(when-let ((ref (org-roam--extract-ref)))
|
||||
(org-roam-db--insert-ref file ref))))
|
||||
|
||||
(defun org-roam-db--update-cache-links ()
|
||||
"Update the file links of the current buffer in the cache."
|
||||
(let ((file (file-truename (buffer-file-name))))
|
||||
(org-roam-db-query [:delete :from links
|
||||
:where (= from $s1)]
|
||||
file)
|
||||
(when-let ((links (org-roam--extract-links)))
|
||||
(org-roam-db--insert-links links))))
|
||||
|
||||
(defun org-roam-db--update-file (&optional file-path)
|
||||
"Update Org-roam cache for FILE-PATH."
|
||||
(when (org-roam--org-roam-file-p file-path)
|
||||
(let ((buf (or (and file-path
|
||||
(find-file-noselect file-path t))
|
||||
(current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(save-excursion
|
||||
(org-roam-db--update-meta)
|
||||
(org-roam-db--update-tags)
|
||||
(org-roam-db--update-titles)
|
||||
(org-roam-db--update-refs)
|
||||
(org-roam-db--update-cache-links)
|
||||
(org-roam-buffer--update-maybe :redisplay t))))))
|
||||
|
||||
(defun org-roam-db-build-cache (&optional force)
|
||||
"Build the cache for `org-roam-directory'.
|
||||
If FORCE, force a rebuild of the cache from scratch."
|
||||
(interactive "P")
|
||||
(when force (delete-file (org-roam-db--get)))
|
||||
(org-roam-db--close) ;; Force a reconnect
|
||||
(org-roam-db) ;; To initialize the database, no-op if already initialized
|
||||
(let* ((org-roam-files (org-roam--list-all-files))
|
||||
(current-files (org-roam-db--get-current-files))
|
||||
all-files all-links all-titles all-refs all-tags)
|
||||
(dolist (file org-roam-files)
|
||||
(let* ((attr (file-attributes file))
|
||||
(atime (file-attribute-access-time attr))
|
||||
(mtime (file-attribute-modification-time attr)))
|
||||
(org-roam--with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(let ((contents-hash (secure-hash 'sha1 (current-buffer))))
|
||||
(unless (string= (gethash file current-files)
|
||||
contents-hash)
|
||||
(org-roam-db--clear-file file)
|
||||
(push (vector file contents-hash (list :atime atime :mtime mtime))
|
||||
all-files)
|
||||
(when-let (links (org-roam--extract-links file))
|
||||
(push links all-links))
|
||||
(when-let (tags (org-roam--extract-tags file))
|
||||
(push (vector file tags) all-tags))
|
||||
(let ((titles (org-roam--extract-titles)))
|
||||
(push (vector file titles)
|
||||
all-titles))
|
||||
(when-let* ((ref (org-roam--extract-ref))
|
||||
(type (car ref))
|
||||
(key (cdr ref)))
|
||||
(setq all-refs (cons (vector key file type) all-refs))))
|
||||
(remhash file current-files)))))
|
||||
(dolist (file (hash-table-keys current-files))
|
||||
;; These files are no longer around, remove from cache...
|
||||
(org-roam-db--clear-file file))
|
||||
(when all-files
|
||||
(org-roam-db-query
|
||||
[:insert :into files
|
||||
:values $v1]
|
||||
all-files))
|
||||
(when all-links
|
||||
(org-roam-db-query
|
||||
[:insert :into links
|
||||
:values $v1]
|
||||
all-links))
|
||||
(when all-titles
|
||||
(org-roam-db-query
|
||||
[:insert :into titles
|
||||
:values $v1]
|
||||
all-titles))
|
||||
(when all-tags
|
||||
(org-roam-db-query
|
||||
[:insert :into tags
|
||||
:values $v1]
|
||||
all-tags))
|
||||
(when all-refs
|
||||
(org-roam-db-query
|
||||
[:insert :into refs
|
||||
:values $v1]
|
||||
all-refs))
|
||||
(let ((stats (list :files (length all-files)
|
||||
:links (length all-links)
|
||||
:tags (length all-tags)
|
||||
:titles (length all-titles)
|
||||
:refs (length all-refs)
|
||||
:deleted (length (hash-table-keys current-files)))))
|
||||
(org-roam-message "files: %s, links: %s, tags: %s, titles: %s, refs: %s, deleted: %s"
|
||||
(plist-get stats :files)
|
||||
(plist-get stats :links)
|
||||
(plist-get stats :tags)
|
||||
(plist-get stats :titles)
|
||||
(plist-get stats :refs)
|
||||
(plist-get stats :deleted))
|
||||
stats)))
|
||||
|
||||
(provide 'org-roam-db)
|
||||
|
||||
;;; org-roam-db.el ends here
|
40
org-roam-dev.el
Normal file
40
org-roam-dev.el
Normal file
@ -0,0 +1,40 @@
|
||||
;;; org-roam-dev.el --- Org-roam development code -mode -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides code for org-roam developers.
|
||||
;; It is intended to be loaded before editing org-roam source files.
|
||||
;; It ensures consistent application of various developer settings.
|
||||
;;
|
||||
;;; Code:
|
||||
(require 'emacsql)
|
||||
(emacsql-fix-vector-indentation)
|
||||
(setq-local sentence-end-double-space nil)
|
||||
(provide 'org-roam-dev)
|
||||
|
||||
;;; org-roam-dev.el ends here
|
231
org-roam-doctor.el
Normal file
231
org-roam-doctor.el
Normal file
@ -0,0 +1,231 @@
|
||||
;;; org-roam-doctor.el --- Linter for Org-roam files -*- coding: utf-8; lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/jethrokuan/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides `org-roam-doctor', a utility for diagnosing and fixing
|
||||
;; Org-roam files. Running `org-roam-doctor' launches a list of checks defined
|
||||
;; by `org-roam-doctor--checkers'. Every checker is an instance of
|
||||
;; `org-roam-doctor-checker'.
|
||||
;;
|
||||
;; Each checker is given the Org parse tree (AST), and is expected to return a
|
||||
;; list of errors. The checker can also provide "actions" for auto-fixing errors
|
||||
;; (see `org-roam-doctor--remove-link' for an example).
|
||||
;;
|
||||
;; The UX experience is inspired by both org-lint and checkdoc, and their code
|
||||
;; is heavily referenced.
|
||||
;;
|
||||
;;; Code:
|
||||
;; Library Requires
|
||||
(require 'cl-lib)
|
||||
(require 'org)
|
||||
(require 'org-roam-macs)
|
||||
(require 'org-element)
|
||||
|
||||
(declare-function org-roam-insert "org-roam")
|
||||
(declare-function org-roam--get-roam-buffers "org-roam")
|
||||
(declare-function org-roam--list-all-files "org-roam")
|
||||
(declare-function org-roam--org-roam-file-p "org-roam")
|
||||
|
||||
(defvar org-roam-verbose)
|
||||
|
||||
(cl-defstruct (org-roam-doctor-checker (:copier nil))
|
||||
(name 'missing-checker-name)
|
||||
(description "")
|
||||
(actions nil))
|
||||
|
||||
(defconst org-roam-doctor--checkers
|
||||
(list
|
||||
(make-org-roam-doctor-checker
|
||||
:name 'org-roam-doctor-broken-links
|
||||
:description "Fix broken links."
|
||||
:actions '(("d" . ("Unlink" . org-roam-doctor--remove-link))
|
||||
("r" . ("Replace link" . org-roam-doctor--replace-link))
|
||||
("R" . ("Replace link (keep label)" . org-roam-doctor--replace-link-keep-label))))))
|
||||
|
||||
(defun org-roam-doctor-broken-links (ast)
|
||||
"Checker for detecting broken links.
|
||||
AST is the org-element parse tree."
|
||||
(let (reports)
|
||||
(org-element-map ast 'link
|
||||
(lambda (l)
|
||||
(when (equal "file" (org-element-property :type l))
|
||||
(let ((file (org-element-property :path l)))
|
||||
(or (file-exists-p file)
|
||||
(file-remote-p file)
|
||||
(push
|
||||
`(,(org-element-property :begin l)
|
||||
,(format (if (org-element-lineage l '(link))
|
||||
"Link to non-existent image file \"%s\"\
|
||||
in link description"
|
||||
"Link to non-existent local file \"%s\"")
|
||||
file))
|
||||
reports))))))
|
||||
reports))
|
||||
|
||||
(defun org-roam-doctor--check (buffer checkers)
|
||||
"Check BUFFER for errors.
|
||||
CHECKERS is the list of checkers used."
|
||||
(with-current-buffer buffer
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let* ((ast (org-element-parse-buffer))
|
||||
(errors (sort (cl-mapcan
|
||||
(lambda (c)
|
||||
(mapcar
|
||||
(lambda (report)
|
||||
(list (set-marker (make-marker) (car report))
|
||||
(nth 1 report) c))
|
||||
(save-excursion
|
||||
(funcall
|
||||
(org-roam-doctor-checker-name c)
|
||||
ast))))
|
||||
checkers)
|
||||
#'car-less-than-car)))
|
||||
(dolist (e errors)
|
||||
(pcase-let ((`(,m ,msg ,checker) e))
|
||||
(switch-to-buffer buffer)
|
||||
(goto-char m)
|
||||
(org-reveal)
|
||||
(undo-boundary)
|
||||
(org-roam-doctor--resolve msg checker)
|
||||
(set-marker m nil)))
|
||||
errors))))
|
||||
|
||||
;;; Actions
|
||||
(defun org-roam-doctor--recursive-edit ()
|
||||
"Launch into a recursive edit."
|
||||
(message "When you're done editing press C-M-c to continue.")
|
||||
(recursive-edit))
|
||||
|
||||
(defun org-roam-doctor--skip ()
|
||||
"Skip the current error."
|
||||
(org-roam-message "Skipping..."))
|
||||
|
||||
(defun org-roam-doctor--replace-link ()
|
||||
"Replace the current link with a new link."
|
||||
(save-match-data
|
||||
(unless (org-in-regexp org-link-bracket-re 1)
|
||||
(user-error "No link at point"))
|
||||
(let ((orig (buffer-string))
|
||||
(p (point)))
|
||||
(condition-case nil
|
||||
(save-excursion
|
||||
(replace-match "")
|
||||
(org-roam-insert))
|
||||
(quit (progn
|
||||
(replace-buffer-contents orig)
|
||||
(goto-char p)))))))
|
||||
|
||||
(defun org-roam-doctor--replace-link-keep-label ()
|
||||
"Replace the current link with a new link, keeping the current link's label."
|
||||
(save-match-data
|
||||
(unless (org-in-regexp org-link-bracket-re 1)
|
||||
(user-error "No link at point"))
|
||||
(let ((orig (buffer-string))
|
||||
(p (point)))
|
||||
(condition-case nil
|
||||
(save-excursion
|
||||
(let ((label (if (match-end 2)
|
||||
(match-string-no-properties 2)
|
||||
(org-link-unescape (match-string-no-properties 1)))))
|
||||
(replace-match "")
|
||||
(org-roam-insert nil nil label)))
|
||||
(quit (progn
|
||||
(replace-buffer-contents orig)
|
||||
(goto-char p)))))))
|
||||
|
||||
(defun org-roam-doctor--remove-link ()
|
||||
"Unlink the text at point."
|
||||
(unless (org-in-regexp org-link-bracket-re 1)
|
||||
(user-error "No link at point"))
|
||||
(save-excursion
|
||||
(let ((label (if (match-end 2)
|
||||
(match-string-no-properties 2)
|
||||
(org-link-unescape (match-string-no-properties 1)))))
|
||||
(delete-region (match-beginning 0) (match-end 0))
|
||||
(insert label))))
|
||||
|
||||
(defun org-roam-doctor--resolve (msg checker)
|
||||
"Resolve an error.
|
||||
MSG is the error that was found, which is displayed in a help buffer.
|
||||
CHECKER is a org-roam-doctor checker instance."
|
||||
(let ((actions (org-roam-doctor-checker-actions checker))
|
||||
c)
|
||||
(push '("e" . ("Edit" . org-roam-doctor--recursive-edit)) actions)
|
||||
(push '("s" . ("Skip" . org-roam-doctor--skip)) actions)
|
||||
(with-output-to-temp-buffer "*Org-roam-doctor Help*"
|
||||
(mapc #'princ
|
||||
(list "Error message:\n " msg "\n\n"))
|
||||
(dolist (action actions)
|
||||
(princ (format "[%s]: %s\n"
|
||||
(car action)
|
||||
(cadr action))))
|
||||
(princ "\n\n"))
|
||||
(shrink-window-if-larger-than-buffer
|
||||
(get-buffer-window "*Org-roam-doctor Help*"))
|
||||
(message "Press key for command:")
|
||||
(unwind-protect
|
||||
(progn
|
||||
(cl-loop
|
||||
do (setq c (char-to-string (read-char-exclusive)))
|
||||
until (assoc c actions)
|
||||
do (message "Please enter a valid key for command:"))
|
||||
(funcall (cddr (assoc c actions)))
|
||||
(redisplay))
|
||||
(when (get-buffer-window "*Org-roam-doctor Help*")
|
||||
(delete-window (get-buffer-window "*Org-roam-doctor Help*"))
|
||||
(kill-buffer "*Org-roam-doctor Help*")))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-doctor (&optional checkall)
|
||||
"Perform a check on the current buffer to ensure cleanliness.
|
||||
If CHECKALL, run the check for all Org-roam files."
|
||||
(interactive "P")
|
||||
(let ((files (if checkall
|
||||
(org-roam--list-all-files)
|
||||
(unless (org-roam--org-roam-file-p)
|
||||
(user-error "Not in an org-roam file"))
|
||||
`(,(buffer-file-name)))))
|
||||
(org-roam-doctor-start files org-roam-doctor--checkers)))
|
||||
|
||||
(defun org-roam-doctor-start (files checkers)
|
||||
"Lint FILES using CHECKERS."
|
||||
(save-window-excursion
|
||||
(let ((existing-buffers (org-roam--get-roam-buffers)))
|
||||
(dolist (f files)
|
||||
(let ((buf (find-file-noselect f)))
|
||||
(org-roam-doctor--check buf checkers)
|
||||
(unless (memq buf existing-buffers)
|
||||
(save-buffer buf)
|
||||
(kill-buffer buf))))))
|
||||
(org-roam-message "Linting completed."))
|
||||
|
||||
(provide 'org-roam-doctor)
|
||||
|
||||
;;; org-roam-doctor.el ends here
|
296
org-roam-graph.el
Normal file
296
org-roam-graph.el
Normal file
@ -0,0 +1,296 @@
|
||||
;;; org-roam-graph.el --- Graphing API -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library provides graphing functionality for org-roam.
|
||||
;;
|
||||
;;; Code:
|
||||
(require 'xml) ;xml-escape-string
|
||||
(require 's) ;s-truncate, s-replace
|
||||
(require 'org-roam-macs)
|
||||
(require 'org-roam-db)
|
||||
|
||||
;;;; Declarations
|
||||
(defvar org-roam-directory)
|
||||
(declare-function org-roam--org-roam-file-p "org-roam")
|
||||
(declare-function org-roam--path-to-slug "org-roam")
|
||||
|
||||
;;;; Options
|
||||
(defcustom org-roam-graph-viewer (executable-find "firefox")
|
||||
"Method to view the org-roam graph.
|
||||
It may be one of the following:
|
||||
- a string representing the path to the executable for viewing the graph.
|
||||
- a function accepting a single argument: the graph file path.
|
||||
- nil uses `view-file' to view the graph."
|
||||
:type '(choice
|
||||
(string :tag "Path to executable")
|
||||
(function :tag "Function to display graph" eww-open-file)
|
||||
(const :tag "view-file"))
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-executable "dot"
|
||||
"Path to graphing executable, or its name."
|
||||
:type 'string
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-extra-config nil
|
||||
"Extra options passed to graphviz.
|
||||
Example:
|
||||
'((\"rankdir\" . \"LR\"))"
|
||||
:type '(alist)
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-node-extra-config
|
||||
'(("shape" . "underline")
|
||||
("style" . "rounded,filled")
|
||||
("fillcolor" . "#EEEEEE")
|
||||
("color" . "#C9C9C9")
|
||||
("fontcolor" . "#111111"))
|
||||
"Extra options for graphviz nodes.
|
||||
Example:
|
||||
'((\"color\" . \"skyblue\"))"
|
||||
:type '(alist)
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-edge-extra-config
|
||||
'(("color" . "#333333"))
|
||||
"Extra options for graphviz edges.
|
||||
Example:
|
||||
'((\"dir\" . \"back\"))"
|
||||
:type '(alist)
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-edge-cites-extra-config '(("color" . "red"))
|
||||
"Extra options for graphviz edges for citation links.
|
||||
Example:
|
||||
'((\"dir\" . \"back\"))"
|
||||
:type '(alist)
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-max-title-length 100
|
||||
"Maximum length of titles in graph nodes."
|
||||
:type 'number
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-shorten-titles 'truncate
|
||||
"Determines how long titles appear in graph nodes.
|
||||
Recognized values are the symbols `truncate' and `wrap', in which
|
||||
cases the title will be truncated or wrapped, respectively, if it
|
||||
is longer than `org-roam-graph-max-title-length'.
|
||||
|
||||
All other values including nil will have no effect."
|
||||
:type '(choice
|
||||
(const :tag "truncate" truncate)
|
||||
(const :tag "wrap" wrap)
|
||||
(const :tag "no" nil))
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-graph-exclude-matcher nil
|
||||
"Matcher for excluding nodes from the generated graph.
|
||||
Any nodes and links for file paths matching this string is
|
||||
excluded from the graph.
|
||||
|
||||
If value is a string, the string is the only matcher.
|
||||
|
||||
If value is a list, all file paths matching any of the strings
|
||||
are excluded."
|
||||
:type '(choice
|
||||
(string :tag "Matcher")
|
||||
(list :tag "Matchers"))
|
||||
:group 'org-roam)
|
||||
|
||||
;;;; Functions
|
||||
(defun org-roam-graph--expand-matcher (col &optional negate where)
|
||||
"Return the exclusion regexp from `org-roam-graph-exclude-matcher'.
|
||||
COL is the symbol to be matched against. if NEGATE, add :not to sql query.
|
||||
set WHERE to true if WHERE query already exists."
|
||||
(let ((matchers (pcase org-roam-graph-exclude-matcher
|
||||
('nil nil)
|
||||
((pred stringp) `(,(concat "%" org-roam-graph-exclude-matcher "%")))
|
||||
((pred listp) (mapcar (lambda (m)
|
||||
(concat "%" m "%"))
|
||||
org-roam-graph-exclude-matcher))
|
||||
(_ (error "Invalid org-roam-graph-exclude-matcher"))))
|
||||
res)
|
||||
(dolist (match matchers)
|
||||
(if where
|
||||
(push :and res)
|
||||
(push :where res)
|
||||
(setq where t))
|
||||
(push col res)
|
||||
(when negate
|
||||
(push :not res))
|
||||
(push :like res)
|
||||
(push match res))
|
||||
(nreverse res)))
|
||||
|
||||
(defun org-roam-graph--dot-option (option &optional wrap-key wrap-val)
|
||||
"Return dot string of form KEY=VAL for OPTION cons.
|
||||
If WRAP-KEY is non-nil it wraps the KEY.
|
||||
If WRAP-VAL is non-nil it wraps the VAL."
|
||||
(concat wrap-key (car option) wrap-key
|
||||
"="
|
||||
wrap-val (cdr option) wrap-val))
|
||||
|
||||
(defun org-roam-graph--dot (node-query)
|
||||
"Build the graphviz dot string for NODE-QUERY.
|
||||
The Org-roam database titles table is read, to obtain the list of titles.
|
||||
The links table is then read to obtain all directed links, and formatted
|
||||
into a digraph."
|
||||
(org-roam-db--ensure-built)
|
||||
(org-roam--with-temp-buffer
|
||||
(let* ((nodes (org-roam-db-query node-query))
|
||||
(edges-query
|
||||
`[:with selected :as [:select [file] :from ,node-query]
|
||||
:select :distinct [to from] :from links
|
||||
:where (and (in to selected) (in from selected))])
|
||||
(edges-cites-query
|
||||
`[:with selected :as [:select [file] :from ,node-query]
|
||||
:select :distinct [file from]
|
||||
:from links :inner :join refs :on (and (= links:to refs:ref)
|
||||
(= links:type "cite")
|
||||
(= refs:type "cite"))
|
||||
:where (and (in file selected) (in from selected))])
|
||||
(edges (org-roam-db-query edges-query))
|
||||
(edges-cites (org-roam-db-query edges-cites-query)))
|
||||
(insert "digraph \"org-roam\" {\n")
|
||||
(dolist (option org-roam-graph-extra-config)
|
||||
(insert (org-roam-graph--dot-option option) ";\n"))
|
||||
(dolist (attribute '("node" "edge"))
|
||||
(insert (format " %s [%s];\n" attribute
|
||||
(mapconcat (lambda (var)
|
||||
(org-roam-graph--dot-option var nil "\""))
|
||||
(symbol-value
|
||||
(intern (concat "org-roam-graph-" attribute "-extra-config")))
|
||||
","))))
|
||||
(dolist (node nodes)
|
||||
(let* ((file (xml-escape-string (car node)))
|
||||
(title (or (caadr node)
|
||||
(org-roam--path-to-slug file)))
|
||||
(shortened-title (pcase org-roam-graph-shorten-titles
|
||||
(`truncate (s-truncate org-roam-graph-max-title-length title))
|
||||
(`wrap (s-word-wrap org-roam-graph-max-title-length title))
|
||||
(_ title)))
|
||||
(node-properties
|
||||
`(("label" . ,(s-replace "\"" "\\\"" shortened-title))
|
||||
("URL" . ,(concat "org-protocol://roam-file?file=" (url-hexify-string file)))
|
||||
("tooltip" . ,(xml-escape-string title)))))
|
||||
(insert
|
||||
(format " \"%s\" [%s];\n" file
|
||||
(mapconcat (lambda (n)
|
||||
(org-roam-graph--dot-option n nil "\""))
|
||||
node-properties ",")))))
|
||||
(dolist (edge edges)
|
||||
(insert (apply #'format `(" \"%s\" -> \"%s\";\n"
|
||||
,@(mapcar #'xml-escape-string edge)))))
|
||||
(insert (format " edge [%s];\n"
|
||||
(mapconcat #'org-roam-graph--dot-option
|
||||
org-roam-graph-edge-cites-extra-config ",")))
|
||||
(dolist (edge edges-cites)
|
||||
(insert (apply #'format `(" \"%s\" -> \"%s\";\n"
|
||||
,@(mapcar #'xml-escape-string edge)))))
|
||||
(insert "}")
|
||||
(buffer-string))))
|
||||
|
||||
(defun org-roam-graph--build (&optional node-query)
|
||||
"Generate a graph showing the relations between nodes in NODE-QUERY."
|
||||
(let ((name org-roam-graph-executable))
|
||||
(unless (stringp name)
|
||||
(user-error "`org-roam-graph-executable' is not a string"))
|
||||
(unless (executable-find org-roam-graph-executable)
|
||||
(user-error (concat "Cannot find executable \"%s\" to generate the graph. "
|
||||
"Please adjust `org-roam-graph-executable'")
|
||||
name))
|
||||
(let* ((node-query (or node-query
|
||||
`[:select [file titles]
|
||||
:from titles
|
||||
,@(org-roam-graph--expand-matcher 'file t)]))
|
||||
(graph (org-roam-graph--dot node-query))
|
||||
(temp-dot (make-temp-file "graph." nil ".dot" graph))
|
||||
(temp-graph (make-temp-file "graph." nil ".svg")))
|
||||
(call-process name nil 0 nil temp-dot "-Tsvg" "-o" temp-graph)
|
||||
temp-graph)))
|
||||
|
||||
(defun org-roam-graph--open (file)
|
||||
"Open FILE using `org-roam-graph-viewer' with `view-file' as a fallback."
|
||||
(pcase org-roam-graph-viewer
|
||||
((pred stringp)
|
||||
(if (executable-find org-roam-graph-viewer)
|
||||
(condition-case err
|
||||
(call-process org-roam-graph-viewer nil 0 nil file)
|
||||
(error (user-error "Failed to open org-roam graph: %s" err)))
|
||||
(user-error "Executable not found: \"%s\"" org-roam-graph-viewer)))
|
||||
((pred functionp) (funcall org-roam-graph-viewer file))
|
||||
('nil (view-file file))
|
||||
(_ (signal 'wrong-type-argument `((functionp stringp null) ,org-roam-graph-viewer)))))
|
||||
|
||||
(defun org-roam-graph--build-connected-component (file &optional max-distance)
|
||||
"Build a graph of nodes connected to FILE.
|
||||
If MAX-DISTANCE is non-nil, limit nodes to MAX-DISTANCE steps."
|
||||
(let* ((file (file-truename file))
|
||||
(files (or (if (and max-distance (>= max-distance 0))
|
||||
(org-roam-db--links-with-max-distance file max-distance)
|
||||
(org-roam-db--connected-component file))
|
||||
(list file)))
|
||||
(query `[:select [file titles]
|
||||
:from titles
|
||||
:where (in file [,@files])]))
|
||||
(org-roam-graph--build query)))
|
||||
|
||||
;;;; Commands
|
||||
;;;###autoload
|
||||
(defun org-roam-graph (&optional arg file node-query)
|
||||
"Build and possibly display a graph for FILE from NODE-QUERY.
|
||||
If FILE is nil, default to current buffer's file name.
|
||||
ARG may be any of the following values:
|
||||
- nil show the graph.
|
||||
- `\\[universal-argument]' show the graph for FILE.
|
||||
- `\\[universal-argument]' N show the graph for FILE limiting nodes to N steps.
|
||||
- `\\[universal-argument] \\[universal-argument]' build the graph.
|
||||
- `\\[universal-argument]' - build the graph for FILE.
|
||||
- `\\[universal-argument]' -N build the graph for FILE limiting nodes to N steps."
|
||||
(interactive "P")
|
||||
(let ((file (or file (buffer-file-name (buffer-base-buffer)))))
|
||||
(unless (or (not arg) (equal arg '(16)))
|
||||
(unless file
|
||||
(user-error "Cannot build graph for nil file. Is current buffer visiting a file?"))
|
||||
(unless (org-roam--org-roam-file-p file)
|
||||
(user-error "\"%s\" is not an org-roam file" file)))
|
||||
(pcase arg
|
||||
('nil (org-roam-graph--open (org-roam-graph--build node-query)))
|
||||
('(4) (org-roam-graph--open (org-roam-graph--build-connected-component file)))
|
||||
((pred integerp) (let ((graph (org-roam-graph--build-connected-component file (abs arg))))
|
||||
(when (>= arg 0)
|
||||
(org-roam-graph--open graph))))
|
||||
('(16) (org-roam-graph--build node-query))
|
||||
('- (org-roam-graph--build-connected-component file))
|
||||
(_ (user-error "Unrecognized ARG: %s" arg)))))
|
||||
|
||||
(provide 'org-roam-graph)
|
||||
|
||||
;;; org-roam-graph.el ends here
|
69
org-roam-macs.el
Normal file
69
org-roam-macs.el
Normal file
@ -0,0 +1,69 @@
|
||||
;;; org-roam-macs.el --- Macros/utility functions -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 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: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (s "1.12.0") (org "9.3") (emacsql "3.0.0") (emacsql-sqlite "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This library implements macros and utility functions used throughout
|
||||
;; org-roam.
|
||||
;;
|
||||
;;
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
|
||||
(defvar org-roam-verbose)
|
||||
|
||||
(defmacro org-roam--with-temp-buffer (&rest body)
|
||||
"Execute BODY within a temp buffer.
|
||||
Like `with-temp-buffer', but propagates `org-roam-directory'."
|
||||
(declare (indent 0) (debug t))
|
||||
(let ((current-org-roam-directory (make-symbol "current-org-roam-directory")))
|
||||
`(let ((,current-org-roam-directory org-roam-directory))
|
||||
(with-temp-buffer
|
||||
(let ((org-roam-directory ,current-org-roam-directory))
|
||||
,@body)))))
|
||||
|
||||
(defmacro org-roam--with-template-error (templates &rest body)
|
||||
"Eval BODY, and point to TEMPLATES on error.
|
||||
Provides more informative error messages so that users know where
|
||||
to look.
|
||||
|
||||
\(fn TEMPLATES BODY...)"
|
||||
(declare (debug (form body)) (indent 1))
|
||||
`(condition-case err
|
||||
,@body
|
||||
(error (user-error "%s. Please adjust `%s'"
|
||||
(error-message-string err)
|
||||
,templates))))
|
||||
|
||||
(defun org-roam-message (format-string &rest args)
|
||||
"Pass FORMAT-STRING and ARGS to `message' when `org-roam-verbose' is t."
|
||||
(when org-roam-verbose
|
||||
(apply #'message `(,(concat "(org-roam) " format-string) ,@args))))
|
||||
|
||||
(provide 'org-roam-macs)
|
||||
|
||||
;;; org-roam-macs.el ends here
|
91
org-roam-protocol.el
Normal file
91
org-roam-protocol.el
Normal file
@ -0,0 +1,91 @@
|
||||
;;; org-roam-protocol.el --- Protocol handler for roam:// links -*- coding: utf-8; lexical-binding: t; -*-
|
||||
|
||||
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.1.1
|
||||
;; Package-Requires: ((emacs "26.1") (org "9.3"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; We extend org-protocol, adding custom Org-roam handlers. The setup
|
||||
;; instructions for `org-protocol' can be found in org-protocol.el.
|
||||
;;
|
||||
;; We define 2 protocols:
|
||||
;;
|
||||
;; 1. "roam-file": This protocol simply opens the file given by the FILE key
|
||||
;; 2. "roam-ref": This protocol creates or opens a note with the given REF
|
||||
;;
|
||||
;;; Code:
|
||||
(require 'org-protocol)
|
||||
(require 'org-roam)
|
||||
|
||||
;;;; Functions
|
||||
(defun org-roam-protocol-open-ref (info)
|
||||
"Process an org-protocol://roam-ref?ref= style url with INFO.
|
||||
|
||||
It opens or creates a note with the given ref.
|
||||
|
||||
javascript:location.href = \\='org-protocol://roam-ref?template=r&ref=\\='+ \\
|
||||
encodeURIComponent(location.href) + \\='&title=\\=' \\
|
||||
encodeURIComponent(document.title) + \\='&body=\\=' + \\
|
||||
encodeURIComponent(window.getSelection())"
|
||||
(when-let* ((alist (org-roam--plist-to-alist info))
|
||||
(decoded-alist (mapcar (lambda (k.v)
|
||||
(let ((key (car k.v))
|
||||
(val (cdr k.v)))
|
||||
(cons key (org-link-decode val)))) alist)))
|
||||
(unless (assoc 'ref decoded-alist)
|
||||
(error "No ref key provided"))
|
||||
(when-let ((title (cdr (assoc 'title decoded-alist))))
|
||||
(push (cons 'slug (org-roam--title-to-slug title)) decoded-alist))
|
||||
(let* ((org-roam-capture-templates org-roam-capture-ref-templates)
|
||||
(org-roam-capture--context 'ref)
|
||||
(org-roam-capture--info decoded-alist)
|
||||
(template (cdr (assoc 'template decoded-alist))))
|
||||
(raise-frame)
|
||||
(org-roam--with-template-error 'org-roam-capture-ref-templates
|
||||
(org-roam-capture--capture nil template))
|
||||
(org-roam-message "Item captured.")))
|
||||
nil)
|
||||
|
||||
(defun org-roam-protocol-open-file (info)
|
||||
"This handler simply opens the file with emacsclient.
|
||||
|
||||
INFO is an alist containing additional information passed by the protocol URL.
|
||||
It should contain the FILE key, pointing to the path of the file to open.
|
||||
|
||||
Example protocol string:
|
||||
|
||||
org-protocol://roam-file?file=/path/to/file.org"
|
||||
(when-let ((file (plist-get info :file)))
|
||||
(raise-frame)
|
||||
(find-file file))
|
||||
nil)
|
||||
|
||||
(push '("org-roam-ref" :protocol "roam-ref" :function org-roam-protocol-open-ref)
|
||||
org-protocol-protocol-alist)
|
||||
(push '("org-roam-file" :protocol "roam-file" :function org-roam-protocol-open-file)
|
||||
org-protocol-protocol-alist)
|
||||
|
||||
(provide 'org-roam-protocol)
|
||||
|
||||
;;; org-roam-protocol.el ends here
|
@ -1,169 +0,0 @@
|
||||
;;; org-roam-utils.el --- Roam Research replica with Org-mode -*- coding: utf-8; lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/jethrokuan/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 0.1.2
|
||||
;; Package-Requires: ((emacs "26.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 library is an attempt at injecting Roam functionality into Org-mode.
|
||||
;; This is achieved primarily through building caches for forward links,
|
||||
;; backward links, and file titles.
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(require 'org)
|
||||
(require 'org-element)
|
||||
(require 'subr-x)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defun org-roam--file-name-extension (filename)
|
||||
"Return file name extension for FILENAME.
|
||||
|
||||
Like file-name-extension, but does not strip version number."
|
||||
(save-match-data
|
||||
(let ((file (file-name-nondirectory filename)))
|
||||
(if (and (string-match "\\.[^.]*\\'" file)
|
||||
(not (eq 0 (match-beginning 0))))
|
||||
(substring file (+ (match-beginning 0) 1))))))
|
||||
|
||||
(defun org-roam--org-file-p (path)
|
||||
"Check if PATH is pointing to an org file."
|
||||
(let ((ext (org-roam--file-name-extension path)))
|
||||
(or (string= ext "org")
|
||||
(and
|
||||
(string= ext "gpg")
|
||||
(string= (org-roam--file-name-extension (file-name-sans-extension path)) "org")))))
|
||||
|
||||
(defun org-roam--find-files (dir)
|
||||
"Return all `org-roam' files in `DIR'."
|
||||
(if (file-exists-p dir)
|
||||
(let ((files (directory-files dir t "." t))
|
||||
(dir-ignore-regexp (concat "\\(?:"
|
||||
"\\."
|
||||
"\\|\\.\\."
|
||||
"\\)$"))
|
||||
result)
|
||||
(dolist (file files)
|
||||
(cond
|
||||
((file-directory-p file)
|
||||
(when (not (string-match dir-ignore-regexp file))
|
||||
(setq result (append (org-roam--find-files file) result))))
|
||||
((and (file-readable-p file)
|
||||
(org-roam--org-file-p file))
|
||||
(setq result (cons (file-truename file) result)))))
|
||||
result)))
|
||||
|
||||
(defun org-roam--parse-content (&optional file-path)
|
||||
"Parse the current buffer, and return a list of items for processing."
|
||||
(org-element-map (org-element-parse-buffer) 'link
|
||||
(lambda (link)
|
||||
(let ((type (org-element-property :type link))
|
||||
(path (org-element-property :path link))
|
||||
(start (org-element-property :begin link)))
|
||||
(when (and (string= type "file")
|
||||
(org-roam--org-file-p path))
|
||||
(goto-char start)
|
||||
(let* ((element (org-element-at-point))
|
||||
(begin (or (org-element-property :content-begin element)
|
||||
(org-element-property :begin element)))
|
||||
(content (or (org-element-property :raw-value element)
|
||||
(buffer-substring
|
||||
begin
|
||||
(or (org-element-property :content-end element)
|
||||
(org-element-property :end element)))))
|
||||
(content (string-trim content))
|
||||
(file-path (or file-path
|
||||
(file-truename (buffer-file-name (current-buffer))))))
|
||||
(list :from file-path
|
||||
:to (file-truename (expand-file-name path (file-name-directory file-path)))
|
||||
:properties (list :content content :point begin))))))))
|
||||
|
||||
(cl-defun org-roam--insert-item (item &key forward backward)
|
||||
"Insert ITEM into FORWARD and BACKWARD cache.
|
||||
|
||||
ITEM is of the form: (:from from-path :to to-path :properties (:content preview-content :point point))."
|
||||
(pcase-let ((`(:from ,p-from :to ,p-to :properties ,props) item))
|
||||
;; Build forward-links
|
||||
(let ((links (gethash p-from forward)))
|
||||
(if links
|
||||
(puthash p-from
|
||||
(if (member p-to links)
|
||||
links
|
||||
(cons p-to links)) forward)
|
||||
(puthash p-from (list p-to) forward)))
|
||||
;; Build backward-links
|
||||
(let ((contents-hash (gethash p-to backward)))
|
||||
(if contents-hash
|
||||
(if-let ((contents-list (gethash p-from contents-hash)))
|
||||
(let ((updated (cons props contents-list)))
|
||||
(puthash p-from updated contents-hash)
|
||||
(puthash p-to contents-hash backward))
|
||||
(progn
|
||||
(puthash p-from (list props) contents-hash)
|
||||
(puthash p-to contents-hash backward)))
|
||||
(let ((contents-hash (make-hash-table :test #'equal)))
|
||||
(puthash p-from (list props) contents-hash)
|
||||
(puthash p-to contents-hash backward))))))
|
||||
|
||||
(defun org-roam--extract-title ()
|
||||
"Extract the title from `BUFFER'."
|
||||
(org-element-map
|
||||
(org-element-parse-buffer)
|
||||
'keyword
|
||||
(lambda (kw)
|
||||
(when (string= (org-element-property :key kw) "TITLE")
|
||||
(org-element-property :value kw)))
|
||||
:first-match t))
|
||||
|
||||
(defun org-roam--build-cache (dir)
|
||||
"Build the org-roam caches in DIR."
|
||||
(let ((backward-links (make-hash-table :test #'equal))
|
||||
(forward-links (make-hash-table :test #'equal))
|
||||
(file-titles (make-hash-table :test #'equal)))
|
||||
(let* ((org-roam-files (org-roam--find-files dir))
|
||||
(file-items (mapcar (lambda (file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(org-roam--parse-content file))) org-roam-files)))
|
||||
(dolist (items file-items)
|
||||
(dolist (item items)
|
||||
(org-roam--insert-item
|
||||
item
|
||||
:forward forward-links
|
||||
:backward backward-links)))
|
||||
(dolist (file org-roam-files)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(when-let ((title (org-roam--extract-title)))
|
||||
(puthash file title file-titles)))
|
||||
org-roam-files))
|
||||
(list
|
||||
:forward forward-links
|
||||
:backward backward-links
|
||||
:titles file-titles)))
|
||||
|
||||
(provide 'org-roam-utils)
|
||||
|
||||
;;; org-roam-utils.el ends here
|
1526
org-roam.el
1526
org-roam.el
File diff suppressed because it is too large
Load Diff
2
tests/roam-files/alias.org
Normal file
2
tests/roam-files/alias.org
Normal file
@ -0,0 +1,2 @@
|
||||
#+ROAM_ALIAS: "a1" "a 2"
|
||||
#+TITLE: t1
|
3
tests/roam-files/bar.org
Normal file
3
tests/roam-files/bar.org
Normal file
@ -0,0 +1,3 @@
|
||||
#+TITLE: Bar
|
||||
|
||||
This is file bar. Bar links to [[file:nested/bar.org][Nested Bar]].
|
1
tests/roam-files/base.org
Normal file
1
tests/roam-files/base.org
Normal file
@ -0,0 +1 @@
|
||||
#+TITLE: Base
|
@ -1,7 +0,0 @@
|
||||
#+TITLE: File 1
|
||||
|
||||
link to [[file:nested/f1.org][Nested File 1]]
|
||||
link to [[file:f2.org][File 2]]
|
||||
|
||||
Arbitrary [[https://google.com][HTML]] link
|
||||
Arbitrary text
|
@ -1,5 +0,0 @@
|
||||
#+TITLE: File 3
|
||||
|
||||
This file has a link to an file with no title.
|
||||
|
||||
[[file:no-title.org][no-title]]
|
8
tests/roam-files/foo.org
Normal file
8
tests/roam-files/foo.org
Normal file
@ -0,0 +1,8 @@
|
||||
#+TITLE: Foo
|
||||
|
||||
This is the foo file. It contains a link to [[file:bar.org][Bar]].
|
||||
|
||||
To make the tests more robust, here are some arbitrary links:
|
||||
|
||||
- [[https:google.com][Google]]
|
||||
- [[mailto:foo@john.com][mail to foo]]
|
3
tests/roam-files/nested/bar.org
Normal file
3
tests/roam-files/nested/bar.org
Normal file
@ -0,0 +1,3 @@
|
||||
#+TITLE: Nested Bar
|
||||
|
||||
This file is nested, 1 level deeper. It links to both [[file:../foo.org][Foo]] and [[file:foo.org][Nested Foo]].
|
1
tests/roam-files/nested/deeply/deeply_nested_file.org
Normal file
1
tests/roam-files/nested/deeply/deeply_nested_file.org
Normal file
@ -0,0 +1 @@
|
||||
#+TITLE: Deeply Nested File
|
@ -1,4 +0,0 @@
|
||||
#+TITLE: Nested File 1
|
||||
|
||||
Link to [[file:f2.org][Nested File 2]]
|
||||
Link to [[file:../f1.org][File 1]]
|
@ -1,3 +0,0 @@
|
||||
#+TITLE: Nested File 2
|
||||
|
||||
Link to [[file:f1.org][Nested File 1]]
|
@ -1,3 +1,3 @@
|
||||
#+TITLE: File 2
|
||||
#+TITLE: Nested Foo
|
||||
|
||||
This file has no links.
|
@ -1 +1,5 @@
|
||||
no title in this file :O
|
||||
|
||||
links to itself, with no title: [[file:no-title.org][no-title]]
|
||||
|
||||
* Headline title
|
||||
|
3
tests/roam-files/tags/no_tag.org
Normal file
3
tests/roam-files/tags/no_tag.org
Normal file
@ -0,0 +1,3 @@
|
||||
#+TITLE: Tagless File
|
||||
|
||||
This file has no tags, and should not yield any tags on extracting via =#+ROAM_TAGS=.
|
4
tests/roam-files/tags/tag.org
Normal file
4
tests/roam-files/tags/tag.org
Normal file
@ -0,0 +1,4 @@
|
||||
#+ROAM_TAGS: "t1" "t2 with space" t3
|
||||
#+TITLE: Tags
|
||||
|
||||
This file is used to test functionality for =(org-roam--extract-tags)=
|
1
tests/roam-files/titles/aliases.org
Normal file
1
tests/roam-files/titles/aliases.org
Normal file
@ -0,0 +1 @@
|
||||
#+ROAM_ALIAS: "roam" "alias"
|
4
tests/roam-files/titles/combination.org
Normal file
4
tests/roam-files/titles/combination.org
Normal file
@ -0,0 +1,4 @@
|
||||
#+TITLE: TITLE PROP
|
||||
#+ROAM_ALIAS: "roam" "alias"
|
||||
|
||||
* Headline
|
1
tests/roam-files/titles/headline.org
Normal file
1
tests/roam-files/titles/headline.org
Normal file
@ -0,0 +1 @@
|
||||
* Headline
|
1
tests/roam-files/titles/title.org
Normal file
1
tests/roam-files/titles/title.org
Normal file
@ -0,0 +1 @@
|
||||
#+TITLE: Title
|
3
tests/roam-files/unlinked.org
Normal file
3
tests/roam-files/unlinked.org
Normal file
@ -0,0 +1,3 @@
|
||||
#+TITLE: Unlinked
|
||||
|
||||
Nothing links here :(
|
1
tests/roam-files/web_ref.org
Normal file
1
tests/roam-files/web_ref.org
Normal file
@ -0,0 +1 @@
|
||||
#+ROAM_KEY: https://google.com/
|
@ -1,4 +1,4 @@
|
||||
;;; test-org-roam.el --- Tests for org-roam -*- lexical-binding: t; -*-
|
||||
;;; test-org-roam.el --- Tests for Org-roam -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2020 Jethro Kuan
|
||||
|
||||
@ -19,212 +19,450 @@
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;;; Requirements
|
||||
|
||||
(require 'buttercup)
|
||||
(require 'with-simulated-input)
|
||||
(require 'org-roam)
|
||||
(require 'dash)
|
||||
|
||||
(defun abs-path (file-path)
|
||||
(defun test-org-roam--abs-path (file-path)
|
||||
"Get absolute FILE-PATH from `org-roam-directory'."
|
||||
(file-truename (expand-file-name file-path org-roam-directory)))
|
||||
|
||||
(defun org-roam--test-find-new-file (path)
|
||||
(let ((path (abs-path path)))
|
||||
(defun test-org-roam--find-file (path)
|
||||
"PATH."
|
||||
(let ((path (test-org-roam--abs-path path)))
|
||||
(make-directory (file-name-directory path) t)
|
||||
(find-file path)))
|
||||
|
||||
(defvar org-roam--tests-directory (file-truename (concat default-directory "tests/roam-files"))
|
||||
(defvar test-org-roam-directory (file-truename (concat default-directory "tests/roam-files"))
|
||||
"Directory containing org-roam test org files.")
|
||||
|
||||
(defun org-roam--test-init ()
|
||||
(let ((original-dir org-roam--tests-directory)
|
||||
(defun test-org-roam--init ()
|
||||
"."
|
||||
(let ((original-dir test-org-roam-directory)
|
||||
(new-dir (expand-file-name (make-temp-name "org-roam") temporary-file-directory)))
|
||||
(copy-directory original-dir new-dir)
|
||||
(setq org-roam-directory new-dir))
|
||||
(org-roam-mode +1))
|
||||
(setq org-roam-directory new-dir)
|
||||
(org-roam-mode +1)
|
||||
(sleep-for 2)))
|
||||
|
||||
(defun org-roam--test-build-cache ()
|
||||
"Builds the caches synchronously."
|
||||
(let ((cache (org-roam--build-cache org-roam-directory)))
|
||||
(setq org-roam-forward-links-cache (plist-get cache :forward))
|
||||
(setq org-roam-backward-links-cache (plist-get cache :backward))
|
||||
(setq org-roam-titles-cache (plist-get cache :titles))
|
||||
(setq org-roam-cache-initialized t)))
|
||||
(defun test-org-roam--teardown ()
|
||||
(org-roam-mode -1)
|
||||
(delete-file (org-roam-db--get))
|
||||
(org-roam-db--close))
|
||||
|
||||
(describe "Title extraction"
|
||||
:var (org-roam-title-sources)
|
||||
(before-all
|
||||
(test-org-roam--init))
|
||||
|
||||
(after-all
|
||||
(test-org-roam--teardown))
|
||||
|
||||
(cl-flet
|
||||
((test (fn file)
|
||||
(let ((buf (find-file-noselect
|
||||
(test-org-roam--abs-path file))))
|
||||
(with-current-buffer buf
|
||||
(funcall fn)))))
|
||||
(it "extracts title from title property"
|
||||
(expect (test #'org-roam--extract-titles-title
|
||||
"titles/title.org")
|
||||
:to-equal
|
||||
'("Title"))
|
||||
(expect (test #'org-roam--extract-titles-title
|
||||
"titles/aliases.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-titles-title
|
||||
"titles/headline.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-titles-title
|
||||
"titles/combination.org")
|
||||
:to-equal
|
||||
'("TITLE PROP")))
|
||||
|
||||
(it "extracts alias"
|
||||
(expect (test #'org-roam--extract-titles-alias
|
||||
"titles/title.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-titles-alias
|
||||
"titles/aliases.org")
|
||||
:to-equal
|
||||
'("roam" "alias"))
|
||||
(expect (test #'org-roam--extract-titles-alias
|
||||
"titles/headline.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-titles-alias
|
||||
"titles/combination.org")
|
||||
:to-equal
|
||||
'("roam" "alias")))
|
||||
|
||||
(it "extracts headlines"
|
||||
(expect (test #'org-roam--extract-titles-alias
|
||||
"titles/title.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-titles-headline
|
||||
"titles/aliases.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-titles-headline
|
||||
"titles/headline.org")
|
||||
:to-equal
|
||||
'("Headline"))
|
||||
(expect (test #'org-roam--extract-titles-headline
|
||||
"titles/combination.org")
|
||||
:to-equal
|
||||
'("Headline")))
|
||||
|
||||
(describe "uses org-roam-title-sources correctly"
|
||||
(it "'((title headline) alias)"
|
||||
(expect (let ((org-roam-title-sources '((title headline) alias)))
|
||||
(test #'org-roam--extract-titles
|
||||
"titles/combination.org"))
|
||||
:to-equal
|
||||
'("TITLE PROP" "roam" "alias")))
|
||||
(it "'((headline title) alias)"
|
||||
(expect (let ((org-roam-title-sources '((headline title) alias)))
|
||||
(test #'org-roam--extract-titles
|
||||
"titles/combination.org"))
|
||||
:to-equal
|
||||
'("Headline" "roam" "alias")))
|
||||
(it "'(headline alias title)"
|
||||
(expect (let ((org-roam-title-sources '(headline alias title)))
|
||||
(test #'org-roam--extract-titles
|
||||
"titles/combination.org"))
|
||||
:to-equal
|
||||
'("Headline" "roam" "alias" "TITLE PROP"))))))
|
||||
|
||||
(describe "Tag extraction"
|
||||
:var (org-roam-tag-sources)
|
||||
(before-all
|
||||
(test-org-roam--init))
|
||||
|
||||
(after-all
|
||||
(test-org-roam--teardown))
|
||||
|
||||
(cl-flet
|
||||
((test (fn file)
|
||||
(let* ((fname (test-org-roam--abs-path file))
|
||||
(buf (find-file-noselect fname)))
|
||||
(with-current-buffer buf
|
||||
(funcall fn fname)))))
|
||||
(it "extracts from prop"
|
||||
(expect (test #'org-roam--extract-tags-prop
|
||||
"tags/tag.org")
|
||||
:to-equal
|
||||
'("t1" "t2 with space" "t3"))
|
||||
(expect (test #'org-roam--extract-tags-prop
|
||||
"tags/no_tag.org")
|
||||
:to-equal
|
||||
nil))
|
||||
|
||||
(it "extracts from all directories"
|
||||
(expect (test #'org-roam--extract-tags-all-directories
|
||||
"base.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-tags-all-directories
|
||||
"tags/tag.org")
|
||||
:to-equal
|
||||
'("tags"))
|
||||
(expect (test #'org-roam--extract-tags-all-directories
|
||||
"nested/deeply/deeply_nested_file.org")
|
||||
:to-equal
|
||||
'("nested" "deeply")))
|
||||
|
||||
(it "extracts from last directory"
|
||||
(expect (test #'org-roam--extract-tags-last-directory
|
||||
"base.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-tags-last-directory
|
||||
"tags/tag.org")
|
||||
:to-equal
|
||||
'("tags"))
|
||||
(expect (test #'org-roam--extract-tags-last-directory
|
||||
"nested/deeply/deeply_nested_file.org")
|
||||
:to-equal
|
||||
'("deeply")))
|
||||
|
||||
(describe "uses org-roam-tag-sources correctly"
|
||||
(it "'(prop)"
|
||||
(expect (let ((org-roam-tag-sources '(prop)))
|
||||
(test #'org-roam--extract-tags
|
||||
"tags/tag.org"))
|
||||
:to-equal
|
||||
'("t1" "t2 with space" "t3")))
|
||||
(it "'(prop all-directories)"
|
||||
(expect (let ((org-roam-tag-sources '(prop all-directories)))
|
||||
(test #'org-roam--extract-tags
|
||||
"tags/tag.org"))
|
||||
:to-equal
|
||||
'("t1" "t2 with space" "t3" "tags"))))))
|
||||
|
||||
;;; Tests
|
||||
(describe "org-roam--build-cache-async"
|
||||
(it "initializes correctly"
|
||||
(org-roam--test-init)
|
||||
(expect org-roam-cache-initialized :to-be nil)
|
||||
(expect (hash-table-count org-roam-forward-links-cache) :to-be 0)
|
||||
(expect (hash-table-count org-roam-backward-links-cache) :to-be 0)
|
||||
(expect (hash-table-count org-roam-titles-cache) :to-be 0)
|
||||
(xdescribe "org-roam-db-build-cache"
|
||||
(before-each
|
||||
(test-org-roam--init))
|
||||
|
||||
(org-roam--build-cache-async)
|
||||
(sleep-for 3) ;; Because it's async
|
||||
(after-each
|
||||
(test-org-roam--teardown))
|
||||
|
||||
;; Caches should be populated
|
||||
(expect org-roam-cache-initialized :to-be t)
|
||||
(expect (hash-table-count org-roam-forward-links-cache) :to-be 4)
|
||||
(expect (hash-table-count org-roam-backward-links-cache) :to-be 5)
|
||||
(expect (hash-table-count org-roam-titles-cache) :to-be 5)
|
||||
(it "initializes correctly"
|
||||
;; Cache
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from files])) :to-be 8)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links])) :to-be 5)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from titles])) :to-be 8)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from titles
|
||||
:where titles :is-null])) :to-be 1)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from refs])) :to-be 1)
|
||||
|
||||
;; Forward cache
|
||||
(let ((f1 (gethash (abs-path "f1.org") org-roam-forward-links-cache))
|
||||
(f2 (gethash (abs-path "f2.org") org-roam-forward-links-cache))
|
||||
(nested-f1 (gethash (abs-path "nested/f1.org") org-roam-forward-links-cache))
|
||||
(nested-f2 (gethash (abs-path "nested/f2.org") org-roam-forward-links-cache))
|
||||
(expected-f1 (list (abs-path "nested/f1.org")
|
||||
(abs-path "f2.org")))
|
||||
(expected-nested-f1 (list (abs-path "nested/f2.org")
|
||||
(abs-path "f1.org")))
|
||||
(expected-nested-f2 (list (abs-path "nested/f1.org"))))
|
||||
;; Links
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 1)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "nested/bar.org"))) :to-be 2)
|
||||
|
||||
(expect f1 :to-have-same-items-as expected-f1)
|
||||
(expect f2 :to-be nil)
|
||||
(expect nested-f1 :to-have-same-items-as expected-nested-f1)
|
||||
(expect nested-f2 :to-have-same-items-as expected-nested-f2))
|
||||
;; Links -- File-to
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||
:where (= to $s1)]
|
||||
(test-org-roam--abs-path "nested/foo.org"))) :to-be 1)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||
:where (= to $s1)]
|
||||
(test-org-roam--abs-path "nested/bar.org"))) :to-be 1)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||
:where (= to $s1)]
|
||||
(test-org-roam--abs-path "unlinked.org"))) :to-be 0)
|
||||
;; TODO Test titles
|
||||
(expect (org-roam-db-query [:select * :from titles])
|
||||
:to-have-same-items-as
|
||||
(list (list (test-org-roam--abs-path "alias.org")
|
||||
(list "t1" "a1" "a 2"))
|
||||
(list (test-org-roam--abs-path "bar.org")
|
||||
(list "Bar"))
|
||||
(list (test-org-roam--abs-path "foo.org")
|
||||
(list "Foo"))
|
||||
(list (test-org-roam--abs-path "nested/bar.org")
|
||||
(list "Nested Bar"))
|
||||
(list (test-org-roam--abs-path "nested/foo.org")
|
||||
(list "Nested Foo"))
|
||||
(list (test-org-roam--abs-path "no-title.org")
|
||||
(list "Headline title"))
|
||||
(list (test-org-roam--abs-path "web_ref.org") nil)
|
||||
(list (test-org-roam--abs-path "unlinked.org")
|
||||
(list "Unlinked"))))
|
||||
|
||||
;; Backward cache
|
||||
(let ((f1 (hash-table-keys (gethash (abs-path "f1.org") org-roam-backward-links-cache)))
|
||||
(f2 (hash-table-keys (gethash (abs-path "f2.org") org-roam-backward-links-cache)))
|
||||
(nested-f1 (hash-table-keys(gethash (abs-path "nested/f1.org") org-roam-backward-links-cache)))
|
||||
(nested-f2 (hash-table-keys (gethash (abs-path "nested/f2.org") org-roam-backward-links-cache)))
|
||||
(expected-f1 (list (abs-path "nested/f1.org")))
|
||||
(expected-f2 (list (abs-path "f1.org")))
|
||||
(expected-nested-f1 (list (abs-path "nested/f2.org")
|
||||
(abs-path "f1.org")))
|
||||
(expected-nested-f2 (list (abs-path "nested/f1.org"))))
|
||||
(expect f1 :to-have-same-items-as expected-f1)
|
||||
(expect f2 :to-have-same-items-as expected-f2)
|
||||
(expect nested-f1 :to-have-same-items-as expected-nested-f1)
|
||||
(expect nested-f2 :to-have-same-items-as expected-nested-f2))
|
||||
(expect (org-roam-db-query [:select * :from refs])
|
||||
:to-have-same-items-as
|
||||
(list (list "https://google.com/" (test-org-roam--abs-path "web_ref.org") "website")))
|
||||
|
||||
;; Titles Cache
|
||||
(expect (gethash (abs-path "f1.org") org-roam-titles-cache) :to-equal "File 1")
|
||||
(expect (gethash (abs-path "f2.org") org-roam-titles-cache) :to-equal "File 2")
|
||||
(expect (gethash (abs-path "nested/f1.org") org-roam-titles-cache) :to-equal "Nested File 1")
|
||||
(expect (gethash (abs-path "nested/f2.org") org-roam-titles-cache) :to-equal "Nested File 2")
|
||||
(expect (gethash (abs-path "no-title.org") org-roam-titles-cache) :to-be nil)))
|
||||
;; Expect rebuilds to be really quick (nothing changed)
|
||||
(expect (org-roam-db-build-cache)
|
||||
:to-equal
|
||||
(list :files 0 :links 0 :tags 0 :titles 0 :refs 0 :deleted 0))))
|
||||
|
||||
(describe "org-roam-insert"
|
||||
(before-each
|
||||
(org-roam--test-init)
|
||||
(org-roam--clear-cache)
|
||||
(org-roam--test-build-cache))
|
||||
(xdescribe "org-roam-insert"
|
||||
(before-each
|
||||
(test-org-roam--init))
|
||||
|
||||
(it "temp1 -> f1"
|
||||
(let ((buf (org-roam--test-find-new-file "temp1.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"File SPC 1 RET"
|
||||
(org-roam-insert nil))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:f1.org")))
|
||||
(after-each
|
||||
(test-org-roam--teardown))
|
||||
|
||||
(it "temp2 -> nested/f1"
|
||||
(let ((buf (org-roam--test-find-new-file "temp2.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"Nested SPC File SPC 1 RET"
|
||||
(org-roam-insert nil))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:nested/f1.org")))
|
||||
(it "temp1 -> foo"
|
||||
(let ((buf (test-org-roam--find-file "temp1.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"Foo RET"
|
||||
(org-roam-insert))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:foo.org")))
|
||||
|
||||
(it "nested/temp3 -> f1"
|
||||
(let ((buf (org-roam--test-find-new-file "nested/temp3.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"File SPC 1 RET"
|
||||
(org-roam-insert nil))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:../f1.org")))
|
||||
(it "temp2 -> nested/foo"
|
||||
(let ((buf (test-org-roam--find-file "temp2.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"(nested) SPC Nested SPC Foo RET"
|
||||
(org-roam-insert))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:nested/foo.org")))
|
||||
|
||||
(it "a/b/temp4 -> nested/f1"
|
||||
(let ((buf (org-roam--test-find-new-file "a/b/temp4.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"Nested SPC File SPC 1 RET"
|
||||
(org-roam-insert nil))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/f1.org"))))
|
||||
(it "nested/temp3 -> foo"
|
||||
(let ((buf (test-org-roam--find-file "nested/temp3.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"Foo RET"
|
||||
(org-roam-insert))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:../foo.org")))
|
||||
|
||||
(describe "rename file updates cache"
|
||||
(before-each
|
||||
(org-roam--test-init)
|
||||
(org-roam--clear-cache)
|
||||
(org-roam--test-build-cache))
|
||||
(it "a/b/temp4 -> nested/foo"
|
||||
(let ((buf (test-org-roam--find-file "a/b/temp4.org")))
|
||||
(with-current-buffer buf
|
||||
(with-simulated-input
|
||||
"(nested) SPC Nested SPC Foo RET"
|
||||
(org-roam-insert))))
|
||||
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/foo.org"))))
|
||||
|
||||
(it "f1 -> new_f1"
|
||||
(rename-file (abs-path "f1.org")
|
||||
(abs-path "new_f1.org"))
|
||||
;; Cache should be cleared of old file
|
||||
(expect (gethash (abs-path "f1.org") org-roam-forward-links-cache) :to-be nil)
|
||||
(expect (->> org-roam-backward-links-cache
|
||||
(gethash (abs-path "nested/f1.org"))
|
||||
(hash-table-keys)
|
||||
(member (abs-path "f1.org"))) :to-be nil)
|
||||
(xdescribe "rename file updates cache"
|
||||
(before-each
|
||||
(test-org-roam--init))
|
||||
|
||||
(expect (->> org-roam-forward-links-cache
|
||||
(gethash (abs-path "new_f1.org"))) :not :to-be nil)
|
||||
(after-each
|
||||
(test-org-roam--teardown))
|
||||
|
||||
(expect (->> org-roam-forward-links-cache
|
||||
(gethash (abs-path "new_f1.org"))
|
||||
(member (abs-path "nested/f1.org"))) :not :to-be nil)
|
||||
;; Links are updated
|
||||
(expect (with-temp-buffer
|
||||
(insert-file-contents (abs-path "nested/f1.org"))
|
||||
(buffer-string)) :to-match (regexp-quote "[[file:../new_f1.org][File 1]]")))
|
||||
(it "foo -> new_foo"
|
||||
(rename-file (test-org-roam--abs-path "foo.org")
|
||||
(test-org-roam--abs-path "new_foo.org"))
|
||||
;; Cache should be cleared of old file
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from titles
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from refs
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
|
||||
;; Cache should be updated
|
||||
(expect (org-roam-db-query [:select [to]
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "new_foo.org"))
|
||||
:to-have-same-items-as
|
||||
(list (list (test-org-roam--abs-path "bar.org"))))
|
||||
(expect (org-roam-db-query [:select [from]
|
||||
:from links
|
||||
:where (= to $s1)]
|
||||
(test-org-roam--abs-path "new_foo.org"))
|
||||
:to-have-same-items-as
|
||||
(list (list (test-org-roam--abs-path "nested/bar.org"))))
|
||||
|
||||
(it "f1 -> f1 with spaces"
|
||||
(rename-file (abs-path "f1.org")
|
||||
(abs-path "f1 with spaces.org"))
|
||||
;; Cache should be cleared of old file
|
||||
(expect (gethash (abs-path "f1.org") org-roam-forward-links-cache) :to-be nil)
|
||||
(expect (->> org-roam-backward-links-cache
|
||||
(gethash (abs-path "nested/f1.org"))
|
||||
(hash-table-keys)
|
||||
(member (abs-path "f1.org"))) :to-be nil)
|
||||
;; Links are updated
|
||||
(expect (with-temp-buffer
|
||||
(insert-file-contents (abs-path "nested/f1.org"))
|
||||
(buffer-string)) :to-match (regexp-quote "[[file:../f1 with spaces.org][File 1]]")))
|
||||
;; Links are updated
|
||||
(expect (with-temp-buffer
|
||||
(insert-file-contents (test-org-roam--abs-path "nested/bar.org"))
|
||||
(buffer-string))
|
||||
:to-match
|
||||
(regexp-quote "[[file:../new_foo.org][Foo]]")))
|
||||
|
||||
(it "no-title -> meaningful-title"
|
||||
(rename-file (abs-path "no-title.org")
|
||||
(abs-path "meaningful-title.org"))
|
||||
;; File has no forward links
|
||||
(expect (gethash (abs-path "no-title.org") org-roam-forward-links-cache) :to-be nil)
|
||||
(expect (gethash (abs-path "meaningful-title.org") org-roam-forward-links-cache) :to-be nil)
|
||||
(it "foo -> foo with spaces"
|
||||
(rename-file (test-org-roam--abs-path "foo.org")
|
||||
(test-org-roam--abs-path "foo with spaces.org"))
|
||||
;; Cache should be cleared of old file
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from titles
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from refs
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
|
||||
(expect (->> org-roam-forward-links-cache
|
||||
(gethash (abs-path "f3.org"))
|
||||
(member (abs-path "no-title.org"))) :to-be nil)
|
||||
;; Cache should be updated
|
||||
(expect (org-roam-db-query [:select [to]
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "foo with spaces.org"))
|
||||
:to-have-same-items-as
|
||||
(list (list (test-org-roam--abs-path "bar.org"))))
|
||||
(expect (org-roam-db-query [:select [from]
|
||||
:from links
|
||||
:where (= to $s1)]
|
||||
(test-org-roam--abs-path "foo with spaces.org"))
|
||||
:to-have-same-items-as
|
||||
(list (list (test-org-roam--abs-path "nested/bar.org"))))
|
||||
|
||||
(expect (->> org-roam-forward-links-cache
|
||||
(gethash (abs-path "f3.org"))
|
||||
(member (abs-path "meaningful-title.org"))) :not :to-be nil)
|
||||
;; Links are updated
|
||||
(expect (with-temp-buffer
|
||||
(insert-file-contents (test-org-roam--abs-path "nested/bar.org"))
|
||||
(buffer-string))
|
||||
:to-match
|
||||
(regexp-quote "[[file:../foo with spaces.org][Foo]]")))
|
||||
|
||||
;; Links are updated with the appropriate name
|
||||
(expect (with-temp-buffer
|
||||
(insert-file-contents (abs-path "f3.org"))
|
||||
(buffer-string)) :to-match (regexp-quote "[[file:meaningful-title.org][meaningful-title]]"))))
|
||||
(it "no-title -> meaningful-title"
|
||||
(rename-file (test-org-roam--abs-path "no-title.org")
|
||||
(test-org-roam--abs-path "meaningful-title.org"))
|
||||
;; File has no forward links
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "no-title.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "meaningful-title.org"))) :to-be 1)
|
||||
|
||||
(describe "delete file updates cache"
|
||||
(before-each
|
||||
(org-roam--test-init)
|
||||
(org-roam--clear-cache)
|
||||
(org-roam--test-build-cache))
|
||||
(it "delete f1"
|
||||
(delete-file (abs-path "f1.org"))
|
||||
(expect (->> org-roam-forward-links-cache
|
||||
(gethash (abs-path "f1.org"))) :to-be nil)
|
||||
(expect (->> org-roam-backward-links-cache
|
||||
(gethash (abs-path "nested/f1.org"))
|
||||
(gethash (abs-path "f1.org"))) :to-be nil)
|
||||
(expect (->> org-roam-backward-links-cache
|
||||
(gethash (abs-path "nested/f1.org"))
|
||||
(gethash (abs-path "nested/f2.org"))) :not :to-be nil)))
|
||||
;; Links are updated with the appropriate name
|
||||
(expect (with-temp-buffer
|
||||
(insert-file-contents (test-org-roam--abs-path "meaningful-title.org"))
|
||||
(buffer-string))
|
||||
:to-match
|
||||
(regexp-quote "[[file:meaningful-title.org][meaningful-title]]")))
|
||||
|
||||
(it "web_ref -> hello"
|
||||
(expect (org-roam-db-query
|
||||
[:select [file] :from refs
|
||||
:where (= ref $s1)]
|
||||
"https://google.com/")
|
||||
:to-equal
|
||||
(list (list (test-org-roam--abs-path "web_ref.org"))))
|
||||
(rename-file (test-org-roam--abs-path "web_ref.org")
|
||||
(test-org-roam--abs-path "hello.org"))
|
||||
(expect (org-roam-db-query
|
||||
[:select [file] :from refs
|
||||
:where (= ref $s1)]
|
||||
"https://google.com/")
|
||||
:to-equal (list (list (test-org-roam--abs-path "hello.org"))))
|
||||
(expect (caar (org-roam-db-query
|
||||
[:select [ref] :from refs
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "web_ref.org")))
|
||||
:to-equal nil)))
|
||||
|
||||
(xdescribe "delete file updates cache"
|
||||
(before-each
|
||||
(test-org-roam--init))
|
||||
|
||||
(after-each
|
||||
(test-org-roam--teardown))
|
||||
|
||||
(it "delete foo"
|
||||
(delete-file (test-org-roam--abs-path "foo.org"))
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from titles
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from refs
|
||||
:where (= file $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0)
|
||||
(expect (caar (org-roam-db-query [:select (funcall count)
|
||||
:from links
|
||||
:where (= from $s1)]
|
||||
(test-org-roam--abs-path "foo.org"))) :to-be 0))
|
||||
|
||||
(it "delete web_ref"
|
||||
(expect (org-roam-db-query [:select * :from refs])
|
||||
:to-have-same-items-as
|
||||
(list (list "https://google.com/" (test-org-roam--abs-path "web_ref.org") "website")))
|
||||
(delete-file (test-org-roam--abs-path "web_ref.org"))
|
||||
(expect (org-roam-db-query [:select * :from refs])
|
||||
:to-have-same-items-as
|
||||
(list))))
|
||||
|
||||
(provide 'test-org-roam)
|
||||
|
||||
;;; test-org-roam.el ends here
|
||||
|
Reference in New Issue
Block a user