mirror of
https://github.com/org-roam/org-roam
synced 2025-08-01 12:17:21 -05:00
Compare commits
71 Commits
Author | SHA1 | Date | |
---|---|---|---|
89e9121f26 | |||
c536fd4f2e | |||
20f876aa6b | |||
863ae2427e | |||
379d5e4770 | |||
4d992ce9e3 | |||
1d9968bf69 | |||
650744adc7 | |||
d099f9bef9 | |||
b5f3f04318 | |||
c20c8f9a0a | |||
c24fb51b03 | |||
80390b5a84 | |||
eb7ee0ef6c | |||
fb5beeb14d | |||
10e91a88c1 | |||
4cdab9103f | |||
4ec4e60358 | |||
7a4b15fd36 | |||
f9fea29c44 | |||
569aeb84ed | |||
1574e0d351 | |||
fffef6711f | |||
ef23f507ec | |||
f1dbe3fdf9 | |||
efba3c2bf0 | |||
6770c3eaf5 | |||
b8aa5c1f23 | |||
ca4a7421bc | |||
3348298527 | |||
d77f897400 | |||
9f7ed4353c | |||
d19a711a44 | |||
9766862e84 | |||
aedfca8de2 | |||
21bc220ed3 | |||
d58fc31dfb | |||
64a0bfd168 | |||
3aff6b2be7 | |||
7f56df7f4d | |||
0830da4504 | |||
3a1c826aa0 | |||
1e11a3a16f | |||
e33c3bcb3f | |||
610d4ced85 | |||
2f13d1fe64 | |||
ee28b5e6b1 | |||
79c75ac174 | |||
c59d6c4f7c | |||
220f395c1f | |||
76b2ac3460 | |||
11e0aa4c55 | |||
408e38f8ba | |||
f16de357a6 | |||
abd81918e1 | |||
6a37fff1e6 | |||
527c693f65 | |||
76d419cc89 | |||
3f2f7e3ff7 | |||
fd73da9410 | |||
11902bc790 | |||
185f9877ae | |||
1276e801c0 | |||
04d335cc40 | |||
8b16e5d520 | |||
7ab67436a7 | |||
87403b330c | |||
fae45434b5 | |||
9cf26494e8 | |||
0d5efe1c14 | |||
2eb0aac88a |
@ -3,4 +3,4 @@
|
||||
|
||||
((emacs-lisp-mode
|
||||
(eval . (require 'org-roam-dev))
|
||||
(sentence-end-double-space . nil)))
|
||||
(eval . (org-roam-dev-mode))))
|
||||
|
@ -3,3 +3,6 @@
|
||||
Many thanks to the following backers, your contributions are greatly appreciated!
|
||||
|
||||
- Nathan Tran
|
||||
- Burke Libbey
|
||||
- forkrul
|
||||
- Andreas Stuhlmüller
|
||||
|
33
CHANGELOG.md
33
CHANGELOG.md
@ -1,5 +1,36 @@
|
||||
# Changelog
|
||||
|
||||
## 1.2.1 (27-07-2020)
|
||||
|
||||
This release consisted of a big deal of refactoring and bug fixes. Notably, we fixed several catastrophic failures on db builds with bad setups (#854), and modularized tag and title extractions.
|
||||
|
||||
We also added some new features that had been a long time coming:
|
||||
|
||||
1. We made the backlinks more outline-friendly by also showing the outline hierarchy for a backlink (#863)
|
||||
2. We now support nested captures, which is crucial for `org-roam-protocol` (#966)
|
||||
|
||||
### Breaking Changes
|
||||
- [#908](https://github.com/org-roam/org-roam/pull/908) Normalized titles in database. May break external packages that rely on unnormalized titles.
|
||||
|
||||
### Features
|
||||
- [#814](https://github.com/org-roam/org-roam/pull/814) Implement `org-roam-insert-immediate`
|
||||
- [#833](https://github.com/org-roam/org-roam/pull/833) Add customization of file titles with `org-roam-title-to-slug-function`.
|
||||
- [#839](https://github.com/org-roam/org-roam/pull/839) Return selected file from `org-roam-insert`
|
||||
- [#847](https://github.com/org-roam/org-roam/pull/847) Add GC threshold `org-roam-db-gc-threshold` to temporarily change the threshold on expensive operations.
|
||||
- [#847](https://github.com/org-roam/org-roam/pull/847) Use sqlite3 transactions instead of storing the values to be inserted.
|
||||
- [#851](https://github.com/org-roam/org-roam/pull/851) Add `'first-directory'` option for `org-roam-tag-sources`
|
||||
- [#863](https://github.com/org-roam/org-roam/pull/863) Display outline hierarchy in backlinks buffer
|
||||
- [#898](https://github.com/org-roam/org-roam/pull/898) Add `org-roam-random-note` to browse a random note.
|
||||
- [#900](https://github.com/org-roam/org-roam/pull/900) Support and index all valid org links
|
||||
- [#966](https://github.com/org-roam/org-roam/pull/966) Enable nested captures
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#854](https://github.com/org-roam/org-roam/pull/854) Warn instead of fail when duplicate refs and IDs exist.
|
||||
- [#857](https://github.com/org-roam/org-roam/pull/857) Fix tag extraction for symlinked directories.
|
||||
- [#894](https://github.com/org-roam/org-roam/pull/894) Perform link fixes on all Org-roam files
|
||||
- [#952](https://github.com/org-roam/org-roam/pull/952) Cache `${foo}` template variables so they do not need to be re-entered twice
|
||||
|
||||
## 1.2.0 (12-06-2020)
|
||||
|
||||
In this release, we improved the linking process by achieving feature parity between links to files and links to headlines. Before, we used the `file:foo::*bar` format to link to the headline `bar` in file `foo`, but this was prone to breakage upon renaming the file or modifying the headline. This is not the case anymore. Now, we use `org-id` to create IDs for those headlines, which are then stored in our database to compute the relationships and jump around. Note that this will work even if you’re not using `org-id` in your global configuration for Org-mode.
|
||||
@ -32,7 +63,7 @@ We also add `org-roam-unlinked-references`, which naively finds text that could
|
||||
In this release, we added two new features:
|
||||
|
||||
1. `org-roam-doctor`: a linting system that helps you discover possible problems with your Org-roam files. This is in the spirit of keeping notes in top quality.
|
||||
2. A tagging system: one can now use sub-directories, and the `#+roam_tags` key add additional meta data to notes. For more information, see [here](https://org-roam.github.io/org-roam/manual/Tags.html#Tags).
|
||||
2. A tagging system: one can now use sub-directories, and the `#+roam_tags` key add additional meta data to notes. For more information, see [here](https://www.orgroam.com/manual/Tags.html#Tags).
|
||||
|
||||
As usual, this release comes with a multitude of bug-fixes and refactorings.
|
||||
|
||||
|
28
README.md
28
README.md
@ -50,6 +50,7 @@ Here's a sample configuration with using `use-package`:
|
||||
|
||||
```emacs-lisp
|
||||
(use-package org-roam
|
||||
:ensure t
|
||||
:hook
|
||||
(after-init . org-roam-mode)
|
||||
:custom
|
||||
@ -57,9 +58,10 @@ Here's a sample configuration with using `use-package`:
|
||||
: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))
|
||||
("C-c n g" . org-roam-graph-show))
|
||||
:map org-mode-map
|
||||
(("C-c n i" . org-roam-insert))))
|
||||
(("C-c n i" . org-roam-insert))
|
||||
(("C-c n I" . org-roam-insert-immediate))))
|
||||
```
|
||||
|
||||
`org-roam-graph` by default expects to find the `dot` executable
|
||||
@ -72,6 +74,25 @@ For more detailed installation and configuration instructions (including for
|
||||
Doom and Spacemacs users), please see [the
|
||||
documentation][docs].
|
||||
|
||||
## Frequently-asked Questions
|
||||
|
||||
Q: How do I create a note whose title already matches one of the candidates (e.g. creating `bar` when `barricade` already exists)?
|
||||
|
||||
A: With `ivy`, you need to press `C-M-j` to use the current input instead of the nearest candidate. (Source: [`ivy`’s
|
||||
FAQ](https://github.com/abo-abo/swiper#frequently-asked-questions))
|
||||
|
||||
## Getting Help
|
||||
|
||||
Before creating a new topic/issue, please be mindful of our time and ensure
|
||||
that it has not already been addressed on
|
||||
[GitHub][issues] or on
|
||||
[Discourse][discourse].
|
||||
|
||||
- If you are new to Emacs and have problem setting up Org-roam, please ask your question on [Slack, channel #how-do-i][slack].
|
||||
- For quick questions, please ask them on [Slack, channel #troubleshooting][slack].
|
||||
- If something is not working as it should, or if you would like to suggest a new feature, please [create a new issue][issues].
|
||||
- If you have questions about your workflow with the slip-box method, please find a relevant topic on [Discourse][discourse], or create a new one.
|
||||
|
||||
## Knowledge Bases using Org-roam
|
||||
|
||||
- [Jethro Kuan](https://braindump.jethro.dev/)
|
||||
@ -95,6 +116,7 @@ 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/
|
||||
[docs]: https://www.orgroam.com/manual/
|
||||
[discourse]: https://org-roam.discourse.group/
|
||||
[slack]: https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg
|
||||
[issues]: https://github.com/org-roam/org-roam/issues
|
||||
|
572
doc/img/logo.svg
Normal file
572
doc/img/logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 42 KiB |
@ -93,7 +93,7 @@
|
||||
You can find us on Discourse and Slack.
|
||||
|
||||
<ul>
|
||||
<li>Read our documentation within Emacs, or on the <a href="https://org-roam.github.io/org-roam/manual/">Online Manual</a></li>
|
||||
<li>Read our documentation within Emacs, or on the <a href="https://www.orgroam.com/manual/">Online Manual</a></li>
|
||||
<li>Participate in our forum discussions on <a href="https://org-roam.discourse.group">Discourse</a></li>
|
||||
<li>Chat with us on <a href="https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg">Slack</a></li>
|
||||
</ul>
|
||||
|
410
doc/org-roam.org
410
doc/org-roam.org
@ -8,13 +8,13 @@
|
||||
#+texinfo_dir_category: Emacs
|
||||
#+texinfo_dir_title: Org-roam: (org-roam).
|
||||
#+texinfo_dir_desc: Rudimentary Roam Replica for Emacs.
|
||||
#+subtitle: for version 1.2.0
|
||||
#+subtitle: for version 1.2.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.2.0.
|
||||
This manual is for Org-roam version 1.2.1.
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||
@ -152,6 +152,17 @@ using:
|
||||
|
||||
Now see [[*Post-Installation Tasks][Post-Installation Tasks]].
|
||||
|
||||
** Installing from Apt
|
||||
|
||||
Users of Debian 11 or later or Ubuntu 20.10 or later can simply install Org-roam
|
||||
using Apt:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
apt-get install elpa-org-roam
|
||||
#+END_SRC
|
||||
|
||||
Org-roam will then be autoloaded into Emacs.
|
||||
|
||||
** TODO Installing from the Git Repository
|
||||
|
||||
** Post-Installation Tasks
|
||||
@ -185,9 +196,11 @@ 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=:
|
||||
To first start using Org-roam, one needs to pick a location to store the
|
||||
Org-roam files. The directory that will contain your notes, and database index
|
||||
is specified by the variable ~org-roam-directory~. This variable needs to be set
|
||||
before any calls to Org-roam functions, including enabling ~org-roam-mode~. For
|
||||
this tutorial, create an empty directory, and set ~org-roam-directory~:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(make-directory "~/org-roam")
|
||||
@ -196,34 +209,34 @@ containing your notes. For this tutorial, create an empty directory, and set the
|
||||
|
||||
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.
|
||||
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
|
||||
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:
|
||||
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.
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -232,7 +245,7 @@ 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=.
|
||||
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
|
||||
@ -255,13 +268,13 @@ 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
|
||||
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.
|
||||
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:
|
||||
@ -275,19 +288,19 @@ Take for example the following org file:
|
||||
|
||||
| Method | Titles |
|
||||
|-------------+--------------------------|
|
||||
| ='title= | '("World War 2") |
|
||||
| ='headline= | '("Headline") |
|
||||
| ='alias= | '("WWII" "World War II") |
|
||||
| ~'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
|
||||
~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.
|
||||
~'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
|
||||
|
||||
@ -295,29 +308,32 @@ 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
|
||||
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
|
||||
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=.
|
||||
~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~.
|
||||
4. ~'first-directory~: Extracts the first 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 ~foo~.
|
||||
|
||||
By default, only the ='prop= extraction method is enabled. To enable the other
|
||||
extraction methods, you may modify =org-roam-tag-sources=:
|
||||
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
|
||||
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.
|
||||
~org-roam--extract-tags-prop~ for an example.
|
||||
|
||||
** File Refs
|
||||
|
||||
@ -330,7 +346,7 @@ For example, a note for a website may contain a ref:
|
||||
#+END_SRC
|
||||
|
||||
These keys come in useful for when taking website notes, using the
|
||||
=roam-ref= protocol (see [[*Roam Protocol][Roam Protocol]]).
|
||||
~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:
|
||||
@ -346,8 +362,9 @@ The backlinks buffer will show any cites of this key: e.g.
|
||||
[[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:
|
||||
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
|
||||
@ -355,15 +372,17 @@ may be desirable to prefill the file with templated content. This may include:
|
||||
- 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=.
|
||||
powerful one: ~org-capture~ (see info:org#capture). However, org-capture was not
|
||||
designed for such use. Org-roam abuses ~org-capture~, extending its syntax and
|
||||
capabilities. 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=. Just like the base =org-capture= this variable can
|
||||
contain multiple templates, in which case you will be prompted on which one to
|
||||
use when capturing a new note.
|
||||
For these reasons, Org-roam capture templates are not compatible with regular
|
||||
~org-capture~. Hence, Org-roam's templates can be customized by instead
|
||||
modifying the variable ~org-roam-capture-templates~. Just like
|
||||
~org-capture-templates~, ~org-roam-capture-templates~ can contain multiple
|
||||
templates. If ~org-roam-capture-templates~ only contains one template, there
|
||||
will be no prompt for template selection.
|
||||
|
||||
** Template Walkthrough
|
||||
|
||||
@ -378,28 +397,28 @@ the default template, reproduced below.
|
||||
:unnarrowed t)
|
||||
#+END_SRC
|
||||
|
||||
1. The template has short key ="d"=. If you have only one template,
|
||||
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=.
|
||||
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
|
||||
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=. This template also
|
||||
~/path/to/org-roam-directory/20200213032037-foo.org~. This template also
|
||||
allows you to specify if you want the note to go into a subdirectory. For
|
||||
example, the template =private/${slug}= will create notes in
|
||||
=/path/to/org-roam-directory/private=.
|
||||
7. =:head= contains the initial template to be inserted (once only), at
|
||||
example, the template ~private/${slug}~ will create notes in
|
||||
~/path/to/org-roam-directory/private~.
|
||||
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
|
||||
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=.
|
||||
Other options you may want to learn about include ~:immediate-finish~.
|
||||
|
||||
** Org-roam Template Expansion
|
||||
|
||||
@ -407,26 +426,26 @@ 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
|
||||
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=.
|
||||
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=.
|
||||
~"%<%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=
|
||||
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
|
||||
@ -443,7 +462,7 @@ 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=.
|
||||
~M-x customize-group org-roam~.
|
||||
|
||||
** Directories and Files
|
||||
|
||||
@ -468,39 +487,39 @@ 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*=.
|
||||
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=.
|
||||
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=.
|
||||
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=.
|
||||
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=.
|
||||
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=.
|
||||
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"=.
|
||||
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.
|
||||
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
|
||||
|
||||
@ -515,27 +534,27 @@ 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=.
|
||||
~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
|
||||
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"=.
|
||||
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=.
|
||||
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
|
||||
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
|
||||
@ -551,7 +570,7 @@ 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=.
|
||||
The entry point to graph creation is ~org-roam-graph~.
|
||||
|
||||
- Function: org-roam-graph & optional arg file node-query
|
||||
|
||||
@ -559,18 +578,18 @@ The entry point to graph creation is =org-roam-graph=.
|
||||
If FILE is nil, default to current buffer’s file name.
|
||||
ARG may be any of the following values:
|
||||
|
||||
- =nil= show the graph.
|
||||
- =C-u= show the graph for FILE.
|
||||
- =C-u N= show the graph for FILE limiting nodes to N steps.
|
||||
- =C-u C-u= build the graph.
|
||||
- =C-u -= build the graph for FILE.
|
||||
- =C-u -N= build the graph for FILE limiting nodes to N steps.
|
||||
- ~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
|
||||
You may also choose to use ~neato~ in place of ~dot~, which generates a more
|
||||
compact graph layout.
|
||||
|
||||
- User Option: org-roam-graph-viewer
|
||||
@ -580,7 +599,16 @@ The entry point to graph creation is =org-roam-graph=.
|
||||
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.
|
||||
~nil~ uses ~view-file~ to view the graph.
|
||||
|
||||
If you are using WSL2 and would like to open the graph in Windows, you can use the second option to set the browser and network file path:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-roam-graph-viewer
|
||||
(lambda (file)
|
||||
(let ((org-roam-graph-viewer "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"))
|
||||
(org-roam-graph--open (concat "file://///wsl$/Ubuntu" file)))))
|
||||
#+END_SRC
|
||||
|
||||
** Graph Options
|
||||
|
||||
@ -589,22 +617,22 @@ Graphviz provides many options for customizing the graph output, and Org-roam su
|
||||
- User Option: org-roam-graph-extra-config
|
||||
|
||||
Extra options passed to graphviz for the digraph (The "G" attributes).
|
||||
Example: ='=(("rankdir" . "LR"))=
|
||||
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"))=
|
||||
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"))=
|
||||
Example: ~'(("dir" . "back"))~
|
||||
|
||||
- User Option: org-roam-graph-edge-cites-extra-config
|
||||
|
||||
Extra options for citation edges in the graphviz output.
|
||||
Example: ='(("color" . "red"))=
|
||||
Example: ~'(("color" . "red"))~
|
||||
|
||||
** Excluding Nodes and Edges
|
||||
|
||||
@ -628,26 +656,30 @@ 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,
|
||||
Org-roam allows customization of which minibuffer completion system to use for
|
||||
its interactive commands. The default setting uses Emacs' standard
|
||||
~completing-read~ mechanism.
|
||||
|
||||
#+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
|
||||
If you have installed Helm or Ivy, and have their modes enabled, under the
|
||||
~'default~ setting they will be used.
|
||||
|
||||
In the rare scenario where you use Ivy globally, but prefer [[https://emacs-helm.github.io/helm/][Helm]] for org-roam
|
||||
commands, set:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-roam-completion-system 'helm)
|
||||
#+END_SRC
|
||||
|
||||
Other options include ='ido=, and ='ivy=.
|
||||
Other options include ~'ido~, and ~'ivy~.
|
||||
|
||||
* Roam Protocol
|
||||
** _ :ignore:
|
||||
Org-roam extending =org-protocol= with 2 protocols: the =roam-file=
|
||||
and =roam-ref= protocol.
|
||||
Org-roam extending ~org-protocol~ with 2 protocols: the ~roam-file~
|
||||
and ~roam-ref~ protocol.
|
||||
|
||||
** Installation
|
||||
|
||||
@ -657,12 +689,12 @@ To enable Org-roam's protocol extensions, you have to add the following to your
|
||||
(require 'org-roam-protocol)
|
||||
#+END_SRC
|
||||
|
||||
The instructions for setting up =org-protocol== are reproduced below.
|
||||
The instructions for setting up ~org-protocol~ are reproduced below.
|
||||
|
||||
We will also need to create a desktop application for =emacsclient=. The
|
||||
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=:
|
||||
For Linux users, create a desktop application in ~~/.local/share/applications/org-protocol.desktop~:
|
||||
|
||||
#+begin_example
|
||||
[Desktop Entry]
|
||||
@ -674,7 +706,7 @@ Terminal=false
|
||||
MimeType=x-scheme-handler/org-protocol
|
||||
#+end_example
|
||||
|
||||
Associate =org-protocol://= links with the desktop application by
|
||||
Associate ~org-protocol://~ links with the desktop application by
|
||||
running in your shell:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
@ -682,7 +714,7 @@ 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
|
||||
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
|
||||
@ -698,8 +730,8 @@ sudo chmod 644 /etc/opt/chrome/policies/managed/external_protocol_dialog.json
|
||||
and then restart Chrome (for example, by navigating to <chrome://restart>) to
|
||||
make the new policy take effect.
|
||||
|
||||
See [[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.
|
||||
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:
|
||||
@ -710,7 +742,7 @@ setting up with Platypus and Chrome:
|
||||
brew cask install platypus
|
||||
#+END_SRC
|
||||
|
||||
2. Create a script =launch_emacs.sh=:
|
||||
2. Create a script ~launch_emacs.sh~:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
#!/usr/bin/env bash
|
||||
@ -731,7 +763,7 @@ brew cask install platypus
|
||||
#+end_example
|
||||
|
||||
|
||||
Inside =Settings=:
|
||||
Inside ~Settings~:
|
||||
|
||||
#+begin_example
|
||||
| Setting | Value |
|
||||
@ -742,7 +774,7 @@ Inside =Settings=:
|
||||
#+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
|
||||
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
|
||||
@ -751,7 +783,7 @@ defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -b
|
||||
|
||||
|
||||
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=
|
||||
handler for the URL scheme `org-protocol`. To make ~OrgProtocol.app~
|
||||
the default handler instead, run:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
@ -761,20 +793,41 @@ defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandle
|
||||
|
||||
Then restart your computer.
|
||||
|
||||
For Windows, create a temporary ~org-protocol.reg~ file:
|
||||
|
||||
** The =roam-file= protocol
|
||||
#+BEGIN_SRC text
|
||||
REGEDIT4
|
||||
|
||||
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
|
||||
[HKEY_CLASSES_ROOT\org-protocol]
|
||||
@="URL:Org Protocol"
|
||||
"URL Protocol"=""
|
||||
[HKEY_CLASSES_ROOT\org-protocol\shell]
|
||||
[HKEY_CLASSES_ROOT\org-protocol\shell\open]
|
||||
[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
|
||||
@="\"C:\\Windows\\System32\\wsl.exe\" emacsclient \"%1\""
|
||||
#+END_SRC
|
||||
|
||||
The above will forward the protocol to WSL. If you run Emacs natively on Windows, replace the last line with:
|
||||
|
||||
#+BEGIN_SRC text
|
||||
@="\"c:\\path\\to\\emacs\\bin\\emacsclientw.exe\" \"%1\""
|
||||
#+END_SRC
|
||||
|
||||
After executing the .reg file, the protocol is registered and you can delete the file.
|
||||
|
||||
** The roam-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
|
||||
** 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:
|
||||
To use this, create the following [[https://en.wikipedia.org/wiki/Bookmarklet][bookmarklet]] in your browser:
|
||||
|
||||
#+BEGIN_SRC javascript
|
||||
javascript:location.href =
|
||||
@ -788,7 +841,7 @@ or as a keybinding in ~qutebrowser~ in , using the ~config.py~ file (see
|
||||
[[https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc][Configuring qutebrowser]]):
|
||||
|
||||
#+BEGIN_SRC python
|
||||
config.bind("<Ctrl-r>", "spawn bash -c 'emacsclient \"org-protocol://roam-ref?template=r&ref={url:pretty}&title={title}\" '")
|
||||
config.bind("<Ctrl-r>", "open javascript:location.href='org-protocol://roam-ref?template=r&ref='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)")
|
||||
#+END_SRC
|
||||
|
||||
where ~template~ is the template key for a template in
|
||||
@ -801,15 +854,17 @@ should contain a ~#+roam_key: ${ref}~ in it.
|
||||
|
||||
Org-roam provides a utility for diagnosing and repairing problematic files via
|
||||
~org-roam-doctor~. By default, ~org-roam-doctor~ runs the check on the current
|
||||
Org-roam file. To run the check only for the current file, run =C-u M-x
|
||||
org-roam-doctor=, but note that this may take some time.
|
||||
Org-roam file. To run the check only for the current file, run ~C-u M-x
|
||||
org-roam-doctor~, but note that this may take some time.
|
||||
|
||||
- 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:
|
||||
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
|
||||
@ -820,14 +875,30 @@ The checks run are defined in =org-roam-doctor--checkers=. Each checker is an in
|
||||
("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
|
||||
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
|
||||
~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=.
|
||||
taken provided in ~:actions~.
|
||||
* Performance Optimization
|
||||
** TODO Profiling Key Operations
|
||||
** Garbage Collection
|
||||
|
||||
During the cache-build process, Org-roam generates a lot of in-memory
|
||||
data-structures (such as the Org file's AST), which are discarded after use. These structures are garbage collected at regular intervals (see [[info:elisp#Garbage Collection][info:elisp#Garbage Collection]]).
|
||||
|
||||
Org-roam provides the option ~org-roam-db-gc-threshold~ to temporarily change
|
||||
the threshold value for GC to be triggered during these memory-intensive
|
||||
operations. To reduce the number of garbage collection processes, one may set
|
||||
~org-roam-db-gc-threshold~ to a high value (such as ~most-positive-fixnum~):
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-roam-db-gc-threshold most-positive-fixnum)
|
||||
#+END_SRC
|
||||
|
||||
* _ Copying
|
||||
:PROPERTIES:
|
||||
:COPYING: t
|
||||
@ -862,15 +933,36 @@ General Public License for more details.
|
||||
- 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
|
||||
*** Browsing History with winner-mode
|
||||
|
||||
~winner-mode~ is a global minor mode that allows one to undo and redo changes in the window configuration. It is included with GNU Emacs since version 20.
|
||||
|
||||
~winner-mode~ can be used as a simple version of browser history for Org-roam. Each click through org-roam links (from both Org files and the backlinks buffer) causes changes in window configuration, which can be undone and redone using ~winner-mode~. To use ~winner-mode~, simply enable it, and bind the appropriate interactive functions:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(winner-mode +1)
|
||||
(define-key winner-mode-map (kbd "<M-left>") #'winner-undo)
|
||||
(define-key winner-mode-map (kbd "<M-right>") #'winner-redo)
|
||||
|
||||
#+END_SRC
|
||||
*** Versioning Notes
|
||||
|
||||
Since Org-roam notes are just plain text, it is trivial to track changes in your
|
||||
notes database using version control systems such as [[https://git-scm.com/][Git]]. Simply initialize
|
||||
~org-roam-directory~ as a Git repository, and commit your files at regular or
|
||||
appropriate intervals. [[https://magit.vc/][Magit]] is a great interface to Git within Emacs.
|
||||
|
||||
In addition, it may be useful to observe how a particular note has evolved, by
|
||||
looking at the file history. [[https://gitlab.com/pidu/git-timemachine][Git-timemachine]] allows you to visit historic
|
||||
versions of a tracked Org-roam note.
|
||||
|
||||
*** Full-text search interface with Deft
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: deft
|
||||
:END:
|
||||
|
||||
[[https://jblevins.org/projects/deft/][Deft]] provides a nice interface
|
||||
for browsing and filtering org-roam notes.
|
||||
[[https://jblevins.org/projects/deft/][Deft]] provides a nice interface for browsing and filtering org-roam notes.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package deft
|
||||
@ -885,7 +977,7 @@ for browsing and filtering org-roam notes.
|
||||
#+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
|
||||
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]]:
|
||||
|
||||
@ -925,7 +1017,7 @@ that uses an external search engine and indexer.
|
||||
:END:
|
||||
|
||||
[[https://github.com/bastibe/org-journal][Org-journal]] is a more
|
||||
powerful alternative to the simple function =org-roam-dailies-today=. It
|
||||
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.
|
||||
|
||||
@ -1004,8 +1096,8 @@ etc.) within Org-mode.
|
||||
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=.
|
||||
~org-roam~. This helps you manage your bibliographic notes under
|
||||
~org-roam~.
|
||||
|
||||
**** Spaced Repetition
|
||||
:PROPERTIES:
|
||||
@ -1019,11 +1111,11 @@ files. Other alternatives include [[https://orgmode.org/worg/org-contrib/org-dri
|
||||
** 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=.
|
||||
~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
|
||||
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
|
||||
@ -1031,7 +1123,7 @@ contain:
|
||||
#+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
|
||||
set of Org-roam files. Remember to run ~org-roam-db-build-cache~ from a
|
||||
file within that directory, at least once.
|
||||
|
||||
** How do I migrate from Roam Research?
|
||||
|
@ -31,7 +31,7 @@ General Public License for more details.
|
||||
@finalout
|
||||
@titlepage
|
||||
@title Org-roam User Manual
|
||||
@subtitle for version 1.2.0
|
||||
@subtitle for version 1.2.1
|
||||
@author Jethro Kuan
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
@ -46,7 +46,7 @@ General Public License for more details.
|
||||
|
||||
@noindent
|
||||
|
||||
This manual is for Org-roam version 1.2.0.
|
||||
This manual is for Org-roam version 1.2.1.
|
||||
|
||||
@quotation
|
||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@@gmail.com>
|
||||
@ -78,6 +78,7 @@ General Public License for more details.
|
||||
* Roam Protocol::
|
||||
* Daily Notes::
|
||||
* Diagnosing and Repairing Files::
|
||||
* Performance Optimization::
|
||||
* Appendix::
|
||||
* FAQ::
|
||||
|
||||
@ -87,6 +88,7 @@ General Public License for more details.
|
||||
Installation
|
||||
|
||||
* Installing from MELPA::
|
||||
* Installing from Apt::
|
||||
* Installing from the Git Repository::
|
||||
* Post-Installation Tasks::
|
||||
|
||||
@ -121,8 +123,13 @@ Roam Protocol
|
||||
|
||||
* _::
|
||||
* Installation: Installation (1).
|
||||
* The @samp{roam-file} protocol::
|
||||
* The @samp{roam-ref} Protocol::
|
||||
* The roam-file protocol::
|
||||
* The roam-ref protocol::
|
||||
|
||||
Performance Optimization
|
||||
|
||||
* Profiling Key Operations::
|
||||
* Garbage Collection::
|
||||
|
||||
Appendix
|
||||
|
||||
@ -131,7 +138,9 @@ Appendix
|
||||
|
||||
Ecosystem
|
||||
|
||||
* Deft::
|
||||
* Browsing History with winner-mode::
|
||||
* Versioning Notes::
|
||||
* Full-text search interface with Deft::
|
||||
* Org-journal::
|
||||
* Note-taking Add-ons::
|
||||
|
||||
@ -231,6 +240,7 @@ development repository.
|
||||
|
||||
@menu
|
||||
* Installing from MELPA::
|
||||
* Installing from Apt::
|
||||
* Installing from the Git Repository::
|
||||
* Post-Installation Tasks::
|
||||
@end menu
|
||||
@ -288,6 +298,18 @@ M-x package-install RET org-roam RET
|
||||
|
||||
Now see @ref{Post-Installation Tasks}.
|
||||
|
||||
@node Installing from Apt
|
||||
@section Installing from Apt
|
||||
|
||||
Users of Debian 11 or later or Ubuntu 20.10 or later can simply install Org-roam
|
||||
using Apt:
|
||||
|
||||
@example
|
||||
apt-get install elpa-org-roam
|
||||
@end example
|
||||
|
||||
Org-roam will then be autoloaded into Emacs.
|
||||
|
||||
@node Installing from the Git Repository
|
||||
@section @strong{TODO} Installing from the Git Repository
|
||||
|
||||
@ -324,9 +346,11 @@ 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 @ref{Note-taking Workflows}.
|
||||
|
||||
To begin using Org-roam, one should set the @samp{org-roam-directory} to the directory
|
||||
containing your notes. For this tutorial, create an empty directory, and set the
|
||||
@samp{org-roam-directory}:
|
||||
To first start using Org-roam, one needs to pick a location to store the
|
||||
Org-roam files. The directory that will contain your notes, and database index
|
||||
is specified by the variable @code{org-roam-directory}. This variable needs to be set
|
||||
before any calls to Org-roam functions, including enabling @code{org-roam-mode}. For
|
||||
this tutorial, create an empty directory, and set @code{org-roam-directory}:
|
||||
|
||||
@lisp
|
||||
(make-directory "~/org-roam")
|
||||
@ -335,34 +359,34 @@ containing your notes. For this tutorial, create an empty directory, and set the
|
||||
|
||||
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 @samp{org-roam-directory} for any notes.
|
||||
fine; Org-roam searches recursively within @code{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 @samp{org-roam-mode}. This sets up Emacs
|
||||
Next, we need to enable the global minor mode @code{org-roam-mode}. This sets up Emacs
|
||||
with several hooks, builds a cache and keeps it consistent. We recommend
|
||||
starting @samp{org-roam-mode} on startup:
|
||||
starting @code{org-roam-mode} on startup:
|
||||
|
||||
@lisp
|
||||
(add-hook 'after-init-hook 'org-roam-mode)
|
||||
@end lisp
|
||||
|
||||
To build the cache manually, one can run @samp{M-x org-roam-db-build-cache}. The cache
|
||||
is a sqlite database named @samp{org-roam.db}, which defaults to residing in the root
|
||||
@samp{org-roam-directory}. Cache builds may take a while the first time, but is often
|
||||
instantaneous in subsequent runs.
|
||||
To build the cache manually, one can run @code{M-x org-roam-db-build-cache}. The
|
||||
cache is a sqlite database named @code{org-roam.db}, which defaults to residing in
|
||||
the root @code{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 @samp{M-x org-roam-find-file}. This shows a list
|
||||
of titles for notes that reside in @samp{org-roam-directory}. It should show nothing
|
||||
Let us now create our first note. Call @code{M-x org-roam-find-file}. This shows a list
|
||||
of titles for notes that reside in @code{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 @samp{RET} should begin the note creation
|
||||
process. This process uses @samp{org-capture}'s templating system, and can be freely
|
||||
customized (see @ref{The Templating System}). Using the default template, pressing @samp{C-c
|
||||
C-c} finishes the note capture. Running @samp{M-x org-roam-find-file} again should show
|
||||
note you wish to create, and pressing @code{RET} should begin the note creation
|
||||
process. This process uses @code{org-capture}'s templating system, and can be freely
|
||||
customized (see @ref{The Templating System}). Using the default template, pressing @code{C-c
|
||||
C-c} finishes the note capture. Running @code{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 @samp{M-x org-roam-insert}. This brings up a prompt
|
||||
To link notes together, we call @code{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
|
||||
@ -371,7 +395,7 @@ 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 @samp{M-x org-roam}.
|
||||
the visibility of this buffer, call @code{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
|
||||
@ -402,17 +426,17 @@ 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 @samp{org-roam--extract-titles} to extract titles. It uses the
|
||||
variable @samp{org-roam-title-sources}, to control how the titles are extracted. The
|
||||
Org-roam calls @code{org-roam--extract-titles} to extract titles. It uses the
|
||||
variable @code{org-roam-title-sources}, to control how the titles are extracted. The
|
||||
title extraction methods supported are:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
@samp{'title}: This extracts the title using the file @samp{#+title} property
|
||||
@code{'title}: This extracts the title using the file @code{#+title} property
|
||||
@item
|
||||
@samp{'headline}: This extracts the title from the first headline in the Org file
|
||||
@code{'headline}: This extracts the title from the first headline in the Org file
|
||||
@item
|
||||
@samp{'alias}: This extracts a list of titles using the @samp{#+roam_alias} property.
|
||||
@code{'alias}: This extracts a list of titles using the @code{#+roam_alias} property.
|
||||
The aliases are space-delimited, and can be multi-worded using quotes
|
||||
@end enumerate
|
||||
|
||||
@ -428,23 +452,23 @@ Take for example the following org file:
|
||||
@multitable {aaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaa}
|
||||
@headitem Method
|
||||
@tab Titles
|
||||
@item @samp{'title}
|
||||
@item @code{'title}
|
||||
@tab '(``World War 2'')
|
||||
@item @samp{'headline}
|
||||
@item @code{'headline}
|
||||
@tab '(``Headline'')
|
||||
@item @samp{'alias}
|
||||
@item @code{'alias}
|
||||
@tab '(``WWII'' ``World War II'')
|
||||
@end multitable
|
||||
|
||||
One can freely control which extraction methods to use by customizing
|
||||
@samp{org-roam-title-sources}: see the doc-string for the variable for more
|
||||
@code{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
|
||||
@samp{'foo} into @samp{org-roam-title-sources}, and define a
|
||||
@samp{org-roam--extract-titles-foo} which accepts no arguments. See
|
||||
@samp{org-roam--extract-titles-title} for an example.
|
||||
@code{'foo} into @code{org-roam-title-sources}, and define a
|
||||
@code{org-roam--extract-titles-foo} which accepts no arguments. See
|
||||
@code{org-roam--extract-titles-title} for an example.
|
||||
|
||||
@node Tags
|
||||
@section Tags
|
||||
@ -453,34 +477,38 @@ 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 @samp{org-roam--extract-tags} to extract tags from files. It uses the
|
||||
variable @samp{org-roam-tag-sources}, to control how tags are extracted. The tag
|
||||
Org-roam calls @code{org-roam--extract-tags} to extract tags from files. It uses the
|
||||
variable @code{org-roam-tag-sources}, to control how tags are extracted. The tag
|
||||
extraction methods supported are:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
@samp{'prop}: This extracts tags from the @samp{#+roam_tags} property. Tags are space delimited, and can be multi-word using double quotes.
|
||||
@code{'prop}: This extracts tags from the @code{#+roam_tags} property. Tags are space delimited, and can be multi-word using double quotes.
|
||||
@item
|
||||
@samp{'all-directories}: All sub-directories relative to @samp{org-roam-directory} are
|
||||
@code{'all-directories}: All sub-directories relative to @code{org-roam-directory} are
|
||||
extracted as tags. That is, if a file is located at relative path
|
||||
@samp{foo/bar/file.org}, the file will have tags @samp{foo} and @samp{bar}.
|
||||
@code{foo/bar/file.org}, the file will have tags @code{foo} and @code{bar}.
|
||||
@item
|
||||
@samp{'last-directory}: Extracts the last directory relative to
|
||||
@samp{org-roam-directory} as the tag. That is, if a file is located at relative
|
||||
path @samp{foo/bar/file.org}, the file will have tag @samp{bar}.
|
||||
@code{'last-directory}: Extracts the last directory relative to
|
||||
@code{org-roam-directory} as the tag. That is, if a file is located at relative
|
||||
path @code{foo/bar/file.org}, the file will have tag @code{bar}.
|
||||
@item
|
||||
@code{'first-directory}: Extracts the first directory relative to
|
||||
@code{org-roam-directory} as the tag. That is, if a file is located at relative
|
||||
path @code{foo/bar/file.org}, the file will have tag @code{foo}.
|
||||
@end enumerate
|
||||
|
||||
By default, only the @samp{'prop} extraction method is enabled. To enable the other
|
||||
extraction methods, you may modify @samp{org-roam-tag-sources}:
|
||||
By default, only the @code{'prop} extraction method is enabled. To enable the other
|
||||
extraction methods, you may modify @code{org-roam-tag-sources}:
|
||||
|
||||
@lisp
|
||||
(setq org-roam-tag-sources '(prop last-directory))
|
||||
@end lisp
|
||||
|
||||
If you wish to add your own tag extraction method, you may push a symbol @samp{'foo}
|
||||
into @samp{org-roam-tag-sources}, and define a @samp{org-roam--extract-tags-foo} which
|
||||
If you wish to add your own tag extraction method, you may push a symbol @code{'foo}
|
||||
into @code{org-roam-tag-sources}, and define a @code{org-roam--extract-tags-foo} which
|
||||
accepts the absolute file path as its argument. See
|
||||
@samp{org-roam--extract-tags-prop} for an example.
|
||||
@code{org-roam--extract-tags-prop} for an example.
|
||||
|
||||
@node File Refs
|
||||
@section File Refs
|
||||
@ -494,7 +522,7 @@ For example, a note for a website may contain a ref:
|
||||
@end example
|
||||
|
||||
These keys come in useful for when taking website notes, using the
|
||||
@samp{roam-ref} protocol (see @ref{Roam Protocol}).
|
||||
@code{roam-ref} protocol (see @ref{Roam Protocol}).
|
||||
|
||||
Alternatively, add a ref for notes for a specific paper, using its
|
||||
@uref{https://github.com/jkitchin/org-ref, org-ref} citation key:
|
||||
@ -514,8 +542,9 @@ The backlinks buffer will show any cites of this key: e.g.
|
||||
@node The Templating System
|
||||
@chapter The Templating System
|
||||
|
||||
Rather than creating blank files on @samp{org-roam-insert} and @samp{org-roam-find-file}, it
|
||||
may be desirable to prefill the file with templated content. This may include:
|
||||
Rather than creating blank files on @code{org-roam-insert} and @code{org-roam-find-file},
|
||||
it may be desirable to prefill the file with templated content. This may
|
||||
include:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@ -529,15 +558,17 @@ Any other data you may want to input manually
|
||||
@end itemize
|
||||
|
||||
This requires a complex template insertion system. Fortunately, Org ships with a
|
||||
powerful one: @samp{org-capture}. However, org-capture was not designed for such use.
|
||||
Org-roam abuses @samp{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
|
||||
@samp{org-capture}.
|
||||
powerful one: @code{org-capture} (see @ref{capture,,,org,}). However, org-capture was not
|
||||
designed for such use. Org-roam abuses @code{org-capture}, extending its syntax and
|
||||
capabilities. To first understand how org-roam's templating system works, it may
|
||||
be useful to look into basic usage of @code{org-capture}.
|
||||
|
||||
Org-roam's templates can be customized by modifying the variable
|
||||
@samp{org-roam-capture-templates}. Just like the base @samp{org-capture} this variable can
|
||||
contain multiple templates, in which case you will be prompted on which one to
|
||||
use when capturing a new note.
|
||||
For these reasons, Org-roam capture templates are not compatible with regular
|
||||
@code{org-capture}. Hence, Org-roam's templates can be customized by instead
|
||||
modifying the variable @code{org-roam-capture-templates}. Just like
|
||||
@code{org-capture-templates}, @code{org-roam-capture-templates} can contain multiple
|
||||
templates. If @code{org-roam-capture-templates} only contains one template, there
|
||||
will be no prompt for template selection.
|
||||
|
||||
@menu
|
||||
* Template Walkthrough::
|
||||
@ -560,36 +591,36 @@ the default template, reproduced below.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
The template has short key @samp{"d"}. If you have only one template,
|
||||
The template has short key @code{"d"}. If you have only one template,
|
||||
org-roam automatically chooses this template for you.
|
||||
@item
|
||||
The template is given a description of @samp{"default"}.
|
||||
The template is given a description of @code{"default"}.
|
||||
@item
|
||||
@samp{plain} text is inserted. Other options include Org headings via
|
||||
@samp{entry}.
|
||||
@code{plain} text is inserted. Other options include Org headings via
|
||||
@code{entry}.
|
||||
@item
|
||||
@samp{(function org-roam--capture-get-point)} should not be changed.
|
||||
@code{(function org-roam--capture-get-point)} should not be changed.
|
||||
@item
|
||||
@samp{"%?"} is the template inserted on each call to @samp{org-roam-capture--capture}.
|
||||
@code{"%?"} is the template inserted on each call to @code{org-roam-capture--capture}.
|
||||
This template means don't insert any content, but place the cursor
|
||||
here.
|
||||
@item
|
||||
@samp{:file-name} is the file-name template for a new note, if it doesn't yet
|
||||
@code{: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
|
||||
@samp{/path/to/org-roam-directory/20200213032037-foo.org}. This template also
|
||||
@code{/path/to/org-roam-directory/20200213032037-foo.org}. This template also
|
||||
allows you to specify if you want the note to go into a subdirectory. For
|
||||
example, the template @samp{private/$@{slug@}} will create notes in
|
||||
@samp{/path/to/org-roam-directory/private}.
|
||||
example, the template @code{private/$@{slug@}} will create notes in
|
||||
@code{/path/to/org-roam-directory/private}.
|
||||
@item
|
||||
@samp{:head} contains the initial template to be inserted (once only), at
|
||||
@code{:head} contains the initial template to be inserted (once only), at
|
||||
the beginning of the file. Here, the title global attribute is
|
||||
inserted.
|
||||
@item
|
||||
@samp{:unnarrowed t} tells org-capture to show the contents for the whole
|
||||
@code{:unnarrowed t} tells org-capture to show the contents for the whole
|
||||
file, rather than narrowing to just the entry.
|
||||
@end enumerate
|
||||
|
||||
Other options you may want to learn about include @samp{:immediate-finish}.
|
||||
Other options you may want to learn about include @code{:immediate-finish}.
|
||||
|
||||
@node Org-roam Template Expansion
|
||||
@section Org-roam Template Expansion
|
||||
@ -598,26 +629,26 @@ 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 @ref{Template Walkthrough, , Template
|
||||
Walkthrough}.
|
||||
|
||||
In org-roam templates, the @samp{$@{var@}} syntax allows for the expansion of
|
||||
variables, stored in @samp{org-roam-capture--info}. For example, during
|
||||
@samp{org-roam-insert}, the user is prompted for a title. Upon entering a
|
||||
non-existent title, the @samp{title} key in @samp{org-roam-capture--info} is set to the
|
||||
provided title. @samp{$@{title@}} is then expanded into the provided title during the
|
||||
In org-roam templates, the @code{$@{var@}} syntax allows for the expansion of
|
||||
variables, stored in @code{org-roam-capture--info}. For example, during
|
||||
@code{org-roam-insert}, the user is prompted for a title. Upon entering a
|
||||
non-existent title, the @code{title} key in @code{org-roam-capture--info} is set to the
|
||||
provided title. @code{$@{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 @samp{completing-read}.
|
||||
values using @code{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 @uref{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:
|
||||
@samp{"%<%Y%m%d%H%M%S>-$@{title@}"}, with the title @samp{"Foo"}. The template is first
|
||||
expanded into @samp{%<%Y%m%d%H%M%S>-Foo}. Then org-capture expands @samp{%<%Y%m%d%H%M%S>}
|
||||
with timestamp: e.g. @samp{20200213032037-Foo}.
|
||||
@code{"%<%Y%m%d%H%M%S>-$@{title@}"}, with the title @code{"Foo"}. The template is first
|
||||
expanded into @code{%<%Y%m%d%H%M%S>-Foo}. Then org-capture expands @code{%<%Y%m%d%H%M%S>}
|
||||
with timestamp: e.g. @code{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 @samp{%(EXP)} template expansion to call @samp{format-time-string}
|
||||
advantage of org-mode's @code{%(EXP)} template expansion to call @code{format-time-string}
|
||||
directly to provide its third argument to specify UTC@.
|
||||
|
||||
@lisp
|
||||
@ -636,7 +667,7 @@ 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
|
||||
@samp{M-x customize-group org-roam}.
|
||||
@code{M-x customize-group org-roam}.
|
||||
|
||||
@menu
|
||||
* Directories and Files::
|
||||
@ -676,47 +707,47 @@ The Org-roam buffer displays backlinks for the currently active Org-roam note.
|
||||
@item
|
||||
User Option: org-roam-buffer
|
||||
|
||||
The name of the org-roam buffer. Defaults to @samp{*org-roam*}.
|
||||
The name of the org-roam buffer. Defaults to @code{*org-roam*}.
|
||||
|
||||
@item
|
||||
User Option: org-roam-buffer-position
|
||||
|
||||
The position of the Org-roam buffer side window. Valid values are @samp{'left},
|
||||
@samp{'right}, @samp{'top}, @samp{'bottom}.
|
||||
The position of the Org-roam buffer side window. Valid values are @code{'left},
|
||||
@code{'right}, @code{'top}, @code{'bottom}.
|
||||
|
||||
@item
|
||||
User Option: org-roam-buffer-width
|
||||
|
||||
Width of @samp{org-roam-buffer}. Has an effect only if @samp{org-roam-buffer-position} is
|
||||
@samp{'left} or @samp{'right}.
|
||||
Width of @code{org-roam-buffer}. Has an effect only if @code{org-roam-buffer-position} is
|
||||
@code{'left} or @code{'right}.
|
||||
|
||||
@item
|
||||
User Option: org-roam-buffer-height
|
||||
|
||||
Height of @samp{org-roam-buffer}. Has an effect only if @samp{org-roam-buffer-position} is
|
||||
@samp{'top} or @samp{'bottom}.
|
||||
Height of @code{org-roam-buffer}. Has an effect only if @code{org-roam-buffer-position} is
|
||||
@code{'top} or @code{'bottom}.
|
||||
|
||||
@item
|
||||
User Option: org-roam-buffer-no-delete-other-windows
|
||||
|
||||
The @samp{no-delete-window} parameter for the org-roam buffer. Setting it to @samp{'t} prevents the window from being deleted when calling @samp{delete-other-windows}.
|
||||
The @code{no-delete-window} parameter for the org-roam buffer. Setting it to @code{'t} prevents the window from being deleted when calling @code{delete-other-windows}.
|
||||
@end itemize
|
||||
|
||||
@node Org-roam Links
|
||||
@section Org-roam Links
|
||||
|
||||
Org-roam links are regular @samp{file:} links in Org-mode. By default, links are
|
||||
inserted with the title as the link description with @samp{org-roam-insert}.
|
||||
Org-roam links are regular @code{file:} links in Org-mode. By default, links are
|
||||
inserted with the title as the link description with @code{org-roam-insert}.
|
||||
|
||||
@itemize
|
||||
@item
|
||||
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 @samp{"%s"}.
|
||||
special indicators for Org-roam links. Defaults to @code{"%s"}.
|
||||
|
||||
If your version of Org is at least @samp{9.2}, consider styling the link differently,
|
||||
by customizing the @samp{org-roam-link}, and @samp{org-roam-link-current} faces.
|
||||
If your version of Org is at least @code{9.2}, consider styling the link differently,
|
||||
by customizing the @code{org-roam-link}, and @code{org-roam-link-current} faces.
|
||||
@end itemize
|
||||
|
||||
@node Org-roam Files
|
||||
@ -739,7 +770,7 @@ 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
|
||||
@samp{org-roam-index-file}.
|
||||
@code{org-roam-index-file}.
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@ -748,23 +779,23 @@ 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 @samp{org-roam-directory}) to the index file. If it
|
||||
path (absolute or relative to @code{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 @samp{org-roam-index} whose
|
||||
title is @samp{"Index"}.
|
||||
Otherwise, the index is assumed to be a note in @code{org-roam-index} whose
|
||||
title is @code{"Index"}.
|
||||
|
||||
@item
|
||||
Function: org-roam-find-index
|
||||
|
||||
Opens the Index file in the current @samp{org-roam-directory}.
|
||||
Opens the Index file in the current @code{org-roam-directory}.
|
||||
@end itemize
|
||||
|
||||
@node Encryption
|
||||
@chapter 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 @samp{org-roam-encrypt-files}
|
||||
to @samp{t}. When enabled, new files are created with the @samp{.org.gpg} extension and
|
||||
GPG), which can be enabled for all new files by setting @code{org-roam-encrypt-files}
|
||||
to @code{t}. When enabled, new files are created with the @code{.org.gpg} extension and
|
||||
decryption are handled automatically by EasyPG@.
|
||||
|
||||
Note that Emacs will prompt for a password for encrypted files during
|
||||
@ -785,7 +816,7 @@ Org-roam provides graphing capabilities to explore interconnections between
|
||||
notes. This is done by performing SQL queries and generating images using
|
||||
@uref{https://graphviz.org/, Graphviz}. The graph can also be navigated: see @ref{Roam Protocol}.
|
||||
|
||||
The entry point to graph creation is @samp{org-roam-graph}.
|
||||
The entry point to graph creation is @code{org-roam-graph}.
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@ -797,17 +828,17 @@ ARG may be any of the following values:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@samp{nil} show the graph.
|
||||
@code{nil} show the graph.
|
||||
@item
|
||||
@samp{C-u} show the graph for FILE@.
|
||||
@code{C-u} show the graph for FILE@.
|
||||
@item
|
||||
@samp{C-u N} show the graph for FILE limiting nodes to N steps.
|
||||
@code{C-u N} show the graph for FILE limiting nodes to N steps.
|
||||
@item
|
||||
@samp{C-u C-u} build the graph.
|
||||
@code{C-u C-u} build the graph.
|
||||
@item
|
||||
@samp{C-u -} build the graph for FILE@.
|
||||
@code{C-u -} build the graph for FILE@.
|
||||
@item
|
||||
@samp{C-u -N} build the graph for FILE limiting nodes to N steps.
|
||||
@code{C-u -N} build the graph for FILE limiting nodes to N steps.
|
||||
@end itemize
|
||||
|
||||
@item
|
||||
@ -815,7 +846,7 @@ 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 @samp{neato} in place of @samp{dot}, which generates a more
|
||||
You may also choose to use @code{neato} in place of @code{dot}, which generates a more
|
||||
compact graph layout.
|
||||
|
||||
@item
|
||||
@ -830,7 +861,16 @@ A string, which is a path to the program used
|
||||
a function accepting a single argument: the graph file path.
|
||||
@end enumerate
|
||||
|
||||
@samp{nil} uses @samp{view-file} to view the graph.
|
||||
@code{nil} uses @code{view-file} to view the graph.
|
||||
|
||||
If you are using WSL2 and would like to open the graph in Windows, you can use the second option to set the browser and network file path:
|
||||
|
||||
@lisp
|
||||
(setq org-roam-graph-viewer
|
||||
(lambda (file)
|
||||
(let ((org-roam-graph-viewer "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"))
|
||||
(org-roam-graph--open (concat "file://///wsl$/Ubuntu" file)))))
|
||||
@end lisp
|
||||
@end itemize
|
||||
|
||||
@menu
|
||||
@ -848,25 +888,25 @@ Graphviz provides many options for customizing the graph output, and Org-roam su
|
||||
User Option: org-roam-graph-extra-config
|
||||
|
||||
Extra options passed to graphviz for the digraph (The ``G'' attributes).
|
||||
Example: @samp{'=(("rankdir" . "LR"))}
|
||||
Example: @code{'~(("rankdir" . "LR"))}
|
||||
|
||||
@item
|
||||
User Option: org-roam-graph-node-extra-config
|
||||
|
||||
Extra options for nodes in the graphviz output (The ``N'' attributes).
|
||||
Example: @samp{'(("color" . "skyblue"))}
|
||||
Example: @code{'(("color" . "skyblue"))}
|
||||
|
||||
@item
|
||||
User Option: org-roam-graph-edge-extra-config
|
||||
|
||||
Extra options for edges in the graphviz output (The ``E'' attributes).
|
||||
Example: @samp{'(("dir" . "back"))}
|
||||
Example: @code{'(("dir" . "back"))}
|
||||
|
||||
@item
|
||||
User Option: org-roam-graph-edge-cites-extra-config
|
||||
|
||||
Extra options for citation edges in the graphviz output.
|
||||
Example: @samp{'(("color" . "red"))}
|
||||
Example: @code{'(("color" . "red"))}
|
||||
@end itemize
|
||||
|
||||
@node Excluding Nodes and Edges
|
||||
@ -896,21 +936,25 @@ This setting excludes all files whose path contain ``private'' or ``dailies''.
|
||||
@node Org-roam Completion System
|
||||
@chapter Org-roam Completion System
|
||||
|
||||
Org-roam offers completion when choosing note titles etc. The completion
|
||||
system is configurable. The default setting,
|
||||
Org-roam allows customization of which minibuffer completion system to use for
|
||||
its interactive commands. The default setting uses Emacs' standard
|
||||
@code{completing-read} mechanism.
|
||||
|
||||
@lisp
|
||||
(setq org-roam-completion-system 'default)
|
||||
@end lisp
|
||||
|
||||
uses Emacs' standard @samp{completing-read}. If you prefer
|
||||
@uref{https://emacs-helm.github.io/helm/, Helm}, use
|
||||
If you have installed Helm or Ivy, and have their modes enabled, under the
|
||||
@code{'default} setting they will be used.
|
||||
|
||||
In the rare scenario where you use Ivy globally, but prefer @uref{https://emacs-helm.github.io/helm/, Helm} for org-roam
|
||||
commands, set:
|
||||
|
||||
@lisp
|
||||
(setq org-roam-completion-system 'helm)
|
||||
@end lisp
|
||||
|
||||
Other options include @samp{'ido}, and @samp{'ivy}.
|
||||
Other options include @code{'ido}, and @code{'ivy}.
|
||||
|
||||
@node Roam Protocol
|
||||
@chapter Roam Protocol
|
||||
@ -918,15 +962,15 @@ Other options include @samp{'ido}, and @samp{'ivy}.
|
||||
@menu
|
||||
* _::
|
||||
* Installation: Installation (1).
|
||||
* The @samp{roam-file} protocol::
|
||||
* The @samp{roam-ref} Protocol::
|
||||
* The roam-file protocol::
|
||||
* The roam-ref protocol::
|
||||
@end menu
|
||||
|
||||
@node _
|
||||
@section _ :ignore:
|
||||
|
||||
Org-roam extending @samp{org-protocol} with 2 protocols: the @samp{roam-file}
|
||||
and @samp{roam-ref} protocol.
|
||||
Org-roam extending @code{org-protocol} with 2 protocols: the @code{roam-file}
|
||||
and @code{roam-ref} protocol.
|
||||
|
||||
@node Installation (1)
|
||||
@section Installation
|
||||
@ -937,12 +981,12 @@ To enable Org-roam's protocol extensions, you have to add the following to your
|
||||
(require 'org-roam-protocol)
|
||||
@end lisp
|
||||
|
||||
The instructions for setting up @samp{org-protocol=} are reproduced below.
|
||||
The instructions for setting up @code{org-protocol} are reproduced below.
|
||||
|
||||
We will also need to create a desktop application for @samp{emacsclient}. The
|
||||
We will also need to create a desktop application for @code{emacsclient}. The
|
||||
instructions for various platforms are shown below.
|
||||
|
||||
For Linux users, create a desktop application in @samp{~/.local/share/applications/org-protocol.desktop}:
|
||||
For Linux users, create a desktop application in @code{~/.local/share/applications/org-protocol.desktop}:
|
||||
|
||||
@example
|
||||
[Desktop Entry]
|
||||
@ -954,7 +998,7 @@ Terminal=false
|
||||
MimeType=x-scheme-handler/org-protocol
|
||||
@end example
|
||||
|
||||
Associate @samp{org-protocol://} links with the desktop application by
|
||||
Associate @code{org-protocol://} links with the desktop application by
|
||||
running in your shell:
|
||||
|
||||
@example
|
||||
@ -962,7 +1006,7 @@ xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
|
||||
@end example
|
||||
|
||||
To disable the ``confirm'' prompt in Chrome, you can also make Chrome
|
||||
show a checkbox to tick, so that the @samp{Org-Protocol Client} app will be used
|
||||
show a checkbox to tick, so that the @code{Org-Protocol Client} app will be used
|
||||
without confirmation. To do this, run in a shell:
|
||||
|
||||
@example
|
||||
@ -978,8 +1022,8 @@ sudo chmod 644 /etc/opt/chrome/policies/managed/external_protocol_dialog.json
|
||||
and then restart Chrome (for example, by navigating to <chrome://restart>) to
|
||||
make the new policy take effect.
|
||||
|
||||
See @uref{https://www.chromium.org/administrators/linux-quick-start, here} for more info on the @samp{/etc/opt/chrome/policies/managed} directory and
|
||||
@uref{https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExternalProtocolDialogShowAlwaysOpenCheckbox, here} for information on the @samp{ExternalProtocolDialogShowAlwaysOpenCheckbox} policy.
|
||||
See @uref{https://www.chromium.org/administrators/linux-quick-start, here} for more info on the @code{/etc/opt/chrome/policies/managed} directory and
|
||||
@uref{https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExternalProtocolDialogShowAlwaysOpenCheckbox, here} for information on the @code{ExternalProtocolDialogShowAlwaysOpenCheckbox} policy.
|
||||
|
||||
For MacOS, one solution is to use @uref{https://github.com/sveinbjornt/Platypus, Platypus}. Here are the instructions for
|
||||
setting up with Platypus and Chrome:
|
||||
@ -995,7 +1039,7 @@ brew cask install platypus
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Create a script @samp{launch_emacs.sh}:
|
||||
Create a script @code{launch_emacs.sh}:
|
||||
@end enumerate
|
||||
|
||||
@example
|
||||
@ -1020,7 +1064,7 @@ Create a Platypus app with the following settings:
|
||||
@end example
|
||||
|
||||
|
||||
Inside @samp{Settings}:
|
||||
Inside @code{Settings}:
|
||||
|
||||
@example
|
||||
| Setting | Value |
|
||||
@ -1031,7 +1075,7 @@ Inside @samp{Settings}:
|
||||
@end example
|
||||
|
||||
To disable the ``confirm'' prompt in Chrome, you can also make Chrome
|
||||
show a checkbox to tick, so that the @samp{OrgProtocol} app will be used
|
||||
show a checkbox to tick, so that the @code{OrgProtocol} app will be used
|
||||
without confirmation. To do this, run in a shell:
|
||||
|
||||
@example
|
||||
@ -1040,7 +1084,7 @@ defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -b
|
||||
|
||||
|
||||
If you're using @uref{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 @samp{OrgProtocol.app}
|
||||
handler for the URL scheme `org-protocol`. To make @code{OrgProtocol.app}
|
||||
the default handler instead, run:
|
||||
|
||||
@example
|
||||
@ -1050,21 +1094,43 @@ defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandle
|
||||
|
||||
Then restart your computer.
|
||||
|
||||
@node The @samp{roam-file} protocol
|
||||
@section The @samp{roam-file} protocol
|
||||
For Windows, create a temporary @code{org-protocol.reg} file:
|
||||
|
||||
This is a simple protocol that opens the path specified by the @samp{file}
|
||||
key (e.g. @samp{org-protocol://roam-file?file=/tmp/file.org}). This is used
|
||||
@example
|
||||
REGEDIT4
|
||||
|
||||
[HKEY_CLASSES_ROOT\org-protocol]
|
||||
@@="URL:Org Protocol"
|
||||
"URL Protocol"=""
|
||||
[HKEY_CLASSES_ROOT\org-protocol\shell]
|
||||
[HKEY_CLASSES_ROOT\org-protocol\shell\open]
|
||||
[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
|
||||
@@="\"C:\\Windows\\System32\\wsl.exe\" emacsclient \"%1\""
|
||||
@end example
|
||||
|
||||
The above will forward the protocol to WSL@. If you run Emacs natively on Windows, replace the last line with:
|
||||
|
||||
@example
|
||||
@@="\"c:\\path\\to\\emacs\\bin\\emacsclientw.exe\" \"%1\""
|
||||
@end example
|
||||
|
||||
After executing the .reg file, the protocol is registered and you can delete the file.
|
||||
|
||||
@node The roam-file protocol
|
||||
@section The roam-file protocol
|
||||
|
||||
This is a simple protocol that opens the path specified by the @code{file}
|
||||
key (e.g. @code{org-protocol://roam-file?file=/tmp/file.org}). This is used
|
||||
in the generated graph.
|
||||
|
||||
@node The @samp{roam-ref} Protocol
|
||||
@section The @samp{roam-ref} Protocol
|
||||
@node The roam-ref protocol
|
||||
@section The roam-ref protocol
|
||||
|
||||
This protocol finds or creates a new note with a given @code{roam_key} (see @ref{Anatomy of an Org-roam File}):
|
||||
|
||||
@image{images/roam-ref,,,,gif}
|
||||
|
||||
To use this, create a Firefox bookmarklet as follows:
|
||||
To use this, create the following @uref{https://en.wikipedia.org/wiki/Bookmarklet, bookmarklet} in your browser:
|
||||
|
||||
@example
|
||||
javascript:location.href =
|
||||
@ -1078,7 +1144,7 @@ or as a keybinding in @code{qutebrowser} in , using the @code{config.py} file (s
|
||||
@uref{https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc, Configuring qutebrowser}):
|
||||
|
||||
@example
|
||||
config.bind("<Ctrl-r>", "spawn bash -c 'emacsclient \"org-protocol://roam-ref?template=r&ref=@{url:pretty@}&title=@{title@}\" '")
|
||||
config.bind("<Ctrl-r>", "open javascript:location.href='org-protocol://roam-ref?template=r&ref='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)")
|
||||
@end example
|
||||
|
||||
where @code{template} is the template key for a template in
|
||||
@ -1093,7 +1159,7 @@ should contain a @code{#+roam_key: $@{ref@}} in it.
|
||||
|
||||
Org-roam provides a utility for diagnosing and repairing problematic files via
|
||||
@code{org-roam-doctor}. By default, @code{org-roam-doctor} runs the check on the current
|
||||
Org-roam file. To run the check only for the current file, run @samp{C-u M-x
|
||||
Org-roam file. To run the check only for the current file, run @code{C-u M-x
|
||||
org-roam-doctor}, but note that this may take some time.
|
||||
|
||||
@itemize
|
||||
@ -1104,7 +1170,9 @@ Perform a check on Org-roam files to ensure cleanliness. If THIS-BUFFER, run
|
||||
the check only for the current buffer.
|
||||
@end itemize
|
||||
|
||||
The checks run are defined in @samp{org-roam-doctor--checkers}. Each checker is an instance of @samp{org-roam-doctor-checker}. To define a checker, use @samp{make-org-roam-doctor-checker}. Here is a sample definition:
|
||||
The checks run are defined in @code{org-roam-doctor--checkers}. Each checker is an
|
||||
instance of @code{org-roam-doctor-checker}. To define a checker, use
|
||||
@code{make-org-roam-doctor-checker}. Here is a sample definition:
|
||||
|
||||
@lisp
|
||||
(make-org-roam-doctor-checker
|
||||
@ -1115,14 +1183,40 @@ The checks run are defined in @samp{org-roam-doctor--checkers}. Each checker is
|
||||
("R" . ("Replace link (keep label)" . org-roam-doctor--replace-link-keep-label))))
|
||||
@end lisp
|
||||
|
||||
The @samp{:name} property is the name of the function run. The function takes in the
|
||||
Org parse tree, and returns a list of @samp{(point error-message)}. @samp{:description} is a
|
||||
short description of what the checker does. @samp{:actions} is an alist containing
|
||||
elements of the form @samp{(char . (prompt . function))}. These actions are defined per
|
||||
The @code{:name} property is the name of the function run. The function takes in the
|
||||
Org parse tree, and returns a list of @code{(point error-message)}. @code{:description} is a
|
||||
short description of what the checker does. @code{:actions} is an alist containing
|
||||
elements of the form @code{(char . (prompt . function))}. These actions are defined per
|
||||
checker, to perform autofixes for the errors. For each error detected,
|
||||
@samp{org-roam-doctor} will move the point to the current error, and pop-up a help
|
||||
@code{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 @samp{:actions}.
|
||||
taken provided in @code{:actions}.
|
||||
|
||||
@node Performance Optimization
|
||||
@chapter Performance Optimization
|
||||
|
||||
@menu
|
||||
* Profiling Key Operations::
|
||||
* Garbage Collection::
|
||||
@end menu
|
||||
|
||||
@node Profiling Key Operations
|
||||
@section @strong{TODO} Profiling Key Operations
|
||||
|
||||
@node Garbage Collection
|
||||
@section Garbage Collection
|
||||
|
||||
During the cache-build process, Org-roam generates a lot of in-memory
|
||||
data-structures (such as the Org file's AST), which are discarded after use. These structures are garbage collected at regular intervals (see @ref{Garbage Collection,info:elisp#Garbage Collection,,elisp,}).
|
||||
|
||||
Org-roam provides the option @code{org-roam-db-gc-threshold} to temporarily change
|
||||
the threshold value for GC to be triggered during these memory-intensive
|
||||
operations. To reduce the number of garbage collection processes, one may set
|
||||
@code{org-roam-db-gc-threshold} to a high value (such as @code{most-positive-fixnum}):
|
||||
|
||||
@lisp
|
||||
(setq org-roam-db-gc-threshold most-positive-fixnum)
|
||||
@end lisp
|
||||
|
||||
@node Appendix
|
||||
@chapter Appendix
|
||||
@ -1169,19 +1263,44 @@ taken provided in @samp{:actions}.
|
||||
@node Ecosystem
|
||||
@section Ecosystem
|
||||
|
||||
A number of packages work well combined with Org-Roam:
|
||||
|
||||
@menu
|
||||
* Deft::
|
||||
* Browsing History with winner-mode::
|
||||
* Versioning Notes::
|
||||
* Full-text search interface with Deft::
|
||||
* Org-journal::
|
||||
* Note-taking Add-ons::
|
||||
@end menu
|
||||
|
||||
@node Deft
|
||||
@subsection Deft
|
||||
@node Browsing History with winner-mode
|
||||
@subsection Browsing History with winner-mode
|
||||
|
||||
@uref{https://jblevins.org/projects/deft/, Deft} provides a nice interface
|
||||
for browsing and filtering org-roam notes.
|
||||
@code{winner-mode} is a global minor mode that allows one to undo and redo changes in the window configuration. It is included with GNU Emacs since version 20.
|
||||
|
||||
@code{winner-mode} can be used as a simple version of browser history for Org-roam. Each click through org-roam links (from both Org files and the backlinks buffer) causes changes in window configuration, which can be undone and redone using @code{winner-mode}. To use @code{winner-mode}, simply enable it, and bind the appropriate interactive functions:
|
||||
|
||||
@lisp
|
||||
(winner-mode +1)
|
||||
(define-key winner-mode-map (kbd "<M-left>") #'winner-undo)
|
||||
(define-key winner-mode-map (kbd "<M-right>") #'winner-redo)
|
||||
|
||||
@end lisp
|
||||
|
||||
@node Versioning Notes
|
||||
@subsection Versioning Notes
|
||||
|
||||
Since Org-roam notes are just plain text, it is trivial to track changes in your
|
||||
notes database using version control systems such as @uref{https://git-scm.com/, Git}. Simply initialize
|
||||
@code{org-roam-directory} as a Git repository, and commit your files at regular or
|
||||
appropriate intervals. @uref{https://magit.vc/, Magit} is a great interface to Git within Emacs.
|
||||
|
||||
In addition, it may be useful to observe how a particular note has evolved, by
|
||||
looking at the file history. @uref{https://gitlab.com/pidu/git-timemachine, Git-timemachine} allows you to visit historic
|
||||
versions of a tracked Org-roam note.
|
||||
|
||||
@node Full-text search interface with Deft
|
||||
@subsection Full-text search interface with Deft
|
||||
|
||||
@uref{https://jblevins.org/projects/deft/, Deft} provides a nice interface for browsing and filtering org-roam notes.
|
||||
|
||||
@lisp
|
||||
(use-package deft
|
||||
@ -1196,7 +1315,7 @@ for browsing and filtering org-roam notes.
|
||||
@end lisp
|
||||
|
||||
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 @samp{org-roam}'s
|
||||
nice titles. You may choose to patch this to use @code{org-roam}'s
|
||||
functionality. Here I'm using
|
||||
@uref{https://github.com/raxod502/el-patch, el-patch}:
|
||||
|
||||
@ -1234,7 +1353,7 @@ that uses an external search engine and indexer.
|
||||
@subsection Org-journal
|
||||
|
||||
@uref{https://github.com/bastibe/org-journal, Org-journal} is a more
|
||||
powerful alternative to the simple function @samp{org-roam-dailies-today}. It
|
||||
powerful alternative to the simple function @code{org-roam-dailies-today}. It
|
||||
provides better journaling capabilities, and a nice calendar interface
|
||||
to see all dated entries.
|
||||
|
||||
@ -1315,8 +1434,8 @@ etc.) within Org-mode.
|
||||
tight integration between
|
||||
@uref{https://github.com/jkitchin/org-ref, org-ref},
|
||||
@uref{https://github.com/tmalsburg/helm-bibtex, helm-bibtex} and
|
||||
@samp{org-roam}. This helps you manage your bibliographic notes under
|
||||
@samp{org-roam}.
|
||||
@code{org-roam}. This helps you manage your bibliographic notes under
|
||||
@code{org-roam}.
|
||||
|
||||
@node Spaced Repetition
|
||||
@unnumberedsubsubsec Spaced Repetition
|
||||
@ -1336,11 +1455,11 @@ files. Other alternatives include @uref{https://orgmode.org/worg/org-contrib/org
|
||||
@section How do I have more than one Org-roam directory?
|
||||
|
||||
Emacs supports directory-local variables, allowing the value of
|
||||
@samp{org-roam-directory} to be different in different directories. It does this by
|
||||
checking for a file named @samp{.dir-locals.el}.
|
||||
@code{org-roam-directory} to be different in different directories. It does this by
|
||||
checking for a file named @code{.dir-locals.el}.
|
||||
|
||||
To add support for multiple directories, override the @samp{org-roam-directory}
|
||||
variable using directory-local variables. This is what @samp{.dir-locals.el} may
|
||||
To add support for multiple directories, override the @code{org-roam-directory}
|
||||
variable using directory-local variables. This is what @code{.dir-locals.el} may
|
||||
contain:
|
||||
|
||||
@lisp
|
||||
@ -1348,7 +1467,7 @@ contain:
|
||||
@end lisp
|
||||
|
||||
All files within that directory will be treated as their own separate
|
||||
set of Org-roam files. Remember to run @samp{org-roam-db-build-cache} from a
|
||||
set of Org-roam files. Remember to run @code{org-roam-db-build-cache} from a
|
||||
file within that directory, at least once.
|
||||
|
||||
@node How do I migrate from Roam Research?
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -49,6 +49,7 @@
|
||||
(declare-function org-roam--get-backlinks "org-roam")
|
||||
(declare-function org-roam-backlinks-mode "org-roam")
|
||||
(declare-function org-roam-mode "org-roam")
|
||||
(declare-function org-roam--find-file "org-roam")
|
||||
|
||||
(defcustom org-roam-buffer-position 'right
|
||||
"Position of `org-roam' buffer.
|
||||
@ -83,7 +84,7 @@ Has an effect if and only if `org-roam-buffer-position' is `top' or `bottom'."
|
||||
|
||||
(defcustom org-roam-buffer-prepare-hook '(org-roam-buffer--insert-title
|
||||
org-roam-buffer--insert-backlinks
|
||||
org-roam-buffer--insert-citelinks)
|
||||
org-roam-buffer--insert-ref-links)
|
||||
"Hook run in the `org-roam-buffer' before it is displayed."
|
||||
:type 'hook
|
||||
:group 'org-roam)
|
||||
@ -97,6 +98,14 @@ For example: (setq org-roam-buffer-window-parameters '((no-other-window . t)))"
|
||||
(defvar org-roam-buffer--current nil
|
||||
"Currently displayed file in `org-roam' buffer.")
|
||||
|
||||
(defun org-roam-buffer--find-file (file)
|
||||
"Open FILE in the window `org-roam' was called from."
|
||||
(if (and org-roam-last-window (window-valid-p org-roam-last-window))
|
||||
(progn (with-selected-window org-roam-last-window
|
||||
(org-roam--find-file file))
|
||||
(select-window org-roam-last-window))
|
||||
(org-roam--find-file file)))
|
||||
|
||||
(defun org-roam-buffer--insert-title ()
|
||||
"Insert the org-roam-buffer title."
|
||||
(insert (propertize (org-roam--get-title-or-slug
|
||||
@ -114,10 +123,9 @@ For example: (setq org-roam-buffer-window-parameters '((no-other-window . t)))"
|
||||
,wrong-type))))))
|
||||
(concat string (when (> l 1) "s"))))
|
||||
|
||||
(defun org-roam-buffer--insert-citelinks ()
|
||||
"Insert citation backlinks for the current buffer."
|
||||
(when-let ((org-ref-p (require 'org-ref nil t)) ;; Ensure that org-ref is present
|
||||
(ref (cdr (with-temp-buffer
|
||||
(defun org-roam-buffer--insert-ref-links ()
|
||||
"Insert ref backlinks for the current buffer."
|
||||
(when-let ((ref (cdr (with-temp-buffer
|
||||
(insert-buffer-substring org-roam-buffer--current)
|
||||
(org-roam--extract-ref)))))
|
||||
(if-let* ((key-backlinks (org-roam--get-backlinks ref))
|
||||
@ -125,7 +133,7 @@ For example: (setq org-roam-buffer-window-parameters '((no-other-window . t)))"
|
||||
(progn
|
||||
(insert (let ((l (length key-backlinks)))
|
||||
(format "\n\n* %d %s\n"
|
||||
l (org-roam-buffer--pluralize "Cite backlink" l))))
|
||||
l (org-roam-buffer--pluralize "Ref Backlink" l))))
|
||||
(dolist (group grouped-backlinks)
|
||||
(let ((file-from (car group))
|
||||
(bls (cdr group)))
|
||||
@ -134,14 +142,12 @@ For example: (setq org-roam-buffer-window-parameters '((no-other-window . t)))"
|
||||
(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)))
|
||||
(insert (propertize (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!"))))
|
||||
(insert "\n\n* No ref backlinks!"))))
|
||||
|
||||
(defun org-roam-buffer--insert-backlinks ()
|
||||
"Insert the org-roam-buffer backlinks string for the current buffer."
|
||||
@ -160,13 +166,18 @@ For example: (setq org-roam-buffer-window-parameters '((no-other-window . t)))"
|
||||
(org-roam--get-title-or-slug file-from)))
|
||||
(dolist (backlink bls)
|
||||
(pcase-let ((`(,file-from _ ,props) backlink))
|
||||
(insert (propertize
|
||||
(insert "*** "
|
||||
(if-let ((outline (plist-get props :outline)))
|
||||
(string-join outline " > ")
|
||||
"Top")
|
||||
"\n"
|
||||
(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"))))))
|
||||
'file-from-point (plist-get props :point))
|
||||
"\n\n"))))))
|
||||
(insert "\n\n* No backlinks!")))
|
||||
|
||||
(defun org-roam-buffer-update ()
|
||||
@ -266,14 +277,25 @@ Valid states are 'visible, 'exists and 'none."
|
||||
(org-roam-buffer--set-height
|
||||
(round (* (frame-height) org-roam-buffer-height))))))))
|
||||
|
||||
(defun org-roam-buffer-toggle-display ()
|
||||
"Toggle display of the `org-roam-buffer'."
|
||||
(defun org-roam-buffer-activate ()
|
||||
"Activate display of the `org-roam-buffer'."
|
||||
(interactive)
|
||||
(unless org-roam-mode (org-roam-mode))
|
||||
(setq org-roam-last-window (get-buffer-window))
|
||||
(org-roam-buffer--get-create))
|
||||
|
||||
(defun org-roam-buffer-deactivate ()
|
||||
"Deactivate display of the `org-roam-buffer'."
|
||||
(interactive)
|
||||
(setq org-roam-last-window (get-buffer-window))
|
||||
(delete-window (get-buffer-window org-roam-buffer)))
|
||||
|
||||
(defun org-roam-buffer-toggle-display ()
|
||||
"Toggle display of the `org-roam-buffer'."
|
||||
(interactive)
|
||||
(pcase (org-roam-buffer--visibility)
|
||||
('visible (delete-window (get-buffer-window org-roam-buffer)))
|
||||
((or 'exists 'none) (org-roam-buffer--get-create))))
|
||||
('visible (org-roam-buffer-deactivate))
|
||||
((or 'exists 'none) (org-roam-buffer-activate))))
|
||||
|
||||
(provide 'org-roam-buffer)
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -39,11 +39,12 @@
|
||||
(defvar org-roam-encrypt-files)
|
||||
(defvar org-roam-directory)
|
||||
(defvar org-roam-mode)
|
||||
(defvar org-roam-title-to-slug-function)
|
||||
(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--find-file "org-roam")
|
||||
(declare-function org-roam--format-link "org-roam")
|
||||
(declare-function org-roam--title-to-slug "org-roam")
|
||||
(declare-function org-roam-mode "org-roam")
|
||||
(declare-function org-roam-completion--completing-read "org-roam-completion")
|
||||
|
||||
@ -81,68 +82,277 @@ note with the given `ref'.")
|
||||
(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
|
||||
(defcustom 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.
|
||||
The Org-roam capture-templates builds on the default behaviours of
|
||||
`org-capture-templates' by expanding them in 3 areas:
|
||||
|
||||
`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.
|
||||
|
||||
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.
|
||||
2. The `:file-name' key is added, which defines the naming format
|
||||
to use when creating new notes. 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.")
|
||||
inserted upon the creation of a new file. This is where you
|
||||
should add your note metadata should go.
|
||||
|
||||
(defvar org-roam-capture-ref-templates
|
||||
Each template should have the following structure:
|
||||
|
||||
\(KEY DESCRIPTION `plain' `(function org-roam-capture--get-point)'
|
||||
TEMPLATE
|
||||
`:file-name' FILENAME-FORMAT
|
||||
`:head' HEADER-FORMAT
|
||||
`:unnarrowed t'
|
||||
OPTIONS-PLIST)
|
||||
|
||||
The elements of a template-entry and their placement are the same
|
||||
as in `org-capture-templates', except that the entry type must
|
||||
always be the symbol `plain', and that the target must always be
|
||||
the list `(function org-roam-capture--get-point)'.
|
||||
|
||||
Org-roam requires the plist elements `:file-name' and `:head' to
|
||||
be present, and it’s recommended that `:unnarrowed' be set to t."
|
||||
:group 'org-roam
|
||||
;; Adapted from `org-capture-templates'
|
||||
:type
|
||||
'(repeat
|
||||
(choice :value ("d" "default" plain (function org-roam-capture--get-point)
|
||||
"%?"
|
||||
:file-name "%<%Y%m%d%H%M%S>-${slug}"
|
||||
:head "#+title: ${title}\n"
|
||||
:unnarrowed t)
|
||||
(list :tag "Multikey description"
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description"))
|
||||
(list :tag "Template entry"
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description ")
|
||||
(const :format "" plain)
|
||||
(const :format "" (function org-roam-capture--get-point))
|
||||
(choice :tag "Template "
|
||||
(string :tag "String"
|
||||
:format "String:\n \
|
||||
Template string :\n%v")
|
||||
(list :tag "File"
|
||||
(const :format "" file)
|
||||
(file :tag "Template file "))
|
||||
(list :tag "Function"
|
||||
(const :format "" function)
|
||||
(function :tag "Template function ")))
|
||||
(const :format "File name format :" :file-name)
|
||||
(string :format " %v" :value "#+title: ${title}\n")
|
||||
(const :format "Header format :" :head)
|
||||
(string :format "\n%v" :value "%<%Y%m%d%H%M%S>-${slug}")
|
||||
(const :format "" :unnarrowed) (const :format "" t)
|
||||
(plist :inline t
|
||||
:tag "Options"
|
||||
;; Give the most common options as checkboxes
|
||||
:options
|
||||
(((const :format "%v " :prepend) (const t))
|
||||
((const :format "%v " :immediate-finish) (const t))
|
||||
((const :format "%v " :jump-to-captured) (const t))
|
||||
((const :format "%v " :empty-lines) (const 1))
|
||||
((const :format "%v " :empty-lines-before) (const 1))
|
||||
((const :format "%v " :empty-lines-after) (const 1))
|
||||
((const :format "%v " :clock-in) (const t))
|
||||
((const :format "%v " :clock-keep) (const t))
|
||||
((const :format "%v " :clock-resume) (const t))
|
||||
((const :format "%v " :time-prompt) (const t))
|
||||
((const :format "%v " :tree-type) (const week))
|
||||
((const :format "%v " :table-line-pos) (string))
|
||||
((const :format "%v " :kill-buffer) (const t))))))))
|
||||
|
||||
(defcustom org-roam-capture-immediate-template
|
||||
(append (car org-roam-capture-templates) '(:immediate-finish t))
|
||||
"Capture template to use for immediate captures in Org-roam.
|
||||
This is a single template, so do not enclose it into a list.
|
||||
See `org-roam-capture-templates' for details on templates."
|
||||
:group 'org-roam
|
||||
;; Adapted from `org-capture-templates'
|
||||
:type
|
||||
'(list :tag "Template entry"
|
||||
:value ("d" "default" plain (function org-roam-capture--get-point)
|
||||
"%?"
|
||||
:file-name "%<%Y%m%d%H%M%S>-${slug}"
|
||||
:head "#+title: ${title}\n"
|
||||
:unnarrowed t
|
||||
:immediate-finish t)
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description ")
|
||||
(const :format "" plain)
|
||||
(const :format "" (function org-roam-capture--get-point))
|
||||
(choice :tag "Template "
|
||||
(string :tag "String"
|
||||
:format "String:\n \
|
||||
Template string :\n%v")
|
||||
(list :tag "File"
|
||||
(const :format "" file)
|
||||
(file :tag "Template file "))
|
||||
(list :tag "Function"
|
||||
(const :format "" function)
|
||||
(function :tag "Template function ")))
|
||||
(const :format "File name format :" :file-name)
|
||||
(string :format " %v" :value "#+title: ${title}\n")
|
||||
(const :format "Header format :" :head)
|
||||
(string :format "\n%v" :value "%<%Y%m%d%H%M%S>-${slug}")
|
||||
(const :format "" :unnarrowed) (const :format "" t)
|
||||
(const :format "" :immediate-finish) (const :format "" t)
|
||||
(plist :inline t
|
||||
:tag "Options"
|
||||
;; Give the most common options as checkboxes
|
||||
:options
|
||||
(((const :format "%v " :prepend) (const t))
|
||||
((const :format "%v " :jump-to-captured) (const t))
|
||||
((const :format "%v " :empty-lines) (const 1))
|
||||
((const :format "%v " :empty-lines-before) (const 1))
|
||||
((const :format "%v " :empty-lines-after) (const 1))
|
||||
((const :format "%v " :clock-in) (const t))
|
||||
((const :format "%v " :clock-keep) (const t))
|
||||
((const :format "%v " :clock-resume) (const t))
|
||||
((const :format "%v " :time-prompt) (const t))
|
||||
((const :format "%v " :tree-type) (const week))
|
||||
((const :format "%v " :table-line-pos) (string))
|
||||
((const :format "%v " :kill-buffer) (const t))))))
|
||||
|
||||
(defcustom org-roam-capture-ref-templates
|
||||
'(("r" "ref" plain (function org-roam-capture--get-point)
|
||||
""
|
||||
"%?"
|
||||
:file-name "${slug}"
|
||||
:head "#+title: ${title}
|
||||
#+roam_key: ${ref}\n"
|
||||
:head "#+title: ${title}\n#+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'.")
|
||||
Details on how to specify for the template is given in `org-roam-capture-templates'."
|
||||
:group 'org-roam
|
||||
;; Adapted from `org-capture-templates'
|
||||
:type
|
||||
'(repeat
|
||||
(choice :value ("d" "default" plain (function org-roam-capture--get-point)
|
||||
"%?"
|
||||
:file-name "${slug}"
|
||||
:head "#+title: ${title}\n#+roam_key: ${ref}\n"
|
||||
:unnarrowed t)
|
||||
(list :tag "Multikey description"
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description"))
|
||||
(list :tag "Template entry"
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description ")
|
||||
(const :format "" plain)
|
||||
(const :format "" (function org-roam-capture--get-point))
|
||||
(choice :tag "Template "
|
||||
(string :tag "String"
|
||||
:format "String:\n \
|
||||
Template string :\n%v")
|
||||
(list :tag "File"
|
||||
(const :format "" file)
|
||||
(file :tag "Template file "))
|
||||
(list :tag "Function"
|
||||
(const :format "" function)
|
||||
(function :tag "Template function ")))
|
||||
(const :format "File name format :" :file-name)
|
||||
(string :format " %v" :value "#+title: ${title}\n")
|
||||
(const :format "Header format :" :head)
|
||||
(string :format "\n%v" :value "%<%Y%m%d%H%M%S>-${slug}")
|
||||
(const :format "" :unnarrowed) (const :format "" t)
|
||||
(plist :inline t
|
||||
:tag "Options"
|
||||
;; Give the most common options as checkboxes
|
||||
:options
|
||||
(((const :format "%v " :prepend) (const t))
|
||||
((const :format "%v " :immediate-finish) (const t))
|
||||
((const :format "%v " :jump-to-captured) (const t))
|
||||
((const :format "%v " :empty-lines) (const 1))
|
||||
((const :format "%v " :empty-lines-before) (const 1))
|
||||
((const :format "%v " :empty-lines-after) (const 1))
|
||||
((const :format "%v " :clock-in) (const t))
|
||||
((const :format "%v " :clock-keep) (const t))
|
||||
((const :format "%v " :clock-resume) (const t))
|
||||
((const :format "%v " :time-prompt) (const t))
|
||||
((const :format "%v " :tree-type) (const week))
|
||||
((const :format "%v " :table-line-pos) (string))
|
||||
((const :format "%v " :kill-buffer) (const t))))))))
|
||||
|
||||
(defun org-roam-capture-p ()
|
||||
"Return t if the current capture process is an Org-roam capture.
|
||||
This function is to only be called when org-capture-plist is
|
||||
valid for the capture (i.e. initialization, and finalization of
|
||||
the capture)."
|
||||
(plist-get org-capture-plist :org-roam))
|
||||
|
||||
(defun org-roam-capture--get (keyword)
|
||||
"Gets the value for KEYWORD from the `org-roam-capture-template'."
|
||||
"Get 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'."
|
||||
"Put 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 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)))
|
||||
;; FIXME: Pending upstream patch
|
||||
;; https://orgmode.org/list/87h7tv9pkm.fsf@hidden/T/#u
|
||||
;;
|
||||
;; Org-capture's behaviour right now is that `org-capture-plist' is valid only
|
||||
;; during the initialization of the Org-capture buffer. The value of
|
||||
;; `org-capture-plist' is saved into buffer-local `org-capture-current-plist'.
|
||||
;; However, the value for that particular capture is no longer accessible for
|
||||
;; hooks in `org-capture-after-finalize-hook', since the capture buffer has been
|
||||
;; cleaned up.
|
||||
;;
|
||||
;; This advice restores the global `org-capture-plist' during finalization, so
|
||||
;; the plist is valid during both initialization and finalization of the
|
||||
;; capture.
|
||||
(defun org-roam-capture--update-plist (&optional _)
|
||||
"Update global plist from local var."
|
||||
(setq org-capture-plist org-capture-current-plist))
|
||||
|
||||
(defun org-roam-capture--fill-template (str &optional info)
|
||||
"Expands the template STR, returning the string.
|
||||
(advice-add 'org-capture-finalize :before #'org-roam-capture--update-plist)
|
||||
|
||||
(defun org-roam-capture--finalize ()
|
||||
"Finalize the `org-roam-capture' process."
|
||||
(unless org-note-abort
|
||||
(pcase (org-roam-capture--get :finalize)
|
||||
('find-file
|
||||
(when-let ((file-path (org-roam-capture--get :file-path)))
|
||||
(org-roam--find-file file-path)
|
||||
(run-hooks 'org-roam-capture-after-find-file-hook)))
|
||||
('insert-link
|
||||
(when-let* ((mkr (org-roam-capture--get :insert-at))
|
||||
(buf (marker-buffer mkr)))
|
||||
(with-current-buffer buf
|
||||
(when-let ((region (org-roam-capture--get :region))) ;; Remove previously selected text.
|
||||
(delete-region (car region) (cdr region)))
|
||||
(let ((path (org-roam-capture--get :file-path))
|
||||
(desc (org-roam-capture--get :link-description)))
|
||||
(if (eq (point) (marker-position mkr))
|
||||
(insert (org-roam--format-link path desc))
|
||||
(org-with-point-at mkr
|
||||
(insert (org-roam--format-link path desc))))))))))
|
||||
(org-roam-capture--save-file-maybe)
|
||||
(remove-hook 'org-capture-after-finalize-hook #'org-roam-capture--finalize))
|
||||
|
||||
(defun org-roam-capture--install-finalize ()
|
||||
"Install `org-roam-capture--finalize' if the capture is an Org-roam capture."
|
||||
(when (org-roam-capture-p)
|
||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--finalize)))
|
||||
|
||||
(add-hook 'org-capture-prepare-finalize-hook #'org-roam-capture--install-finalize)
|
||||
|
||||
(defun org-roam-capture--fill-template (str)
|
||||
"Expand 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.
|
||||
First, it expands ${var} occurrences in STR, using `org-roam-capture--info'.
|
||||
If there is a ${var} with no matching var in the alist, the value
|
||||
of var is prompted for via `completing-read'.
|
||||
|
||||
@ -150,23 +360,13 @@ 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)
|
||||
(or (s--aget org-roam-capture--info key)
|
||||
(when-let ((val (completing-read (format "%s: " key) nil)))
|
||||
(push (cons key val) org-roam-capture--info)
|
||||
val))) 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 ()
|
||||
(defun org-roam-capture--save-file-maybe ()
|
||||
"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
|
||||
@ -180,8 +380,7 @@ The file is saved if the original value of :no-save is not t and
|
||||
((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))
|
||||
(save-buffer)))))
|
||||
|
||||
(defun org-roam-capture--new-file ()
|
||||
"Return the path to the new file during an Org-roam capture.
|
||||
@ -201,14 +400,13 @@ aborted, we do the following:
|
||||
|
||||
2. Set the capture template's :no-save to t.
|
||||
|
||||
3. Add a function on `org-capture-after-finalize-hook' that saves
|
||||
3. Add a function on `org-capture-before-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)))
|
||||
name-templ)))
|
||||
(file-path (org-roam--file-path-from-id new-id))
|
||||
(roam-head (or (org-roam-capture--get :head)
|
||||
org-roam-capture--header-default))
|
||||
@ -229,16 +427,6 @@ the file if the original value of :no-save is not t and
|
||||
: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:
|
||||
@ -271,7 +459,8 @@ This function is used solely in Org-roam's capture templates: see
|
||||
(plist-get pl :path)
|
||||
(org-roam-capture--new-file))))
|
||||
(_ (error "Invalid org-roam-capture-context")))))
|
||||
(org-roam-capture--expand-template)
|
||||
(org-capture-put :template
|
||||
(org-roam-capture--fill-template (org-capture-get :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))
|
||||
@ -299,33 +488,31 @@ This function is used solely in Org-roam's capture templates: see
|
||||
(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)
|
||||
|
||||
(defcustom org-roam-capture-function #'org-capture
|
||||
"Function that is invoked to start the `org-capture' process."
|
||||
:group 'org-roam
|
||||
:type 'function)
|
||||
|
||||
(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)
|
||||
(let* ((org-capture-templates (mapcar #'org-roam-capture--convert-template org-roam-capture-templates))
|
||||
(one-template-p (= (length org-capture-templates) 1))
|
||||
org-capture-templates-contexts)
|
||||
(when one-template-p
|
||||
(setq keys (caar org-capture-templates)))
|
||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--save-file-maybe-h)
|
||||
(org-capture goto keys)))
|
||||
(if (or one-template-p
|
||||
(eq org-roam-capture-function 'org-capture))
|
||||
(org-capture goto keys)
|
||||
(funcall-interactively org-roam-capture-function))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-capture ()
|
||||
@ -333,8 +520,6 @@ GOTO and KEYS argument have the same functionality as
|
||||
This uses the templates defined at `org-roam-capture-templates'."
|
||||
(interactive)
|
||||
(unless org-roam-mode (org-roam-mode))
|
||||
(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))
|
||||
@ -342,10 +527,9 @@ This uses the templates defined at `org-roam-capture-templates'."
|
||||
(title (or (plist-get res :title) title-with-keys))
|
||||
(file-path (plist-get res :path)))
|
||||
(let ((org-roam-capture--info (list (cons 'title title)
|
||||
(cons 'slug (org-roam--title-to-slug title))
|
||||
(cons 'slug (funcall org-roam-title-to-slug-function 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'"
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -79,6 +79,8 @@
|
||||
"org-roam 1.1.0")
|
||||
(define-obsolete-function-alias 'org-roam-db--maybe-update 'org-roam-db--update-maybe
|
||||
"org-roam 1.1.0")
|
||||
(define-obsolete-function-alias 'org-roam-db--clear 'org-roam-db-clear
|
||||
"org-roam 1.2.0")
|
||||
|
||||
(when (version< (org-version) "9.3")
|
||||
(defalias 'org-link-make-string 'org-make-link-string))
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -36,13 +36,62 @@
|
||||
(require 'org-roam-capture)
|
||||
(require 'org-roam-macs)
|
||||
|
||||
(defvar org-roam-dailies-capture-templates
|
||||
(defcustom 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.")
|
||||
"Capture templates for daily notes in Org-roam."
|
||||
:group 'org-roam
|
||||
;; Adapted from `org-capture-templates'
|
||||
:type
|
||||
'(repeat
|
||||
(choice :value ("d" "daily" plain (function org-roam-capture--get-point)
|
||||
""
|
||||
:immediate-finish t
|
||||
:file-name "%<%Y-%m-%d>"
|
||||
:head "#+title: %<%Y-%m-%d>")
|
||||
(list :tag "Multikey description"
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description"))
|
||||
(list :tag "Template entry"
|
||||
(string :tag "Keys ")
|
||||
(string :tag "Description ")
|
||||
(const :format "" plain)
|
||||
(const :format "" (function org-roam-capture--get-point))
|
||||
(choice :tag "Template "
|
||||
(string :tag "String"
|
||||
:format "String:\n \
|
||||
Template string :\n%v")
|
||||
(list :tag "File"
|
||||
(const :format "" file)
|
||||
(file :tag "Template file "))
|
||||
(list :tag "Function"
|
||||
(const :format "" function)
|
||||
(function :tag "Template function ")))
|
||||
(const :format "" :immediate-finish) (const :format "" t)
|
||||
(const :format "File name format :" :file-name)
|
||||
(string :format " %v" :value "#+title: ${title}\n")
|
||||
(const :format "Header format :" :head)
|
||||
(string :format "\n%v" :value "%<%Y%m%d%H%M%S>-${slug}")
|
||||
(plist :inline t
|
||||
:tag "Options"
|
||||
;; Give the most common options as checkboxes
|
||||
:options
|
||||
(((const :format "%v " :prepend) (const t))
|
||||
((const :format "%v " :jump-to-captured) (const t))
|
||||
((const :format "%v " :empty-lines) (const 1))
|
||||
((const :format "%v " :empty-lines-before) (const 1))
|
||||
((const :format "%v " :empty-lines-after) (const 1))
|
||||
((const :format "%v " :clock-in) (const t))
|
||||
((const :format "%v " :clock-keep) (const t))
|
||||
((const :format "%v " :clock-resume) (const t))
|
||||
((const :format "%v " :time-prompt) (const t))
|
||||
((const :format "%v " :tree-type) (const week))
|
||||
((const :format "%v " :table-line-pos) (string))
|
||||
((const :format "%v " :kill-buffer) (const t))
|
||||
((const :format "%v " :unnarrowed) (const t))))))))
|
||||
|
||||
;; Declarations
|
||||
(defvar org-roam-mode)
|
||||
@ -54,7 +103,7 @@
|
||||
(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)
|
||||
(setq org-roam-capture-additional-template-props (list :finalize 'find-file))
|
||||
(org-roam--with-template-error 'org-roam-dailies-capture-templates
|
||||
(org-roam-capture--capture))))
|
||||
|
||||
|
272
org-roam-db.el
272
org-roam-db.el
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -48,6 +48,8 @@
|
||||
(declare-function org-roam--extract-headlines "org-roam")
|
||||
(declare-function org-roam--extract-links "org-roam")
|
||||
(declare-function org-roam--list-all-files "org-roam")
|
||||
(declare-function org-roam--path-to-slug "org-roam")
|
||||
(declare-function org-roam--file-name-extension "org-roam")
|
||||
(declare-function org-roam-buffer--update-maybe "org-roam-buffer")
|
||||
|
||||
;;;; Options
|
||||
@ -60,7 +62,22 @@ when used with multiple Org-roam instances."
|
||||
:type 'string
|
||||
:group 'org-roam)
|
||||
|
||||
(defconst org-roam-db--version 6)
|
||||
(defcustom org-roam-db-gc-threshold gc-cons-threshold
|
||||
"The value to temporarily set the `gc-cons-threshold' threshold to.
|
||||
During large, heavy operations like `org-roam-db-build-cache',
|
||||
many GC operations happen because of the large number of
|
||||
temporary structures generated (e.g. parsed ASTs). Temporarily
|
||||
increasing `gc-cons-threshold' will help reduce the number of GC
|
||||
operations, at the cost of temporary memory usage.
|
||||
|
||||
This defaults to the original value of `gc-cons-threshold', but
|
||||
tweaking this number may lead to better overall performance. For
|
||||
example, to reduce the number of GCs, one may set it to a large
|
||||
value like `most-positive-fixnum'."
|
||||
:type 'int
|
||||
:group 'org-roam)
|
||||
|
||||
(defconst org-roam-db--version 7)
|
||||
|
||||
(defvar org-roam-db--connection (make-hash-table :test #'equal)
|
||||
"Database connection to Org-roam database.")
|
||||
@ -68,7 +85,7 @@ when used with multiple Org-roam instances."
|
||||
;;;; Core Functions
|
||||
(defun org-roam-db--get ()
|
||||
"Return the sqlite db file."
|
||||
(or org-roam-db-location
|
||||
(or org-roam-db-location
|
||||
(expand-file-name "org-roam.db" org-roam-directory)))
|
||||
|
||||
(defun org-roam-db--get-connection ()
|
||||
@ -137,7 +154,7 @@ SQL can be either the emacsql vector representation, or a string."
|
||||
|
||||
(titles
|
||||
[(file :not-null)
|
||||
titles])
|
||||
title])
|
||||
|
||||
(refs
|
||||
[(ref :unique :not-null)
|
||||
@ -179,7 +196,7 @@ the current `org-roam-directory'."
|
||||
;;;; Database API
|
||||
;;;;; Initialization
|
||||
(defun org-roam-db--initialized-p ()
|
||||
"Whether the cache has been initialized."
|
||||
"Whether the Org-roam cache has been initialized."
|
||||
(and (file-exists-p (org-roam-db--get))
|
||||
(> (caar (org-roam-db-query [:select (funcall count) :from titles]))
|
||||
0)))
|
||||
@ -190,8 +207,8 @@ the current `org-roam-directory'."
|
||||
(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."
|
||||
(defun org-roam-db-clear ()
|
||||
"Clears all entries in the Org-roam cache."
|
||||
(interactive)
|
||||
(when (file-exists-p (org-roam-db--get))
|
||||
(dolist (table (mapcar #'car org-roam-db--table-schemata))
|
||||
@ -227,14 +244,29 @@ This is equivalent to removing the node from the graph."
|
||||
(org-roam-db-query
|
||||
[:insert :into titles
|
||||
:values $v1]
|
||||
(list (vector file titles))))
|
||||
(mapcar (lambda (title)
|
||||
(vector file title)) titles)))
|
||||
|
||||
(defun org-roam-db--insert-headlines (headlines)
|
||||
"Insert HEADLINES into the Org-roam cache."
|
||||
(org-roam-db-query
|
||||
[:insert :into headlines
|
||||
:values $v1]
|
||||
headlines))
|
||||
"Insert HEADLINES into the Org-roam cache.
|
||||
Returns t if the insertion was successful, nil otherwise.
|
||||
Insertions can fail when there is an ID conflict."
|
||||
(condition-case nil
|
||||
(progn
|
||||
(org-roam-db-query
|
||||
[:insert :into headlines
|
||||
:values $v1]
|
||||
headlines)
|
||||
t)
|
||||
(error
|
||||
(unless (listp headlines)
|
||||
(setq headlines (list headlines)))
|
||||
(lwarn '(org-roam) :error
|
||||
(format "Duplicate IDs in %s, one of:\n\n%s\n\nskipping..."
|
||||
(aref (car headlines) 1)
|
||||
(string-join (mapcar (lambda (hl)
|
||||
(aref hl 0)) headlines) "\n")))
|
||||
nil)))
|
||||
|
||||
(defun org-roam-db--insert-tags (file tags)
|
||||
"Insert TAGS for a FILE into the Org-roam cache."
|
||||
@ -244,12 +276,27 @@ This is equivalent to removing the node from the graph."
|
||||
(list (vector file tags))))
|
||||
|
||||
(defun org-roam-db--insert-ref (file ref)
|
||||
"Insert REF for FILE into the Org-roam cache."
|
||||
"Insert REF for FILE into the Org-roam cache.
|
||||
Returns t if successful, and nil otherwise.
|
||||
Insertions can fail if the key is already in the database."
|
||||
(let ((key (cdr ref))
|
||||
(type (car ref)))
|
||||
(org-roam-db-query
|
||||
[:insert :into refs :values $v1]
|
||||
(list (vector key file type)))))
|
||||
(condition-case nil
|
||||
(progn
|
||||
(org-roam-db-query
|
||||
[:insert :into refs :values $v1]
|
||||
(list (vector key file type)))
|
||||
t)
|
||||
(error
|
||||
(lwarn '(org-roam) :error
|
||||
(format "Duplicate ref %s in:\n\nA: %s\nB: %s\n\nskipping..."
|
||||
key
|
||||
file
|
||||
(caar (org-roam-db-query
|
||||
[:select file :from refs
|
||||
:where (= ref $v1)]
|
||||
(vector key)))))
|
||||
nil))))
|
||||
|
||||
;;;;; Fetching
|
||||
(defun org-roam-db--get-current-files ()
|
||||
@ -262,10 +309,10 @@ This is equivalent to removing the node from the graph."
|
||||
|
||||
(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)))
|
||||
(caar (org-roam-db-query [:select [title] :from titles
|
||||
:where (= file $s1)
|
||||
:limit 1]
|
||||
file)))
|
||||
|
||||
(defun org-roam-db--connected-component (file)
|
||||
"Return all files reachable from/connected to FILE, including the file itself.
|
||||
@ -321,6 +368,26 @@ connections, nil is returned."
|
||||
(files (mapcar 'car-safe (emacsql (org-roam-db) query file max-distance))))
|
||||
files))
|
||||
|
||||
(defun org-roam-db--file-hash (&optional file-path)
|
||||
"Compute the hash of FILE-PATH, a file or current buffer."
|
||||
(let* ((file-p (and file-path))
|
||||
(file-path (or file-path
|
||||
(buffer-file-name (current-buffer))))
|
||||
(encrypted-p (and file-path
|
||||
(string= (org-roam--file-name-extension file-path)
|
||||
"gpg"))))
|
||||
(cond ((and encrypted-p file-p)
|
||||
(with-temp-buffer
|
||||
(set-buffer-multibyte nil)
|
||||
(insert-file-contents-literally file-path)
|
||||
(secure-hash 'sha1 (current-buffer))))
|
||||
(file-p
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file-path)
|
||||
(secure-hash 'sha1 (current-buffer))))
|
||||
(t
|
||||
(secure-hash 'sha1 (current-buffer))))))
|
||||
|
||||
;;;;; Updating
|
||||
(defun org-roam-db--update-meta ()
|
||||
"Update the metadata of the current buffer into the cache."
|
||||
@ -328,7 +395,7 @@ connections, nil is returned."
|
||||
(attr (file-attributes file))
|
||||
(atime (file-attribute-access-time attr))
|
||||
(mtime (file-attribute-modification-time attr))
|
||||
(hash (secure-hash 'sha1 (current-buffer))))
|
||||
(hash (org-roam-db--file-hash)))
|
||||
(org-roam-db-query [:delete :from files
|
||||
:where (= file $s1)]
|
||||
file)
|
||||
@ -337,11 +404,12 @@ connections, nil is returned."
|
||||
(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)))
|
||||
(titles (or (org-roam--extract-titles)
|
||||
(list (org-roam--path-to-slug file)))))
|
||||
(org-roam-db-query [:delete :from titles
|
||||
:where (= file $s1)]
|
||||
file)
|
||||
(org-roam-db--insert-titles file title)))
|
||||
(org-roam-db--insert-titles file titles)))
|
||||
|
||||
(defun org-roam-db--update-tags ()
|
||||
"Update the tags of the current buffer into the cache."
|
||||
@ -388,12 +456,13 @@ connections, nil is returned."
|
||||
(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-headlines)
|
||||
(org-roam-db--update-links)
|
||||
(emacsql-with-transaction (org-roam-db)
|
||||
(org-roam-db--update-meta)
|
||||
(org-roam-db--update-tags)
|
||||
(org-roam-db--update-titles)
|
||||
(org-roam-db--update-refs)
|
||||
(org-roam-db--update-headlines)
|
||||
(org-roam-db--update-links))
|
||||
(org-roam-buffer--update-maybe :redisplay t))))))
|
||||
|
||||
(defun org-roam-db-build-cache (&optional force)
|
||||
@ -403,91 +472,74 @@ If FORCE, force a rebuild of the cache from scratch."
|
||||
(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))
|
||||
(let* ((gc-cons-threshold org-roam-db-gc-threshold)
|
||||
(org-roam-files (org-roam--list-all-files))
|
||||
(current-files (org-roam-db--get-current-files))
|
||||
all-files all-headlines all-links all-titles all-refs all-tags)
|
||||
;; Two-step building
|
||||
;; First step: Rebuild files and headlines
|
||||
(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 file
|
||||
(let ((contents-hash (secure-hash 'sha1 (current-buffer))))
|
||||
(file-count 0)
|
||||
(headline-count 0)
|
||||
(link-count 0)
|
||||
(tag-count 0)
|
||||
(title-count 0)
|
||||
(ref-count 0)
|
||||
(deleted-count 0))
|
||||
(emacsql-with-transaction (org-roam-db)
|
||||
;; Two-step building
|
||||
;; First step: Rebuild files and headlines
|
||||
(dolist (file org-roam-files)
|
||||
(let* ((attr (file-attributes file))
|
||||
(atime (file-attribute-access-time attr))
|
||||
(mtime (file-attribute-modification-time attr)))
|
||||
(let ((contents-hash (org-roam-db--file-hash file)))
|
||||
(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 (headlines (org-roam--extract-headlines file))
|
||||
(push headlines all-headlines)))))))
|
||||
(when all-files
|
||||
(org-roam-db-query
|
||||
[:insert :into files
|
||||
:values $v1]
|
||||
all-files))
|
||||
(when all-headlines
|
||||
(org-roam-db-query
|
||||
[:insert :into headlines
|
||||
:values $v1]
|
||||
all-headlines))
|
||||
;; Second step: Rebuild the rest
|
||||
(dolist (file org-roam-files)
|
||||
(org-roam--with-temp-buffer file
|
||||
(let ((contents-hash (secure-hash 'sha1 (current-buffer))))
|
||||
(org-roam--with-temp-buffer file
|
||||
(org-roam-db--clear-file file)
|
||||
(org-roam-db-query
|
||||
[:insert :into files
|
||||
:values $v1]
|
||||
(vector file contents-hash (list :atime atime :mtime mtime)))
|
||||
(setq file-count (1+ file-count))
|
||||
(when-let ((headlines (org-roam--extract-headlines file)))
|
||||
(when (org-roam-db--insert-headlines headlines)
|
||||
(setq headline-count (1+ headline-count)))))))))
|
||||
;; Second step: Rebuild the rest
|
||||
(dolist (file org-roam-files)
|
||||
(let ((contents-hash (org-roam-db--file-hash file)))
|
||||
(unless (string= (gethash file current-files)
|
||||
contents-hash)
|
||||
(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-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)
|
||||
:headlines (length all-headlines)
|
||||
: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, headlines: %s, links: %s, tags: %s, titles: %s, refs: %s, deleted: %s"
|
||||
(plist-get stats :files)
|
||||
(plist-get stats :headlines)
|
||||
(plist-get stats :links)
|
||||
(plist-get stats :tags)
|
||||
(plist-get stats :titles)
|
||||
(plist-get stats :refs)
|
||||
(plist-get stats :deleted))
|
||||
stats)))
|
||||
(org-roam--with-temp-buffer file
|
||||
(when-let (links (org-roam--extract-links file))
|
||||
(org-roam-db-query
|
||||
[:insert :into links
|
||||
:values $v1]
|
||||
links)
|
||||
(setq link-count (1+ link-count)))
|
||||
(when-let (tags (org-roam--extract-tags file))
|
||||
(org-roam-db-query
|
||||
[:insert :into tags
|
||||
:values $v1]
|
||||
(vector file tags))
|
||||
(setq tag-count (1+ tag-count)))
|
||||
(let ((titles (or (org-roam--extract-titles)
|
||||
(list (org-roam--path-to-slug file)))))
|
||||
(org-roam-db--insert-titles file titles)
|
||||
(setq title-count (+ title-count (length titles))))
|
||||
(when-let* ((ref (org-roam--extract-ref)))
|
||||
(when (org-roam-db--insert-ref file ref)
|
||||
(setq ref-count (1+ ref-count))))))
|
||||
(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)
|
||||
(setq deleted-count (1+ deleted-count))))
|
||||
(org-roam-message "files: Δ%s, headlines: Δ%s, links: Δ%s, tags: Δ%s, titles: Δ%s, refs: Δ%s, deleted: Δ%s"
|
||||
file-count
|
||||
headline-count
|
||||
link-count
|
||||
tag-count
|
||||
title-count
|
||||
ref-count
|
||||
deleted-count)))
|
||||
|
||||
(provide 'org-roam-db)
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -33,7 +33,14 @@
|
||||
;;
|
||||
;;; Code:
|
||||
(require 'emacsql)
|
||||
(emacsql-fix-vector-indentation)
|
||||
(provide 'org-roam-dev)
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode org-roam-dev-mode
|
||||
"Minor mode for setting the dev environment of Org-roam."
|
||||
:lighter " ORD"
|
||||
(when org-roam-dev-mode
|
||||
(emacsql-fix-vector-indentation)
|
||||
(setq-local sentence-end-double-space nil)))
|
||||
|
||||
(provide 'org-roam-dev)
|
||||
;;; org-roam-dev.el ends here
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/jethrokuan/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -192,14 +192,16 @@ into a digraph."
|
||||
","))))
|
||||
(dolist (node nodes)
|
||||
(let* ((file (xml-escape-string (car node)))
|
||||
(title (or (caadr node)
|
||||
(title (or (cadr 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)))
|
||||
(shortened-title (org-roam-string-quote shortened-title))
|
||||
(title (org-roam-string-quote title))
|
||||
(node-properties
|
||||
`(("label" . ,(s-replace "\"" "\\\"" shortened-title))
|
||||
`(("label" . ,shortened-title)
|
||||
("URL" . ,(concat "org-protocol://roam-file?file=" (url-hexify-string file)))
|
||||
("tooltip" . ,(xml-escape-string title)))))
|
||||
(insert
|
||||
@ -230,8 +232,9 @@ CALLBACK is passed the graph file as its sole argument."
|
||||
"Please adjust `org-roam-graph-executable'")
|
||||
org-roam-graph-executable))
|
||||
(let* ((node-query (or node-query
|
||||
`[:select [file titles] :from titles
|
||||
,@(org-roam-graph--expand-matcher 'file t)]))
|
||||
`[:select [file title] :from titles
|
||||
,@(org-roam-graph--expand-matcher 'file t)
|
||||
:group :by file]))
|
||||
(graph (org-roam-graph--dot node-query))
|
||||
(temp-dot (make-temp-file "graph." nil ".dot" graph))
|
||||
(temp-graph (make-temp-file "graph." nil ".svg")))
|
||||
@ -267,7 +270,7 @@ CALLBACK is passed to `org-roam-graph--build'."
|
||||
(org-roam-db--links-with-max-distance file max-distance)
|
||||
(org-roam-db--connected-component file))
|
||||
(list file)))
|
||||
(query `[:select [file titles]
|
||||
(query `[:select [file title]
|
||||
:from titles
|
||||
:where (in file [,@files])]))
|
||||
(org-roam-graph--build query callback)))
|
||||
|
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -33,6 +33,7 @@
|
||||
;;
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
(require 'dash)
|
||||
|
||||
(defvar org-roam-verbose)
|
||||
|
||||
@ -44,7 +45,9 @@ If FILE, set `org-roam-temp-file-name' to file and insert its contents."
|
||||
(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))
|
||||
(let ((org-roam-directory ,current-org-roam-directory)
|
||||
(org-mode-hook nil))
|
||||
(org-mode)
|
||||
(when ,file
|
||||
(insert-file-contents ,file)
|
||||
(setq-local org-roam-file-name ,file))
|
||||
@ -68,6 +71,12 @@ to look.
|
||||
(when org-roam-verbose
|
||||
(apply #'message `(,(concat "(org-roam) " format-string) ,@args))))
|
||||
|
||||
(defun org-roam-string-quote (str)
|
||||
"Quote STR."
|
||||
(->> str
|
||||
(s-replace "\\" "\\\\")
|
||||
(s-replace "\"" "\\\"")))
|
||||
|
||||
(provide 'org-roam-macs)
|
||||
|
||||
;;; org-roam-macs.el ends here
|
||||
|
@ -4,7 +4,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.1
|
||||
;; Package-Requires: ((emacs "26.1") (org "9.3"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -56,7 +56,7 @@ It opens or creates a note with the given ref.
|
||||
(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))
|
||||
(push (cons 'slug (funcall org-roam-title-to-slug-function title)) decoded-alist))
|
||||
(let* ((org-roam-capture-templates org-roam-capture-ref-templates)
|
||||
(org-roam-capture--context 'ref)
|
||||
(org-roam-capture--info decoded-alist)
|
||||
@ -78,7 +78,7 @@ It should contain the FILE key, pointing to the path of the file to open.
|
||||
org-protocol://roam-file?file=/path/to/file.org"
|
||||
(when-let ((file (plist-get info :file)))
|
||||
(raise-frame)
|
||||
(find-file file))
|
||||
(org-roam--find-file file))
|
||||
nil)
|
||||
|
||||
(push '("org-roam-ref" :protocol "roam-ref" :function org-roam-protocol-open-ref)
|
||||
|
329
org-roam.el
329
org-roam.el
@ -5,7 +5,7 @@
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam
|
||||
;; Keywords: org-mode, roam, convenience
|
||||
;; Version: 1.2.0
|
||||
;; Version: 1.2.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-sqlite3 "1.0.0"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
@ -70,14 +70,13 @@
|
||||
(defvar org-id-link-to-org-use-id)
|
||||
(declare-function org-id-find-id-in-file "ext:org-id" (id file &optional markerp))
|
||||
|
||||
|
||||
;;;; Customizable variables
|
||||
(defgroup org-roam nil
|
||||
"Roam Research replica in Org-mode."
|
||||
:group 'org
|
||||
:prefix "org-roam-"
|
||||
:link '(url-link :tag "Github" "https://github.com/org-roam/org-roam")
|
||||
:link '(url-link :tag "Online Manual" "https://org-roam.github.io/org-roam/manual/"))
|
||||
:link '(url-link :tag "Online Manual" "https://www.orgroam.com/manual/"))
|
||||
|
||||
(defgroup org-roam-faces nil
|
||||
"Faces used by Org-roam."
|
||||
@ -104,6 +103,12 @@ ensure that."
|
||||
:type '(repeat string)
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-find-file-function nil
|
||||
"Function called when visiting files in Org-roam commands.
|
||||
If nil, `find-file' is used."
|
||||
:type 'function
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-include-type-in-ref-path-completions nil
|
||||
"When t, include the type in ref-path completions.
|
||||
Note that this only affects interactive calls.
|
||||
@ -197,10 +202,22 @@ extraction methods:
|
||||
`last-directory'
|
||||
Extract the last directory relative to `org-roam-directory'.
|
||||
That is, if a file is located at relative path foo/bar/file.org,
|
||||
the file will have tag \"bar\"."
|
||||
:type '(set (const :tag "#+roam_tags" PROP)
|
||||
the file will have tag \"bar\".
|
||||
|
||||
`first-directory'
|
||||
Extract the first directory relative to `org-roam-directory'.
|
||||
That is, if a file is located at relative path foo/bar/file.org,
|
||||
the file will have tag \"foo\"."
|
||||
:type '(set (const :tag "#+roam_tags" prop)
|
||||
(const :tag "sub-directories" all-directories)
|
||||
(const :tag "parent directory" last-directory)))
|
||||
(const :tag "parent directory" last-directory)
|
||||
(const :tag "first sub-directory" first-directory)))
|
||||
|
||||
(defcustom org-roam-title-to-slug-function #'org-roam--title-to-slug
|
||||
"Function to be used in converting a title to the filename slug.
|
||||
Function should return a filename string based on title."
|
||||
:type 'function
|
||||
:group 'org-roam)
|
||||
|
||||
(defcustom org-roam-title-sources '((title headline) alias)
|
||||
"The list of sources from which to retrieve a note title.
|
||||
@ -489,10 +506,46 @@ PATH should be the root from which to compute the relativity."
|
||||
(when (f-relative-p link)
|
||||
(delete-region (match-beginning 1)
|
||||
(match-end 1))
|
||||
(insert (expand-file-name
|
||||
(concat dir link)))))
|
||||
(insert (expand-file-name link dir))))
|
||||
(buffer-string))))
|
||||
|
||||
(defun org-roam--get-outline-path ()
|
||||
"Return the outline path to the current entry.
|
||||
|
||||
An outline path is a list of ancestors for current headline, as a
|
||||
list of strings. Statistics cookies are removed and links are
|
||||
kept.
|
||||
|
||||
When optional argument WITH-SELF is non-nil, the path also
|
||||
includes the current headline."
|
||||
(org-with-wide-buffer
|
||||
(save-match-data
|
||||
(and (or (condition-case nil
|
||||
(org-back-to-heading t)
|
||||
(error nil))
|
||||
(org-up-heading-safe))
|
||||
(reverse (org-roam--get-outline-path-1))))))
|
||||
|
||||
(defun org-roam--get-outline-path-1 ()
|
||||
"Return outline path to current headline.
|
||||
|
||||
Outline path is a list of strings, in reverse order. See
|
||||
`org-roam--get-outline-path' for details.
|
||||
|
||||
Assume buffer is widened and point is on a headline."
|
||||
(when org-complex-heading-regexp
|
||||
(let ((heading (let ((case-fold-search nil))
|
||||
(looking-at org-complex-heading-regexp)
|
||||
(if (not (match-end 4)) ""
|
||||
;; Remove statistics cookies.
|
||||
(org-trim
|
||||
(replace-regexp-in-string
|
||||
"\\[[0-9]+%\\]\\|\\[[0-9]+/[0-9]+\\]" ""
|
||||
(match-string-no-properties 4)))))))
|
||||
(if (org-up-heading-safe)
|
||||
(cons heading (org-roam--get-outline-path-1))
|
||||
(list heading)))))
|
||||
|
||||
(defun org-roam--extract-links (&optional file-path)
|
||||
"Extracts all link items within the current buffer.
|
||||
Link items are of the form:
|
||||
@ -503,6 +556,7 @@ This is the format that emacsql expects when inserting into the database.
|
||||
FILE-FROM is typically the buffer file path, but this may not exist, for example
|
||||
in temp buffers. In cases where this occurs, we do know the file path, and pass
|
||||
it as FILE-PATH."
|
||||
(require 'org-ref nil t)
|
||||
(let ((file-path (or file-path
|
||||
(file-truename (buffer-file-name))))
|
||||
links)
|
||||
@ -510,47 +564,45 @@ it as FILE-PATH."
|
||||
(lambda (link)
|
||||
(let* ((type (org-element-property :type link))
|
||||
(path (org-element-property :path link))
|
||||
(start (org-element-property :begin link))
|
||||
(id-data (org-roam-id-find path))
|
||||
(link-type (cond ((and (string= type "file")
|
||||
(org-roam--org-file-p path))
|
||||
"file")
|
||||
((and (string= type "id")
|
||||
id-data)
|
||||
"id")
|
||||
((and
|
||||
(require 'org-ref nil t)
|
||||
(-contains? org-ref-cite-types type))
|
||||
"cite")
|
||||
(t nil))))
|
||||
(when link-type
|
||||
(goto-char start)
|
||||
(let* ((element (org-element-at-point))
|
||||
(begin (or (org-element-property :content-begin element)
|
||||
(org-element-property :begin element)))
|
||||
(content (or (org-element-property :raw-value element)
|
||||
(buffer-substring-no-properties
|
||||
begin
|
||||
(or (org-element-property :content-end element)
|
||||
(org-element-property :end element)))))
|
||||
(content (string-trim content))
|
||||
;; Expand all relative links to absolute links
|
||||
(content (org-roam--expand-links content file-path)))
|
||||
(let ((context (list :content content :point begin))
|
||||
(names (pcase link-type
|
||||
("file"
|
||||
(list (file-truename (expand-file-name path (file-name-directory file-path)))))
|
||||
("id"
|
||||
(list (car id-data)))
|
||||
("cite"
|
||||
(org-ref-split-and-strip-string path)))))
|
||||
(seq-do (lambda (name)
|
||||
(start (org-element-property :begin link)))
|
||||
(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-no-properties
|
||||
begin
|
||||
(or (org-element-property :content-end element)
|
||||
(org-element-property :end element)))))
|
||||
(content (string-trim content))
|
||||
;; Expand all relative links to absolute links
|
||||
(content (org-roam--expand-links content file-path)))
|
||||
(let ((properties (list :outline (mapcar (lambda (path)
|
||||
(org-roam--expand-links path file-path))
|
||||
(org-roam--get-outline-path))
|
||||
:content content
|
||||
:point begin))
|
||||
(names (pcase type
|
||||
("file"
|
||||
(if (file-remote-p path)
|
||||
(list path)
|
||||
(list (file-truename (expand-file-name path (file-name-directory file-path))))))
|
||||
("id"
|
||||
(list (car (org-roam-id-find path))))
|
||||
((pred (lambda (typ)
|
||||
(and (boundp 'org-ref-cite-types)
|
||||
(-contains? org-ref-cite-types typ))))
|
||||
(setq type "cite")
|
||||
(org-ref-split-and-strip-string path))
|
||||
(_ (list (org-element-property :raw-link link))))))
|
||||
(seq-do (lambda (name)
|
||||
(when name
|
||||
(push (vector file-path
|
||||
name
|
||||
link-type
|
||||
context)
|
||||
links))
|
||||
names)))))))
|
||||
type
|
||||
properties)
|
||||
links)))
|
||||
names))))))
|
||||
links))
|
||||
|
||||
(defun org-roam--extract-headlines (&optional file-path)
|
||||
@ -621,16 +673,24 @@ If NESTED, return the first successful result from SOURCES."
|
||||
"Extract tags from using the directory path FILE.
|
||||
All sub-directories relative to `org-roam-directory' are used as tags."
|
||||
(when-let ((dir-relative (file-name-directory
|
||||
(file-relative-name file org-roam-directory))))
|
||||
(file-relative-name file (file-truename org-roam-directory)))))
|
||||
(f-split dir-relative)))
|
||||
|
||||
(defun org-roam--extract-tags-last-directory (file)
|
||||
"Extract tags from using the directory path FILE.
|
||||
The final directory component is used as a tag."
|
||||
(when-let ((dir-relative (file-name-directory
|
||||
(file-relative-name file org-roam-directory))))
|
||||
(file-relative-name file (file-truename org-roam-directory)))))
|
||||
(last (f-split dir-relative))))
|
||||
|
||||
(defun org-roam--extract-tags-first-directory (file)
|
||||
"Extract tags from path FILE.
|
||||
The first directory component after `org-roam-directory' is used as a
|
||||
tag."
|
||||
(when-let ((dir-relative (file-name-directory
|
||||
(file-relative-name file (file-truename org-roam-directory)))))
|
||||
(list (car (f-split dir-relative)))))
|
||||
|
||||
(defun org-roam--extract-tags-prop (_file)
|
||||
"Extract tags from the current buffer's \"#roam_tags\" global property."
|
||||
(let* ((prop (cdr (assoc "ROAM_TAGS" (org-roam--extract-global-props '("ROAM_TAGS"))))))
|
||||
@ -718,7 +778,7 @@ Examples:
|
||||
|
||||
(defun org-roam--get-title-or-slug (path)
|
||||
"Convert `PATH' to the file title, if it exists. Else, return the path."
|
||||
(or (car (org-roam-db--get-titles path))
|
||||
(or (org-roam-db--get-titles path)
|
||||
(org-roam--path-to-slug path)))
|
||||
|
||||
(defun org-roam--title-to-slug (title)
|
||||
@ -761,7 +821,7 @@ Examples:
|
||||
"Return an alist for completion.
|
||||
The car is the displayed title for completion, and the cdr is the
|
||||
to the file."
|
||||
(let* ((rows (org-roam-db-query [:select [titles:file titles:titles tags:tags files:meta] :from titles
|
||||
(let* ((rows (org-roam-db-query [:select [files:file titles:title tags:tags files:meta] :from titles
|
||||
:left :join tags
|
||||
:on (= titles:file tags:file)
|
||||
:left :join files
|
||||
@ -772,15 +832,13 @@ to the file."
|
||||
#'time-less-p
|
||||
rows)
|
||||
(dolist (row rows completions)
|
||||
(pcase-let ((`(,file-path ,titles ,tags) row))
|
||||
(let ((titles (or titles (list (org-roam--path-to-slug file-path)))))
|
||||
(dolist (title titles)
|
||||
(let ((k (concat
|
||||
(pcase-let ((`(,file-path ,title ,tags) row))
|
||||
(let ((k (concat
|
||||
(when tags
|
||||
(format "(%s) " (s-join org-roam-tag-separator tags)))
|
||||
title))
|
||||
(v (list :path file-path :title title)))
|
||||
(push (cons k v) completions))))))))
|
||||
(push (cons k v) completions))))))
|
||||
|
||||
(defun org-roam--get-index-path ()
|
||||
"Return the path to the index in `org-roam-directory'.
|
||||
@ -800,43 +858,61 @@ whose title is 'Index'."
|
||||
index)))
|
||||
|
||||
;;;; org-roam-find-ref
|
||||
(defun org-roam--get-ref-path-completions (&optional interactive filter)
|
||||
(defun org-roam--get-ref-path-completions (&optional arg filter)
|
||||
"Return an alist of refs to absolute path of Org-roam files.
|
||||
When `org-roam-include-type-in-ref-path-completions' and
|
||||
INTERACTIVE are non-nil, format the car of the
|
||||
completion-candidates as 'type:ref'.
|
||||
|
||||
When called interactively (i.e. when ARG is 1), formats the car
|
||||
of the completion-candidates with extra information: title, tags,
|
||||
and type \(when `org-roam-include-type-in-ref-path-completions'
|
||||
is non-nil).
|
||||
|
||||
When called with a `C-u' prefix (i.e. when ARG is 4), forces the
|
||||
default format without the formatting.
|
||||
|
||||
FILTER can either be a string or a function:
|
||||
|
||||
- If it is a string, it should be the type of refs to include as
|
||||
candidates (e.g. \"cite\" ,\"website\" ,etc.)
|
||||
candidates \(e.g. \"cite\", \"website\", etc.)
|
||||
|
||||
- If it is a function, it should be the name of a function that
|
||||
takes three arguments: the type, the ref, and the file of the
|
||||
current candidate. It should return t if that candidate is to be
|
||||
included as a candidate."
|
||||
(let ((rows (org-roam-db-query [:select [refs:type refs:ref refs:file ] :from refs
|
||||
:left :join files
|
||||
:on (= refs:file files:file)]))
|
||||
(include-type (and interactive
|
||||
org-roam-include-type-in-ref-path-completions))
|
||||
takes three arguments: the type, the ref, and the file of the
|
||||
current candidate. It should return t if that candidate is to
|
||||
be included as a candidate."
|
||||
(let ((rows (org-roam-db-query
|
||||
[:select [refs:type refs:ref refs:file titles:title tags:tags]
|
||||
:from titles
|
||||
:left :join tags
|
||||
:on (= titles:file tags:file)
|
||||
:left :join refs :on (= titles:file refs:file)
|
||||
:where refs:file :is :not :null]))
|
||||
completions)
|
||||
(seq-sort-by (lambda (x)
|
||||
(plist-get (nth 3 x) :mtime))
|
||||
#'time-less-p
|
||||
rows)
|
||||
(dolist (row rows completions)
|
||||
(pcase-let ((`(,type ,ref ,file-path) row))
|
||||
(pcase-let ((`(,type ,ref ,file-path ,title ,tags) row))
|
||||
(when (pcase filter
|
||||
('nil t)
|
||||
((pred stringp) (string= type filter))
|
||||
((pred functionp) (funcall filter type ref file-path))
|
||||
(wrong-type (signal 'wrong-type-argument
|
||||
`((stringp functionp)
|
||||
,wrong-type))))
|
||||
(let ((k (concat
|
||||
(when include-type
|
||||
(format "(%s) " type))
|
||||
ref))
|
||||
(v (list :path file-path :type type :ref ref)))
|
||||
(push (cons k v) completions)))))))
|
||||
('nil t)
|
||||
((pred stringp) (string= type filter))
|
||||
((pred functionp) (funcall filter type ref file-path))
|
||||
(wrong-type (signal 'wrong-type-argument
|
||||
`((stringp functionp)
|
||||
,wrong-type))))
|
||||
(let ((k (if (eq arg 1)
|
||||
(concat
|
||||
(when org-roam-include-type-in-ref-path-completions
|
||||
(format "{%s} " type))
|
||||
(when tags
|
||||
(format "(%s) " (s-join org-roam-tag-separator tags)))
|
||||
(format "%s (%s)" title ref))
|
||||
ref))
|
||||
(v (list :path file-path :type type :ref ref)))
|
||||
(push (cons k v) completions)))))))
|
||||
|
||||
(defun org-roam--find-file (file)
|
||||
"Open FILE using `org-roam-find-file-function' or `find-file'."
|
||||
(funcall (or org-roam-find-file-function #'find-file) file))
|
||||
|
||||
(defun org-roam--find-ref (ref)
|
||||
"Find and open and Org-roam file from REF if it exists.
|
||||
@ -845,7 +921,7 @@ type-information (e.g. 'cite:').
|
||||
Return nil if the file does not exist."
|
||||
(when-let* ((completions (org-roam--get-ref-path-completions))
|
||||
(file (plist-get (cdr (assoc ref completions)) :path)))
|
||||
(find-file file)))
|
||||
(org-roam--find-file file)))
|
||||
|
||||
(defun org-roam--get-roam-buffers ()
|
||||
"Return a list of buffers that are Org-roam files."
|
||||
@ -929,7 +1005,8 @@ Applies `org-roam-link-current' if PATH corresponds to the
|
||||
currently opened Org-roam file in the backlink buffer, or
|
||||
`org-roam-link-face' if PATH corresponds to any other Org-roam
|
||||
file."
|
||||
(cond ((not (file-exists-p path))
|
||||
(cond ((and (not (file-remote-p path)) ;; Prevent lockups opening Tramp links
|
||||
(not (file-exists-p path)))
|
||||
'org-roam-link-invalid)
|
||||
((and (org-roam--in-buffer-p)
|
||||
(org-roam--backlink-to-current-p))
|
||||
@ -969,27 +1046,19 @@ This function hooks into `org-open-at-point' via `org-open-at-point-functions'."
|
||||
(when (and (eq (org-element-type context) 'link)
|
||||
(string= "file" type)
|
||||
(org-roam--org-roam-file-p (file-truename path)))
|
||||
(org-roam--find-file path)
|
||||
(org-roam-buffer--find-file path)
|
||||
(org-show-context)
|
||||
t)))
|
||||
;; Org-roam preview text
|
||||
((when-let ((file-from (get-text-property (point) 'file-from))
|
||||
(p (get-text-property (point) 'file-from-point)))
|
||||
(org-roam--find-file file-from)
|
||||
(org-roam-buffer--find-file file-from)
|
||||
(goto-char p)
|
||||
(org-show-context)
|
||||
t))
|
||||
;; If called via `org-open-at-point', fall back to default behavior.
|
||||
(t nil)))
|
||||
|
||||
(defun org-roam--find-file (file)
|
||||
"Open FILE in the window `org-roam' was called from."
|
||||
(if (and org-roam-last-window (window-valid-p org-roam-last-window))
|
||||
(progn (with-selected-window org-roam-last-window
|
||||
(find-file file))
|
||||
(select-window org-roam-last-window))
|
||||
(find-file file)))
|
||||
|
||||
(defun org-roam--get-backlinks (target)
|
||||
"Return the backlinks for TARGET.
|
||||
TARGET may be a file, for Org-roam file links, or a citation key,
|
||||
@ -1164,13 +1233,15 @@ replaced links are made relative to the current buffer."
|
||||
new-file-or-dir)))
|
||||
(when (and (not (auto-save-file-name-p old-file))
|
||||
(not (auto-save-file-name-p new-file))
|
||||
(org-roam--org-roam-file-p new-file))
|
||||
(not (backup-file-name-p old-file))
|
||||
(not (backup-file-name-p new-file))
|
||||
(org-roam--org-roam-file-p old-file))
|
||||
(org-roam-db--ensure-built)
|
||||
(let* ((old-path (file-truename old-file))
|
||||
(new-path (file-truename new-file))
|
||||
(old-slug (org-roam--get-title-or-slug old-file))
|
||||
(old-desc (org-roam--format-link-title old-slug))
|
||||
(new-slug (or (car (org-roam-db--get-titles old-path))
|
||||
(new-slug (or (org-roam-db--get-titles old-path)
|
||||
(org-roam--path-to-slug new-path)))
|
||||
(new-desc (org-roam--format-link-title new-slug))
|
||||
(new-buffer (or (find-buffer-visiting new-path)
|
||||
@ -1201,7 +1272,8 @@ replaced links are made relative to the current buffer."
|
||||
(with-current-buffer new-buffer
|
||||
(org-roam--fix-relative-links old-path)
|
||||
(save-buffer)))
|
||||
(org-roam-db--update-file new-path)))))
|
||||
(when (org-roam--org-roam-file-p new-file)
|
||||
(org-roam-db--update-file new-path))))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode org-roam-mode
|
||||
@ -1227,7 +1299,9 @@ Otherwise, behave as if called interactively."
|
||||
:global t
|
||||
(cond
|
||||
(org-roam-mode
|
||||
(unless (executable-find "sqlite3")
|
||||
(unless (or (and (boundp 'emacsql-sqlite3-executable)
|
||||
(file-executable-p emacsql-sqlite3-executable))
|
||||
(executable-find "sqlite3"))
|
||||
(lwarn '(org-roam) :error "Cannot find executable 'sqlite3'. \
|
||||
Ensure it is installed and can be found within `exec-path'. \
|
||||
M-x info for more information at Org-roam > Installation > Post-Installation Tasks."))
|
||||
@ -1284,7 +1358,6 @@ which takes as its argument an alist of path-completions. See
|
||||
`org-roam--get-title-path-completions' for details."
|
||||
(interactive)
|
||||
(unless org-roam-mode (org-roam-mode))
|
||||
(when (org-roam-capture--in-process-p) (user-error "Org-roam capture in process"))
|
||||
(let* ((completions (funcall (or filter-fn #'identity)
|
||||
(or completions (org-roam--get-title-path-completions))))
|
||||
(title-with-tags (org-roam-completion--completing-read "File: " completions
|
||||
@ -1292,11 +1365,11 @@ which takes as its argument an alist of path-completions. See
|
||||
(res (cdr (assoc title-with-tags completions)))
|
||||
(file-path (plist-get res :path)))
|
||||
(if file-path
|
||||
(find-file file-path)
|
||||
(org-roam--find-file file-path)
|
||||
(let ((org-roam-capture--info `((title . ,title-with-tags)
|
||||
(slug . ,(org-roam--title-to-slug title-with-tags))))
|
||||
(slug . ,(funcall org-roam-title-to-slug-function title-with-tags))))
|
||||
(org-roam-capture--context 'title))
|
||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h)
|
||||
(setq org-roam-capture-additional-template-props (list :finalize 'find-file))
|
||||
(org-roam--with-template-error 'org-roam-capture-templates
|
||||
(org-roam-capture--capture))))))
|
||||
|
||||
@ -1304,7 +1377,7 @@ which takes as its argument an alist of path-completions. See
|
||||
(defun org-roam-find-directory ()
|
||||
"Find and open `org-roam-directory'."
|
||||
(interactive)
|
||||
(find-file org-roam-directory))
|
||||
(org-roam--find-file org-roam-directory))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-find-ref (arg &optional filter)
|
||||
@ -1326,11 +1399,18 @@ included as a candidate."
|
||||
:require-match t))
|
||||
(file (-> (cdr (assoc ref completions))
|
||||
(plist-get :path))))
|
||||
(find-file file)))
|
||||
(org-roam--find-file file)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-random-note ()
|
||||
"Find a random Org-roam file."
|
||||
(interactive)
|
||||
(find-file (seq-random-elt (org-roam--list-all-files))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-insert (&optional lowercase completions filter-fn description)
|
||||
"Find an Org-roam file, and insert a relative org link to it at point.
|
||||
Return selected file if it exists.
|
||||
If LOWERCASE, downcase the title before insertion.
|
||||
COMPLETIONS is a list of completions to be used instead of
|
||||
`org-roam--get-title-path-completions`.
|
||||
@ -1366,17 +1446,40 @@ If DESCRIPTION is provided, use this as the link label. See
|
||||
(when region ;; Remove previously selected text.
|
||||
(delete-region (car region) (cdr region)))
|
||||
(insert (org-roam--format-link target-file-path link-description)))
|
||||
(when (org-roam-capture--in-process-p)
|
||||
(user-error "Nested Org-roam capture processes not supported"))
|
||||
(let ((org-roam-capture--info `((title . ,title-with-tags)
|
||||
(slug . ,(org-roam--title-to-slug title-with-tags))))
|
||||
(slug . ,(funcall org-roam-title-to-slug-function title-with-tags))))
|
||||
(org-roam-capture--context 'title))
|
||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--insert-link-h)
|
||||
(setq org-roam-capture-additional-template-props (list :region region
|
||||
:insert-at (point-marker)
|
||||
:link-description link-description
|
||||
:capture-fn 'org-roam-insert))
|
||||
:finalize 'insert-link))
|
||||
(org-roam--with-template-error 'org-roam-capture-templates
|
||||
(org-roam-capture--capture))))))
|
||||
(org-roam-capture--capture))))
|
||||
res))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-insert-immediate (arg &rest args)
|
||||
"Find an Org-roam file, and insert a relative org link to it at point.
|
||||
This variant of `org-roam-insert' inserts the link immediately by
|
||||
using the template in `org-roam-capture-immediate-template'. The
|
||||
interactive ARG and ARGS are passed to `org-roam-insert'.
|
||||
See `org-roam-insert' for details."
|
||||
(interactive "P")
|
||||
(let ((args (push arg args))
|
||||
(org-roam-capture-templates (list org-roam-capture-immediate-template)))
|
||||
(apply #'org-roam-insert args)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-find-file-immediate (arg &rest args)
|
||||
"Find and open an Org-roam file.
|
||||
This variant of `org-roam-find-file' uses the template in
|
||||
`org-roam-capture-immediate-template', avoiding the capture
|
||||
process. The interactive ARG and ARGS are passed to
|
||||
`org-roam-find-file'. See `org-roam-find-file' for details."
|
||||
(interactive "P")
|
||||
(let ((args (push arg args))
|
||||
(org-roam-capture-templates (list org-roam-capture-immediate-template)))
|
||||
(apply #'org-roam-find-file args)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-jump-to-index ()
|
||||
@ -1390,7 +1493,7 @@ command will offer you to create one."
|
||||
(let ((index (org-roam--get-index-path)))
|
||||
(if (and index
|
||||
(file-exists-p index))
|
||||
(find-file index)
|
||||
(org-roam--find-file index)
|
||||
(when (y-or-n-p "Index file does not exist. Would you like to create it? ")
|
||||
(org-roam-find-file "Index")))))
|
||||
|
||||
@ -1438,7 +1541,7 @@ linked, lest the network graph get too crowded."
|
||||
(unless (org-roam--org-roam-file-p)
|
||||
(user-error "Not in org-roam file"))
|
||||
(if (not (executable-find "rg"))
|
||||
(user-error "Cannot find the \"rg\" executable, aborting")
|
||||
(error "Cannot find the ripgrep executable \"rg\". Check that it is installed and available on `exec-path'")
|
||||
(let* ((titles (org-roam--extract-titles))
|
||||
(rg-command (concat "rg -o --vimgrep -P -i "
|
||||
(string-join (mapcar (lambda (glob) (concat "-g " glob))
|
||||
@ -1451,7 +1554,7 @@ linked, lest the network graph get too crowded."
|
||||
(file-loc (buffer-file-name))
|
||||
(buf (get-buffer-create "*org-roam unlinked references*"))
|
||||
(results (split-string (shell-command-to-string rg-command) "\n"))
|
||||
(result-regex (rx (group (one-or-more anychar))
|
||||
(result-regex (rx (group (one-or-more anything))
|
||||
":"
|
||||
(group (one-or-more digit))
|
||||
":"
|
||||
|
14
tests/roam-files/headlines/headline.org
Normal file
14
tests/roam-files/headlines/headline.org
Normal file
@ -0,0 +1,14 @@
|
||||
#+TITLE: Headline
|
||||
|
||||
* Headline 1
|
||||
:PROPERTIES:
|
||||
:ID: e84d0630-efad-4017-9059-5ef917908823
|
||||
:END:
|
||||
|
||||
* No headline here
|
||||
Oops.
|
||||
|
||||
* Headline 2
|
||||
:PROPERTIES:
|
||||
:ID: 801b58eb-97e2-435f-a33e-ff59a2f0c213
|
||||
:END:
|
53
tests/test-org-roam-perf.el
Normal file
53
tests/test-org-roam-perf.el
Normal file
@ -0,0 +1,53 @@
|
||||
;;; test-org-roam-perf.el --- Performance Tests for Org-roam -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2020 Jethro Kuan
|
||||
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; Package-Requires: ((buttercup))
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;; Code:
|
||||
|
||||
(require 'buttercup)
|
||||
(require 'org-roam)
|
||||
|
||||
(defconst test-org-roam-perf-zip-url "https://github.com/org-roam/test-org-files/archive/master.zip"
|
||||
"Path to zip for test org-roam files.")
|
||||
|
||||
(defun test-org-roam-perf--abs-path (file-path)
|
||||
"Get absolute FILE-PATH from `org-roam-directory'."
|
||||
(file-truename (expand-file-name file-path org-roam-directory)))
|
||||
|
||||
(defun test-org-roam-perf--init ()
|
||||
"."
|
||||
(let* ((temp-loc (expand-file-name (make-temp-name "test-org-files-") temporary-file-directory))
|
||||
(zip-file-loc (concat temp-loc ".zip"))
|
||||
(_ (url-copy-file test-org-roam-perf-zip-url zip-file-loc))
|
||||
(_ (shell-command (format "mkdir -p %s && unzip -j -qq %s -d %s" temp-loc zip-file-loc temp-loc))))
|
||||
(setq org-roam-directory temp-loc)))
|
||||
|
||||
(describe "Cache Build"
|
||||
(it "cache build from scratch time to be acceptable"
|
||||
(test-org-roam-perf--init)
|
||||
(pcase (benchmark-run 1 (org-roam-db-build-cache t))
|
||||
(`(,time ,gcs ,time-in-gc)
|
||||
(message "Elapsed time: %fs (%fs in %d GCs)" time time-in-gc gcs)
|
||||
(expect time :to-be-less-than 100))))
|
||||
(it "builds quickly without change"
|
||||
(pcase (benchmark-run 1 (org-roam-db-build-cache))
|
||||
(`(,time ,gcs ,time-in-gc)
|
||||
(message "Elapsed time: %fs (%fs in %d GCs)" time time-in-gc gcs)
|
||||
(expect time :to-be-less-than 5)))))
|
@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 Jethro Kuan
|
||||
|
||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||
;; Package-Requires: ((buttercup) (with-simulated-input))
|
||||
;; Package-Requires: ((buttercup))
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
@ -211,6 +211,20 @@
|
||||
:to-equal
|
||||
'("deeply")))
|
||||
|
||||
(it "extracts from first directory"
|
||||
(expect (test #'org-roam--extract-tags-first-directory
|
||||
"base.org")
|
||||
:to-equal
|
||||
nil)
|
||||
(expect (test #'org-roam--extract-tags-first-directory
|
||||
"tags/tag.org")
|
||||
:to-equal
|
||||
'("tags"))
|
||||
(expect (test #'org-roam--extract-tags-first-directory
|
||||
"nested/deeply/deeply_nested_file.org")
|
||||
:to-equal
|
||||
'("nested")))
|
||||
|
||||
(describe "uses org-roam-tag-sources correctly"
|
||||
(it "'(prop)"
|
||||
(expect (let ((org-roam-tag-sources '(prop)))
|
||||
@ -225,6 +239,26 @@
|
||||
:to-equal
|
||||
'("t1" "t2 with space" "t3" "tags"))))))
|
||||
|
||||
(describe "Headline extraction"
|
||||
(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 headlines"
|
||||
(expect (test #'org-roam--extract-headlines
|
||||
"headlines/headline.org")
|
||||
:to-equal
|
||||
`(["e84d0630-efad-4017-9059-5ef917908823" ,(test-org-roam--abs-path "headlines/headline.org")]
|
||||
["801b58eb-97e2-435f-a33e-ff59a2f0c213" ,(test-org-roam--abs-path "headlines/headline.org")])))))
|
||||
|
||||
;;; Tests
|
||||
(xdescribe "org-roam-db-build-cache"
|
||||
(before-each
|
||||
|
Reference in New Issue
Block a user