Compare commits

...

273 Commits

Author SHA1 Message Date
cce2db8b5a (release): v1.1.1 (#668) 2020-05-18 22:04:51 +08:00
2147adf95c Create FUNDING.yml 2020-05-18 21:27:31 +08:00
d2654f6023 (docs): add a nice default theme (#667) 2020-05-18 19:15:12 +08:00
N V
78b518efd3 (fix): org-roam-capture--capture shadow org-capture-templates-contexts (#662)
Lexically bind org-capture-templates-contexts to nil before calling org-capture
with org-roam-capture-templates. Otherwise, contexts may shadow
org-roam-templates which have same keys as org-capture-templates.

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

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

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

* Remove leftover variable

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

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

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

Replace generic package description in features' first line summary.

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

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

* Fix typos

* Try again

* Fix typo

* fix syntax error

* fix syntax error

* Apply args correctly

* Refactor with funcall

* Revert "Refactor with funcall"

This reverts commit 0807252d64.

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

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

* Error when ROAM_KEY is empty

* Handle nil

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

* Replace let* with let

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

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

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

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

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

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

* Rename to ‘invalid’

* Update docstring

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

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

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

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

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

* Refactor with ->>

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

* Update changelog with #545

* (fix): optimize processing

* (fix): avoid repetition

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

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

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

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

* (fix) improve docstrings

* (feat) add var for modifying subdir-separator

* (fix) nitpick docstring

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

* (feat) make subdir-format accept a function

* (fix) respect docstring one-line-description

* (fix) address checkdoc errors

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

* (feat) improve modularisation

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

* Refactor with ->>

* Refactor with let*

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

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

In addition, the `after-save-hook` function was not checking for whether
the file was within the org-roam system, which meant files from outside
`org-roam` would also be added into the database. This PR adds a guard
clause.
2020-04-22 14:35:47 +08:00
8a99febd0b (fix): lowercase username in url to org-roam-bibtex (#505) 2020-04-22 14:28:30 +08:00
b5786edb30 (docs): Fix org-roam-protocol JS Bookmarklet (#508) 2020-04-22 13:57:12 +08:00
dce8c47d6e (docs): mention org-roam-bibtex (#503) 2020-04-21 20:55:12 +08:00
27a63b59b1 (release): 1.1.0: update version headers in source (#502) 2020-04-21 20:50:24 +08:00
339336a27f (release): 1.1.0 (#501) 2020-04-21 20:43:21 +08:00
a35454bb7e (internal): Simplify org-roam--list-files implementation. (#497)
Use destructive elisp functions to optimize for speed and memory
usage.

Refs #104
2020-04-20 18:28:33 +08:00
N V
228af5b6be (fix): Remove old definition of org-roam-graph--open (#498)
Fixes #496
2020-04-20 02:24:18 +08:00
89b941a207 (feat) implement after-find-file-hook for org-roam-capture (#482)
Allows user to run functions when an `org-roam-capture` is successful.  This
might come in handy for moving point after finding the new file, since right
now, it is at `(point-min)`.
2020-04-19 22:45:09 +08:00
N V
258d6f8a52 (feat): Allow function for org-roam-graph-viewer (#488)
User may specify a function to open the org-roam graph.
Adds more error handling to org-roam-graph--open.

See #440
2020-04-19 19:00:33 +08:00
N V
dc65e58405 (refactor): org-roam-graph (#490)
- Consolidate graph build/display commands into org-roam-graph command
  See #450
- Require org-roam-db
  Rather than declaring its functions.
- Move obsolete variable org-roam-graph-node-shape to org-roam-compat
- org-roam-graph--build-connected-component accepts a file argument
  Allows building a graph without having the target file as the current
  buffer
- Eliminate repeating code
- Fix checkdoc warnings
2020-04-19 15:04:24 +08:00
de4f5477d8 (feat): Use TITLE as description when linking before first heading (#491)
Fixes #487
2020-04-19 00:41:38 +08:00
9e138e259a (feat) remove user-error for org-roam-insert (#486)
* (feat) remove user-error for org-roam-insert

Closes #477.

* (fix) use absolute path when buffer has no associated file

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-18 13:10:14 +08:00
ba80a31fe0 (feat): add optional FILTER-FN argument for org-roam-find-file and org-roam-insert (#481) 2020-04-18 04:54:17 +08:00
6175739b33 (docs) Provide examples of using template expansion and function overrides. (#478) 2020-04-17 18:31:39 +08:00
35b20de45f (fix): ensure that directory exists before capturing to dir (#476)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-17 12:39:03 +08:00
06afa27725 (docs): export: add snippet for backlinks with contents. (#466) 2020-04-17 12:34:40 +08:00
e1873a6a16 (internal): extract daily notes functionality (#473)
Beyond just an extraction, this is also a simplification. It removes two
variables: `org-roam-date-filename-format` and
`org-roam-date-title-format`, in favour of directly specifying them in
the `org-roam-dailies-capture-templates`.

`org-roam--file-for-time` is also vastly simplified to use org-capture's
default time expansion utilities, by setting the capture template's
`:default-time` appropriately.
2020-04-17 03:25:16 +08:00
e33c144298 (bugfix): add workaround for undocumented file-truename behavior (#470)
This prevents and error being generated when the agenda is displayed.

Fixes #408
2020-04-16 02:53:43 +08:00
ea1ba21825 (chore): inline links in changelog (#467)
I had initially thought that keeping them separate would be cleaner, but
it's very easy to forget to add the links at the bottom of the
changelog. Relevant emacs-lisp that did this:

(replace-regexp "\\[gh-\\([0-9]+\\)\\]" "(https://github.com/jethrokuan/org-roam/pull/\\1)")
2020-04-15 15:28:47 +08:00
d7fc91e047 (feat): Add support for different file extensions (#465)
Adds `org-roam-file-extensions`, which allows org-roam to detect file extensions other than .org. Fixes #461
2020-04-15 15:02:05 +08:00
a4a2ac8d19 Use MELPA for installing in Spacemacs (#462)
Now that org-roam is out on MELPA, let's suggest that people use it
instead of GitHub to install the package.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-15 14:34:23 +08:00
f79ee9e850 Correct database query function (#463)
`org-roam-sql` is obsolete now. Also changed the syntax that works for the new `org-roam-db-query` function.
2020-04-15 14:09:58 +08:00
a71176ee40 (docs): mention company-org-roam in documentation (#457) 2020-04-14 17:00:13 +08:00
6bdde3a634 (bugfix): fix org-roam-graph--open (#456) 2020-04-14 16:31:14 +08:00
b33300a23d (docs): fix broken format in win-install doc (#438) (#451) 2020-04-14 13:17:05 +08:00
N V
8c7bc09f9b (fix): Use make-temp-file in org-roam-graph-build (#454)
Create a new temporary file for each graph that is built.

See: #453
2020-04-14 13:14:23 +08:00
0a9ca736e4 (docs): fix small typo (#445)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-13 14:55:12 +08:00
N V
3506f16648 (fix): org-roam.el eval-when-compile subr-x (#449) 2020-04-13 12:12:30 +08:00
772505ba70 (bugfix): Explicitly load subr-x library (#429)
Ensure the `if-let*` macro definitions is available during compile-time
2020-04-12 17:18:09 +08:00
6392a8b5df (docs): fix broken format+typo in win-install (#438) (#444)
Co-authored-by: nobiot <me@nobiot.com>
2020-04-12 17:05:27 +08:00
580a320c66 (feat): graph: add cite links to graph (#439) 2020-04-12 14:38:58 +08:00
0e79bbb75a (doc) add Windows installation instruction (#397) (#438)
Co-authored-by: nobiot <me@nobiot.com>
2020-04-12 11:35:42 +08:00
4af4d2e4d5 (feat): split building and showing of the graph into two functions (#426) 2020-04-11 16:41:49 +08:00
N V
18939fcccd (doc): ref-capture-templates > capture-ref-templates (#433)
See: #430
2020-04-11 16:38:46 +08:00
1b13c426aa (feat): add org-roam-graph-edge-extra-config (#435)
Introduces `org-roam-graph-edge-extra-config` to add options to edges
2020-04-11 13:41:21 +08:00
N V
bee8e506c2 (refactor): Move obsolete vars/functions to org-roam-compat (#434) 2020-04-11 13:25:12 +08:00
c280f249a9 (fix) typo in doc, titles -> refs (#436) 2020-04-11 12:36:59 +08:00
ba1782d361 (feat): graph of bfs from given node (#418) 2020-04-11 04:20:43 +08:00
e327fb3f0c (fix): reuse variable defined in let-form (#431)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-11 04:13:16 +08:00
N V
40dc3a5af8 (refactor): org-roam-db.el eval-when-compile subr-x (#432)
Prevents unnecessary evaluation when compiled .elc is loaded.
From the commentary of subr-x.el:
;; NB If you want to use this library, it's almost always correct to use:
;; (eval-when-compile (require 'subr-x))

See: #429
2020-04-11 03:55:24 +08:00
05c9e8e2e7 (feat): add org-roam-find-directory (#424) 2020-04-10 20:11:39 +08:00
df20754fb0 (bugfix): Explicitly load subr-x library (#425)
Ensure the `when-let` macro definitions is available during
compile-time.
2020-04-10 19:19:00 +08:00
dddbe286de (feat): add customization to set no-delete-other-windows (#422)
Adds `org-roam-buffer-no-delete-other-windows`, which controls the behaviour of the org-roam buffer side window upon `delete-other-windows`.
2020-04-10 17:50:52 +08:00
92500b1338 (bugfix): Use predicate to check for a org-roam-capture process (#413)
Instead of using a global variable to check for a existing capture,
leverage the :org-roam plist property of the buffer-local variable
`org-roam-capture-current-plist`.

This prevents a lockout if the capture buffer is killed
2020-04-10 17:03:49 +08:00
N V
772504c488 (internal): modularize org-roam-buffer (#406)
Split functionality related to the org-roam-buffer into its own
feature/file.

Introduce `org-roam-buffer-prepare-hook' to allow customizations of the
org-roam-buffer content.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-10 14:38:41 +08:00
6e97003967 (fix): Detect all org-ref cite types (#417) 2020-04-09 12:26:40 +08:00
N V
dd3fd592bb (internal): Move aliases to org-roam-compat.el (#412)
Same strategy Org uses. Consolidates backward compatibility into a
single location. Leverages `define-obsolete-*-alias' macros.
2020-04-09 12:16:22 +08:00
67495e269a (feat): allow creation of connected-component graph (#398) 2020-04-08 10:52:40 +08:00
72faa591fb (docs): fix typo eduring -> during (#405)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-07 15:30:07 +08:00
N V
c7a44b9f12 Move org-roam-capture command to org-roam-capture.el (#407) 2020-04-07 13:53:22 +08:00
5120f8eac3 (chore): update Slack invite link (#403) 2020-04-06 18:23:51 +08:00
e73bc78274 (feat): Add org-ref citation support (#374)
Adds support for org-ref cite: links to the backlinks buffer.

Requires a db-rebuild, since the db schema has changed.
2020-04-06 16:48:17 +08:00
N V
4ca2606a28 (docs): org-roam-db-build-cache (#396)
Remove references to obsolete variable.
org-roam-build-cache -> org-roam-db-build-cache
2020-04-04 03:50:10 +08:00
f9a4f3b7f7 (docs:) spacemacs: replace show-graph with graph-show (#393)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-04-02 13:40:53 +08:00
8f28bd4ccf (feature): Add numeric prefix argument to org-roam-tomorrow (#392)
Also add prefix argument to `org-roam-yesterday`.

This makes it possible to jump back or forward several days.
2020-04-02 13:32:22 +08:00
N V
dfb8449680 Refactor org-roam--setup-buffer (#388)
Change function name org-roam--setup-buffer org-roam--set-up-buffer.
Warn user and default to 'right when org-roam-buffer-position is
an invalid position.

Make better use of pcase to avoid repeating code.
2020-04-01 13:16:09 +08:00
48ccb084f0 (feat): Cache template variable entry (#387)
Addresses
https://github.com/jethrokuan/org-roam/issues/285#issuecomment-606724827
2020-04-01 12:09:41 +08:00
f27e5f2384 (fix): Undo font locking changes in backlinks buffer (#386) 2020-04-01 11:50:16 +08:00
e4f77eb586 (feat): Add org-roam-graph-node-extra-config (#385)
org-roam-graph-node-extra-config is an alist containing additional node
configuration options, as per
https://graphviz.gitlab.io/_pages/doc/info/attrs.html

This also deprecates org-roam-graph-node-shape, which is a special case
of the node options
2020-04-01 11:36:24 +08:00
2e3119e027 Allow top and bottom placement of the sidebar in addition to left and right (#380)
* Allow placement of the sidebar on top or on bottom

* Add "let_sidebar_be_on_top_or_bottom" to the changelog

* Remove an unnecessary progn and replace an if with a pcase

As requested by jethrokuan in https://github.com/jethrokuan/org-roam/pull/380
comments.
2020-03-31 18:34:23 +08:00
N V
b06e296e88 (chore): update org-roam-graph variable names (#383)
See: https://github.com/jethrokuan/org-roam/issues/382
2020-03-31 16:56:15 +08:00
04acbda916 (docs): simplifying doom installation instructions (#381)
With the new `+roam` flag now added to doom emacs, this simplifies the instructions.
2020-03-31 05:46:46 +08:00
b86d2c8637 (docs): Add Org-roam video (#376) 2020-03-30 02:39:17 +08:00
7dd371c023 (fix?): use helm-make-source instead (#375)
Byte-compiled code should not contain macros.
2020-03-29 21:30:23 +08:00
58c07f74bc (docs): Add note about completion mechanism (#373) 2020-03-29 17:58:49 +08:00
bc28c85dfc (hotfix): move capture in-process setting as late as possible (#372)
This is a hotfix for #369. Currently, calling `org-roam-capture` sets
`org-roam-capture--in-process` to `t`, but cancelling the capture
process does not reset it to `nil`, causing false errors. The whole
nested org-capture processes workaround is brittle, this change moves it
as far back as possible, but the whole thing needs to be redesigned.
2020-03-29 17:52:22 +08:00
b607e56c5f (feat): Add interactive org-roam-capture (#371) 2020-03-29 17:29:57 +08:00
ba835ef624 (fix): Add alias for 'org-roam--capture-get-point (#370)
This ensures custom templates don't break
2020-03-29 17:12:33 +08:00
649af54640 (internal): remove company-org-roam (#368)
company-org-roam is maintained separately, at jethrokuan/company-org-roam.
2020-03-29 14:14:13 +08:00
N V
22b9d4bd22 (internal): modularize features (#363)
Addresses #357
2020-03-28 21:16:28 +08:00
df29da1b6d (feat): add variable for muting messages (#359)
Adds `org-roam-verbose`, which echoes messages that are not errors.
2020-03-27 15:09:52 +08:00
de36d15d0f Turn org-roam-backlinks-mode into a minor mode (#355)
This change makes `org-roam-open-at-point` non-interactive and adds it to
`org-open-at-point-functions`.  As a consequence, `org-open-at-point` will try
to visit an Org-roam link or preview text, before falling back to the default
behavior of Org mode.

Fixes #312.
2020-03-27 13:06:44 +08:00
3e0a49de03 (bugfix): change declare-function for helm-build-sync-source (#354) 2020-03-26 20:17:06 +08:00
3add2c5a8b (feature): add org-roam-db-location (#350)
`org-roam-db-location` sets the location of the Org-roam sqlite database.
2020-03-24 12:22:00 +08:00
4b6f580375 (bugfix): fix org-roam date functions filename format (#349)
Previously the filename was not used in the capture template.
2020-03-24 11:47:40 +08:00
23a8b0d722 Add warning: binding conflict with ranger layer (#348)
This happened to me. The error message and backtrace information were not very clear
2020-03-24 11:16:53 +08:00
1433dbc316 (release): v1.0.0 (#341) 2020-03-23 15:34:21 +08:00
def3d27d25 (internal): small refactor (#340) 2020-03-22 12:12:40 +08:00
6fae1d8100 (chore): update internal Github settings (#339)
Removes sponsor button, and disables 26.3 in testing matrix
2020-03-22 11:37:23 +08:00
07672213b6 (chore): fix bytecompile errors and checkdoc errors (#338) 2020-03-22 03:16:38 +08:00
5406827451 (internal): use org-link-make-string (#337)
This takes care of properly escaping backslashes in file names.
2020-03-22 02:46:36 +08:00
214a8f771f (internal): reduce org-roam capture template key pollution (#336)
Following #332, nest all org-roam related customization in to a single
key.
2020-03-22 00:13:19 +08:00
57f5e73192 (internal): force a reconnect on org-roam-build-cache (#335)
This is to guard against scenarios where a db connection is still live, although it
may already be invalid (like in #331)
2020-03-21 22:30:30 +08:00
1352809451 ensure "%?" is present in the template string (#330)
* ensure "%?" is present in the template string

- addresses #298
- fixes `org-capture-place-plain-text` throwing 'invalid search bound'
  when both :unnarowed t and "%?" is missing from the template string

* ensure "%?" is present in the template string

- if "%?" is missing, add it at the end of the template
2020-03-21 20:56:20 +08:00
N V
8b37135aa2 (internal): refactor to remove hooks in a loop (#334)
Removing hooks in a loop should be easier to extend/maintain.
More "DRY" than repeating calls to `remove-hook'.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-03-21 12:43:11 +08:00
N V
159e11c842 (internal): update cl.el functions to cl-lib versions (#333)
cl is a deprecated library. cl-lib replaces it.
2020-03-21 12:40:13 +08:00
63b2eaaf86 (bugfix): throw an error on nested org-roam capture processes (#329) 2020-03-20 20:17:56 +08:00
919d08732c (bugfix): fix nested org-roam-inserts not working (#328) 2020-03-20 00:57:32 +08:00
97dfc4b980 (bugfix): fix `org-roam--completing-read' for ido (#324)
For `ido-completing-read', `choices' must be a list of strings
2020-03-19 16:23:04 +08:00
4556f727ff (bugfix): fix org-roam-capture not saving file, and org-roam date functions (#321)
* (bugfix): fix org-roam-captures not saving file

* (bugfix): fix org-roam date functions
2020-03-18 01:11:08 +08:00
6775f15ad1 (bugfix): prevent file open if capture is cancelled (#316) 2020-03-17 17:20:55 +08:00
8f8ccf6797 (feat): clean-ups for org-roam-capture system (#315)
This introduces 2 user-facing changes:

1. If a capture process is aborted, the file is not created if it
doesn't yet exist

2. If a capture process is aborted, org-roam-insert will not insert a
link
2020-03-17 17:06:49 +08:00
81dd880357 (bugfix): fix ugly node labels in org-roam graph (#314) 2020-03-17 13:00:45 +08:00
c14ac7b613 (bugfix): fix Helm completing-read containing extra spaces on non-match (#309) 2020-03-16 17:42:57 +08:00
08667d9c7d (bugfix): Fix Helm integration for completing-read (#306)
Fixes #304, using PR #305 as the base, thanks @khinsen
2020-03-16 13:00:12 +08:00
f544bd9ca1 hexify file url for org-protocol link (#299)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-03-15 21:55:54 +08:00
66aff57cdb (bugfix): capture: prepend header template only on new file (#302) 2020-03-15 21:50:25 +08:00
f238e3fe02 (feat): order backlinks by filename (#300)
Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-03-15 15:26:24 +08:00
98fc273a0f (internal): less abusive use of org-capture (#294)
`org-roam--capture-new-file` does not write anything to a file, all the templating is delegated to vanilla `org-capture`
2020-03-15 13:41:36 +08:00
a4df95b518 Create FUNDING.yml 2020-03-14 17:52:51 +08:00
6f1154c90e (bugfix): remove nonexistent/redundant code (#297) 2020-03-14 14:55:53 +08:00
486ba9c5a8 (feat): upgrade org-roam-graph-exclude-matcher to accept a list (#296)
Closes #295
2020-03-14 01:17:32 +08:00
d28a83c992 (bugfix): fix unintuitive behaviour of capture insertion (#293)
Ref #285
2020-03-13 18:13:04 +08:00
62ed117eb6 (feat): Support multiple org-roam-directories for company backend (#292)
Fixes #276
2020-03-13 14:03:53 +08:00
a44b847596 (docs): add documentation for using neato (#291)
Some prefer using neato for generating a graph (ref #263). This
documents how to do so.
2020-03-13 13:37:55 +08:00
e64890c80e (feat): add org-roam-date-title-format and org-roam-date-filename-format (#290)
This PR supercedes #280. It allows users who use the date
functionality in Org-roam to customize the filename and title formats
of the created files.
2020-03-13 13:29:49 +08:00
4eaf69465e (feat): add 'ido and 'ivy support for completing-read (#289)
Also adds org-roam-fuzzy-match, which for ivy and helm controls
whether completion candidates are fuzzy matched.
2020-03-13 13:11:22 +08:00
0950ae3cc6 (feature): add support for Helm's completion system (#284)
adds org-roam-completion-system, supporting helm as the default completion option.
2020-03-12 19:34:27 +08:00
0cab668d9e (bugfix): propagate org-roam-directory to temp buffers (#275) 2020-03-11 15:41:18 +08:00
6095d01ef4 (feat): add a company-mode for link completion (#257)
Adds company-org-roam, a company backend which autocompletes text into org file links
2020-03-11 14:32:58 +08:00
bd425e4427 (docs):fix typo in platypus installation (#274) 2020-03-11 11:37:01 +08:00
65ead3c9ed (chore): fix more checkdoc errors (#270) 2020-03-11 00:55:42 +08:00
be1d1f1d7b (feat): add org-roam-graphviz-extra-options (#269) 2020-03-11 00:44:07 +08:00
f5d5b83b49 (bugfix): fix missed org-roam-link-title-format uses (#268)
In #261 we allowed org-roam-link-title-format to be a function, but missed some of its uses during the update. h.t. @alanz
2020-03-11 00:34:08 +08:00
8a3945945b (bugfix): emove duplicate line from `org-roam--db-clear' (#267) 2020-03-10 15:35:34 +08:00
7f09c76baf (fix): allow org-roam-insert in Org-roam file indirect buffers (#266) 2020-03-10 10:57:49 +08:00
f6e75f995a (chore): cleanup buffer-file-name calls (#265)
buffer-file-name uses the current-buffer if the argument is not passed
2020-03-10 10:41:43 +08:00
6ba9ffe9c8 (fix): Error if org-roam-insert is not called from Org-roam file (#264) 2020-03-10 10:36:36 +08:00
5e0b7440a3 (feat): Allow function for org-roam-link-title-format (#261)
Addresses #255
2020-03-09 22:18:04 +08:00
d16d001b9e (feat): add optional initial-prompt to org-roam-find-file (#259) 2020-03-09 16:43:48 +08:00
f67e0b025a (docs): fix typo in vanilla installation (#254) 2020-03-08 20:49:17 +08:00
b836f9fc35 (bugfix): Don't query about SQL proccess on Emacs exit (#253)
Graceful shutdown is already guaranteed via `kill-emacs-hook`.

Refs #200

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-03-08 19:57:48 +08:00
e138056115 (docs): fix documentation for manual installation (#252) 2020-03-08 17:43:07 +08:00
63e0558d96 (chore): Cleanups for MELPA release (#251)
* (chore): require minimum Org version 9.3

* fix bytecompile errors for org-roam.el

* fix checkdoc errors

* fix more things
2020-03-08 15:58:13 +08:00
3fccaef967 (chore): change main branch to master (#250) 2020-03-08 15:05:57 +08:00
6eb7238daf (feature): add org-roam-backlink face (#247) 2020-03-08 14:54:56 +08:00
fc79901682 (chore): drop org-roam-filename-noconfirm (#248)
With org-capture integration, it does not seem to be used anymore.
2020-03-08 11:15:41 +08:00
46afa483a9 (docs): add documentation for exporting backlinks in Org file (#244)
h.t. @jdiez17
2020-03-07 23:49:43 +08:00
f63f29ac05 (docs): Add link to slack invite (#242) 2020-03-07 15:05:16 +08:00
e357693297 (release): v1.1.0-rc1 (#238) 2020-03-06 20:39:28 +08:00
b7afb02015 (chore): Cleanup for MELPA release (#236) 2020-03-06 20:15:33 +08:00
4c6e4df474 (fix): fix org-roam-today date functionality overriding old files (#235) 2020-03-06 19:35:22 +08:00
b1e2209dfc (feature): org-roam-graph-exclude-matcher: exclude nodes from graph (#233) 2020-03-06 12:48:30 +08:00
8f83ffc2a3 org-roam-show-graph: PREFIX to generate a graph but not display it (#232)
This lets the viewer application watch the file, or have the user manually refresh the view rather than opening a new browser tab.
2020-03-06 11:22:39 +08:00
09a23c377b (fix): remove nonspacing marks from slugs (#230)
Linux and macOS use different Unicode normalization conventions in filenames
2020-03-06 01:47:22 +08:00
d1a47e090e (docs): update docs (#229) 2020-03-06 00:19:11 +08:00
7d1dd831db (fix): relative links should work from org-roam-buffer with multidir (#228) 2020-03-05 13:53:53 +08:00
c77c1b7316 (docs): add more org-protocol instructions for MacOS (#227) 2020-03-05 12:53:57 +08:00
55d7edd5ee (docs): fix org-roam-protocol docs formatting (#226) 2020-03-05 12:07:15 +08:00
1f02b0c5dd (docs): update org-protocol installation for MacOS (#225) 2020-03-05 11:51:28 +08:00
d96ae119ab (bugfix): remove interactive from org-roam-capture (#224) 2020-03-05 11:27:05 +08:00
b7a7741bb0 (feature): use org-capture templates (#216)
Instead of implementing our own templating system, we abuse org-capture's templating system. We add 2 additional properties:

- :head: a starting template that goes at the beginning of the file.
- :file-name: a string that expands to the file name

The templates are customizable at `org-roam-capture-templates` and `org-roam-ref-capture-templates`.
2020-03-05 00:21:24 +08:00
4de88b3c4f (bugfix): use "org-roam" as graphname (#221)
The graphname is displayed as tooltip when hovering over non-node
areas in the SVG viewer.

When grahname is undefined Chrome and Firefox just displays
"%3" (ETX/End of Text).
2020-03-03 21:28:08 +08:00
b74cc14377 (feature): add org-roam-yesterday (#215)
Closes #214
2020-03-02 02:53:53 +08:00
4c3d5b90a7 (docs): add Doom Emacs installation instructions (#212) 2020-03-01 23:56:05 +08:00
f98e7d22a5 (chore): cleanup and re-order code (#213) 2020-03-01 15:36:39 +08:00
a03ad54460 (bugfix): fix org-roam-delete-file-advice triggering on non-org-roam files (#211)
Adding a predicate for the delete-file advice ensures that expensive
SQL operations do not run when not necessary
2020-03-01 02:42:55 +08:00
a88076a704 (fix): build org-roam cache on org-roam-mode (#210)
`org-roam-build-cache` takes very little time, when the cache is
already built running it on `org-roam-mode` ensures that the cache is
consistent with the files.
2020-03-01 02:35:01 +08:00
9296470d17 (bugfix): populate database after org-roam--make-new-file (#208) 2020-03-01 01:58:54 +08:00
4da30a7134 (bugfix): escape strings for graph export (#207)
strings with quotes used to break the graph export. This change escapes the strings.
2020-03-01 01:08:54 +08:00
150ae65564 (feature): deprecate roam-protocol, extend org-protocol instead (#203)
Add 2 custom handlers:

1. roam-file?file=path: this simply opens the file at path in Emacs.
2. roam-ref?ref=ref&template=roam-template&title=title&...: attempts to open a roam note with a given ROAM_KEY. If the note doesn't exist, create one. Else, open it.
2020-02-29 22:09:04 +08:00
0c2aaad3df (feature): use sqlite as backing database (#200)
All org-roam related information will now be stored in the database. Henceforth, the cache needs to be built synchronously once (via `M-x org-roam-build-cache`), which is then incrementally updated.
2020-02-29 15:56:08 +08:00
d086d1675d (fix): change locals to hash tables (#196)
better support emacs 25
2020-02-27 10:34:54 +08:00
685aa2afcd Ensure cache consistency for refs cache (#194) 2020-02-26 23:04:02 +08:00
92d25b287e (feature): add a cache for ROAM_KEY (#192) 2020-02-26 22:26:02 +08:00
962ef23cce (fix): Require a minimum version of Org 9.2 for roam link styling (#190) 2020-02-26 16:29:20 +08:00
5e76c67cf6 (feature): emacs-lisp handling for roam:// links (#188)
We emulate org-protocol, and advise server-find-files, stripping the
roam protocol from the filename. This reduces the setup required to
open `roam://` links.
2020-02-26 15:35:20 +08:00
b382b1f21a (docs): add documentation for multiple org-roam directories (#187) 2020-02-26 15:23:29 +08:00
f1fb9f4680 (docs): remove :after from package install (#186)
Some of org-roam's functions (e.g. org-roam-today and
org-roam-find-file) should not need to have org loaded before use.
2020-02-26 11:00:24 +08:00
5b96cf806f (docs): Add documentation for #+ROAM_ALIAS attribute (#185) 2020-02-26 01:33:49 +08:00
a8d696e6e8 (performance): avoid path expansion by referencing cache obj (#184)
Prevent needless repeated calls to org-roam-directory-normalized by having a
reference to the cache object that matches the local buffer.

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2020-02-26 00:15:38 +08:00
19f16e9c64 (feature): support file aliases (#182)
Closes #91
2020-02-26 00:11:38 +08:00
4b38b07c41 (feature): fix org-roam-open-at-point (#183) 2020-02-25 23:09:37 +08:00
b4d89c6a0c (feature): allow multiple org-roam directories (#178)
Each org-roam-directory gets its own cache. One can override the `org-roam-directory` variable locally via dir-locals:

((org-mode . ((eval . (setq-local org-roam-directory (expand-file-name "./"))))))
2020-02-25 23:06:40 +08:00
d780b6ffd1 (chore): require minimum org version of 9.0 (#177) 2020-02-24 18:58:03 +08:00
5f6ff4282c (docs): fix broken markdown src block (#176) 2020-02-24 17:08:29 +08:00
a0559a2709 (docs): add note about removing title timestamps in configuration.md (#175) 2020-02-24 14:55:07 +08:00
de1ac9d5cc Fix typo in tour.md (#172) 2020-02-24 10:28:16 +08:00
b2dc9b33f6 (bugfix): fix new file template default case (#169)
ref #165

Without this change I am getting the error:

    org-roam--make-new-file: Symbol’s function definition is void: file-name-fn
2020-02-23 22:54:59 +08:00
f9a903f52d add changelog entry for #165 (#168) 2020-02-23 17:16:57 +08:00
c54c206694 (feature) add templating functionality via org-roam-template (#165)
This allows users to customize the filename, and the content of the template.
2020-02-23 17:11:49 +08:00
d2843b816f (bugfix): keep unicode alphanumerics in filename (#164)
Ref #158

Example output:
    (mapcar #'org-roam--title-to-slug
            '("!!!!Org-Roam is great!!!!"
              "Sobre a formação dos planetas"
              "1\\2.3///**"
              "10-2+3=45"))
    ;; ("org_roam_is_great" "sobre_a_formação_dos_planetas" "1_2_3" "10_2_3_45")
2020-02-23 00:53:16 +08:00
c2c25f7d83 (bugfix): Use correct padding for modeline lighter (#163) 2020-02-22 21:40:29 +08:00
cba79b941a (feature): add custom font styling for org-roam links (#162)
* (feature): add custom font styling for org-roam links

This adds 'org-roam-link-face. When org-roam-mode is on, all roam
links take this face. By default, it is exactly the same as 'org-link,
and would require styling.

* update docs
2020-02-22 21:11:14 +08:00
a2a858a0fe (bugfix): Check future status to prevent multiple async tasks (#160)
Prevents that the `org-roam--build-cache-async` process is blocked forever if an async
error occurs.

Refs #149, #151
2020-02-22 16:56:45 +08:00
43ff60fec7 (feature): add org-roam-mute-cache-build to mute cache build message (#159) 2020-02-22 11:29:34 +08:00
fe3f0e3b6c (docs): documentation on how to enable Chrome external app checkbox on Linux (#157)
* Enable Chrome external app checkbox on Linux

* Fix command to write file
2020-02-22 11:12:33 +08:00
d02d48e559 (bugfix): prevent multiple async build processes (#149)
Prevent multiple async cache builds.  This can happen when restoring a session
or loading multiple org-roam files before a build has completed.
2020-02-21 15:45:54 +08:00
22f596d275 (feature): update org-roam-insert behaviour on region-selection (#148)
`org-roam-insert` now uses active region to pre-populate insert completion, and as the link description

fixes #127
2020-02-21 14:44:43 +08:00
68 changed files with 6866 additions and 1588 deletions

4
.dir-locals.el Normal file
View 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
View 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']

View File

@ -1,14 +1,15 @@
---
name: Bug Report
about: Something's not working.
title: ''
labels: ''
assignees: 'jethrokuan'
title: ""
labels: ""
assignees: ""
---
### Description
#### Steps to Reproduce
<!--
Example:
@ -18,13 +19,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

View File

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

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

@ -0,0 +1,31 @@
# * docs.yml --- Build the documentation and publish to Github Pages
name: "Docs"
on:
push:
branches:
- 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
View 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'

View File

@ -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
View File

@ -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/

View File

@ -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: -->

View File

@ -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

View File

@ -1,50 +1,57 @@
[![License GPL 3][badge-license]](http://www.gnu.org/licenses/gpl-3.0.txt)
[![Documentation Status](https://readthedocs.org/projects/org-roam/badge/?version=latest)](https://org-roam.readthedocs.io/en/latest/?badge=latest)
[![GitHub Release](https://img.shields.io/github/v/release/jethrokuan/org-roam)](https://img.shields.io/github/v/release/jethrokuan/org-roam)
[![GitHub Release](https://img.shields.io/github/v/release/org-roam/org-roam)](https://img.shields.io/github/v/release/org-roam/org-roam)
[![MELPA](https://melpa.org/packages/org-roam-badge.svg)](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.
[![Making Connections in your Notes](http://img.youtube.com/vi/Lg61ocfxk3c/0.jpg)](http://www.youtube.com/watch?v=Lg61ocfxk3c "Making Connections in your Notes")
As of February 2020, it is in a very early stage of development.
Important links:
- **[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.
![img](doc/images/org-roam-graph.gif)
## 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
View 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
View File

37
doc/AUTHORS.md Normal file
View File

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

130
doc/Makefile Normal file
View 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
View 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;
}

View File

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

View File

@ -1,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")
```

View File

@ -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:
![org-download](images/org-download.gif)
```emacs-lisp
(use-package org-download
:after org
:bind
(:map org-mode-map
(("s-Y" . org-download-screenshot)
("s-y" . org-download-yank))))
```
### mathpix.el
[mathpix.el][mathpix-el] uses [Mathpix's](https://mathpix.com/) API to convert clips into
latex equations:
![mathpix](images/mathpix.gif)
```emacs-lisp
(use-package mathpix.el
:straight (:host github :repo "jethrokuan/mathpix.el")
:custom ((mathpix-app-id "app-id")
(mathpix-app-key "app-key"))
:bind
("C-x m" . mathpix-screenshot))
```
### Org-noter / Interleave
[Org-noter][org-noter] and [Interleave][interleave] are both projects
that allow synchronised annotation of documents (PDF, EPUB etc.)
within Org-mode.
### Org-ref
[Org-ref][org-ref] does citation and bibliography management in
Org-mode, and a great tool for scientific notes.
[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

View File

@ -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
View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

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
View File

@ -0,0 +1,3 @@
<html>
<h1>--> <a href="manual/index.html">MANUAL HERE</a> <--</h1>
</html>

View File

@ -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/

View File

@ -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.

View File

@ -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
View 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 users 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 buffers 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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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.
![org-roam-find-file](images/org-roam-find-file.gif)
## 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.
![org-roam-insert](images/org-roam-insert-filetag.gif)
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.
![org-roam-buffer](images/org-roam-buffer.gif)
## 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.
![org-roam-graph](images/org-roam-graph.gif)
[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/

View File

@ -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
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

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

3
tests/roam-files/bar.org Normal file
View File

@ -0,0 +1,3 @@
#+TITLE: Bar
This is file bar. Bar links to [[file:nested/bar.org][Nested Bar]].

View File

@ -0,0 +1 @@
#+TITLE: Base

View File

@ -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

View File

@ -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
View 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]]

View 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]].

View File

@ -0,0 +1 @@
#+TITLE: Deeply Nested File

View File

@ -1,4 +0,0 @@
#+TITLE: Nested File 1
Link to [[file:f2.org][Nested File 2]]
Link to [[file:../f1.org][File 1]]

View File

@ -1,3 +0,0 @@
#+TITLE: Nested File 2
Link to [[file:f1.org][Nested File 1]]

View File

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

View File

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

View File

@ -0,0 +1,3 @@
#+TITLE: Tagless File
This file has no tags, and should not yield any tags on extracting via =#+ROAM_TAGS=.

View 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)=

View File

@ -0,0 +1 @@
#+ROAM_ALIAS: "roam" "alias"

View File

@ -0,0 +1,4 @@
#+TITLE: TITLE PROP
#+ROAM_ALIAS: "roam" "alias"
* Headline

View File

@ -0,0 +1 @@
* Headline

View File

@ -0,0 +1 @@
#+TITLE: Title

View File

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

View File

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

View File

@ -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"
(xdescribe "org-roam-db-build-cache"
(before-each
(test-org-roam--init))
(after-each
(test-org-roam--teardown))
(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)
;; 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)
(org-roam--build-cache-async)
(sleep-for 3) ;; Because it's async
;; 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)
;; 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)
;; 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"))))
;; 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"))))
(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")))
(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))
;; 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))))
;; 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))
;; 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)))
(describe "org-roam-insert"
(xdescribe "org-roam-insert"
(before-each
(org-roam--test-init)
(org-roam--clear-cache)
(org-roam--test-build-cache))
(test-org-roam--init))
(it "temp1 -> f1"
(let ((buf (org-roam--test-find-new-file "temp1.org")))
(after-each
(test-org-roam--teardown))
(it "temp1 -> foo"
(let ((buf (test-org-roam--find-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")))
"Foo RET"
(org-roam-insert))))
(expect (buffer-string) :to-match (regexp-quote "file:foo.org")))
(it "temp2 -> nested/f1"
(let ((buf (org-roam--test-find-new-file "temp2.org")))
(it "temp2 -> nested/foo"
(let ((buf (test-org-roam--find-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")))
"(nested) SPC Nested SPC Foo RET"
(org-roam-insert))))
(expect (buffer-string) :to-match (regexp-quote "file:nested/foo.org")))
(it "nested/temp3 -> f1"
(let ((buf (org-roam--test-find-new-file "nested/temp3.org")))
(it "nested/temp3 -> foo"
(let ((buf (test-org-roam--find-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")))
"Foo RET"
(org-roam-insert))))
(expect (buffer-string) :to-match (regexp-quote "file:../foo.org")))
(it "a/b/temp4 -> nested/f1"
(let ((buf (org-roam--test-find-new-file "a/b/temp4.org")))
(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 File SPC 1 RET"
(org-roam-insert nil))))
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/f1.org"))))
"(nested) SPC Nested SPC Foo RET"
(org-roam-insert))))
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/foo.org"))))
(describe "rename file updates cache"
(xdescribe "rename file updates cache"
(before-each
(org-roam--test-init)
(org-roam--clear-cache)
(org-roam--test-build-cache))
(test-org-roam--init))
(it "f1 -> new_f1"
(rename-file (abs-path "f1.org")
(abs-path "new_f1.org"))
(after-each
(test-org-roam--teardown))
(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 (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)
(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 "new_f1.org"))) :not :to-be nil)
;; 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"))))
(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]]")))
(insert-file-contents (test-org-roam--abs-path "nested/bar.org"))
(buffer-string))
:to-match
(regexp-quote "[[file:../new_foo.org][Foo]]")))
(it "f1 -> f1 with spaces"
(rename-file (abs-path "f1.org")
(abs-path "f1 with spaces.org"))
(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 (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)
(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 "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"))))
;; 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]]")))
(insert-file-contents (test-org-roam--abs-path "nested/bar.org"))
(buffer-string))
:to-match
(regexp-quote "[[file:../foo with spaces.org][Foo]]")))
(it "no-title -> meaningful-title"
(rename-file (abs-path "no-title.org")
(abs-path "meaningful-title.org"))
(rename-file (test-org-roam--abs-path "no-title.org")
(test-org-roam--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)
(expect (->> org-roam-forward-links-cache
(gethash (abs-path "f3.org"))
(member (abs-path "no-title.org"))) :to-be nil)
(expect (->> org-roam-forward-links-cache
(gethash (abs-path "f3.org"))
(member (abs-path "meaningful-title.org"))) :not :to-be nil)
(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)
;; 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]]"))))
(insert-file-contents (test-org-roam--abs-path "meaningful-title.org"))
(buffer-string))
:to-match
(regexp-quote "[[file:meaningful-title.org][meaningful-title]]")))
(describe "delete file updates cache"
(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
(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)))
(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