mirror of
https://github.com/org-roam/org-roam
synced 2025-08-03 12:27:23 -05:00
Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
cc01cf346e | |||
eaf99cba03 | |||
65a2cb6efd | |||
bc12d1cf04 | |||
a86d82b20e | |||
d4c875b53b | |||
2159b6a846 | |||
1db4c22950 | |||
9c0f030ffd | |||
983d7a8798 | |||
910b37268e | |||
d39556a78b | |||
167553b8ee | |||
76affe177a | |||
e96685b1a9 | |||
aef71f1623 | |||
d913447939 | |||
47e83f7d3f | |||
023bcce867 | |||
4f6eb285bf | |||
8c81104816 | |||
7602b8c48d | |||
c6797cbd75 | |||
440461a90b | |||
4d423a916e | |||
b184cdaef0 | |||
b2cc997976 | |||
bc5c41d212 | |||
7c83a84db3 | |||
56c47fbff8 | |||
0d235686f4 | |||
ac2044b84b | |||
cffa0bd201 | |||
bd8b5587f5 | |||
b937bc9655 | |||
a7cf48ea89 | |||
46327991ef | |||
a4da8f32bf | |||
5d483f2d4d | |||
09fd41ce24 | |||
a0c4abf579 | |||
cbf1b585ac | |||
66cd5b6226 | |||
5348654a7e | |||
87d7c07e87 | |||
02fda3adb1 | |||
82bd6c6cda | |||
e8d3516fa8 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,4 +12,4 @@
|
|||||||
/doc/mimetype
|
/doc/mimetype
|
||||||
/doc/stats/
|
/doc/stats/
|
||||||
/config.mk
|
/config.mk
|
||||||
/doc/manual/
|
/doc/manual.html
|
||||||
|
28
CHANGELOG.md
28
CHANGELOG.md
@ -1,5 +1,33 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.2.3 (13-11-2020)
|
||||||
|
|
||||||
|
Primarily a stabilization and bug-fix release.
|
||||||
|
|
||||||
|
Org-roam-dailies has also been revamped to include new features, see [this video](https://www.youtube.com/watch?v=1q9x2aZCJJ4) for a quick overview.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- [#978](https://github.com/org-roam/org-roam/pull/978) Revamp org-roam-dailies
|
||||||
|
- [#1183](https://github.com/org-roam/org-roam/pull/1183) Interactive functions for managing aliases and tags in Org-roam file, namely `org-roam-alias-add`, `org-roam-alias-delete`, `org-roam-tag-add`, and `org-roam-tag-delete`.
|
||||||
|
- [#1215](https://github.com/org-roam/org-roam/pull/1215) Multiple `ROAM_KEY` keywords can now be specified in one file. This allows bibliographical entries to share the same note file.
|
||||||
|
- [#1238](https://github.com/org-roam/org-roam/pull/1238) Add `org-roam-prefer-id-links` variable to select linking method
|
||||||
|
- [#1239](https://github.com/org-roam/org-roam/pull/1239) Allow `org-roam-protocol` to capture the webpage's selection, and add a toggle for storing the links to the pages
|
||||||
|
- [#1264](https://github.com/org-roam/org-roam/pull/1264) add `org-roam-db-update-method` to control when the cache is rebuilt.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- [#1264](https://github.com/org-roam/org-roam/pull/1264) renamed `org-roam-update-db-idle-seconds` to `org-roam-db-idle-idle-seconds`
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- [#1074](https://github.com/org-roam/org-roam/issues/1074) fix `org-roam--extract-links` to handle content boundaries.
|
||||||
|
- [#1193](https://github.com/org-roam/org-roam/issues/1193) fix `org-roam-db-build-cache` by not killing temporary buffer in `org-roam--extract-links`.
|
||||||
|
- [#1195](https://github.com/org-roam/org-roam/issues/1195) fix ID face showing as invalid if within Org ID files, but not Org-roam's.
|
||||||
|
- [#1199](https://github.com/org-roam/org-roam/issues/1199) make Org-roam link insertions respect `org-roam-link-title-format` everywhere.
|
||||||
|
- [#1201](https://github.com/org-roam/org-roam/issues/1201) fix `org-roam-db-build-cache` failing in scenarios involving duplicate IDs and deleted files.
|
||||||
|
- [#1226](https://github.com/org-roam/org-roam/issues/1226) only update relative path of file links
|
||||||
|
- [#1232](https://github.com/org-roam/org-roam/issues/1232) fix incorrect title extractions from narrowed buffers
|
||||||
|
- [#1233](https://github.com/org-roam/org-roam/issues/1233) fixes bug where descriptive file links become plain links during update for relative paths
|
||||||
|
- [#1252](https://github.com/org-roam/org-roam/issues/1252) respect original link type during automatic replacement
|
||||||
|
|
||||||
## 1.2.2 (06-10-2020)
|
## 1.2.2 (06-10-2020)
|
||||||
|
|
||||||
In this release we support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`. Completion for these fuzzy links is supported via `completion-at-point`.
|
In this release we support fuzzy links of the form `[[roam:Title]]`, `[[roam:*Headline]]` and `[[roam:Title*Headline]]`. Completion for these fuzzy links is supported via `completion-at-point`.
|
||||||
|
@ -121,7 +121,7 @@ General Public License, Version 3
|
|||||||
[roamresearch]: https://www.roamresearch.com/
|
[roamresearch]: https://www.roamresearch.com/
|
||||||
[org]: https://orgmode.org/
|
[org]: https://orgmode.org/
|
||||||
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
|
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
|
||||||
[docs]: https://www.orgroam.com/manual/
|
[docs]: https://www.orgroam.com/manual.html
|
||||||
[discourse]: https://org-roam.discourse.group/
|
[discourse]: https://org-roam.discourse.group/
|
||||||
[slack]: https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg
|
[slack]: https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg
|
||||||
[issues]: https://github.com/org-roam/org-roam/issues
|
[issues]: https://github.com/org-roam/org-roam/issues
|
||||||
|
@ -28,11 +28,8 @@ dir: org-roam.info
|
|||||||
@$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) $<
|
@$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) $<
|
||||||
|
|
||||||
html-dir:
|
html-dir:
|
||||||
@printf "Generating org-roam/*.html\n"
|
@$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) org-roam.texi
|
||||||
@$(MAKEINFO) --html $(MANUAL_HTML_ARGS) org-roam.texi
|
mv org-roam.html manual.html
|
||||||
mv org-roam manual
|
|
||||||
cp -r assets manual
|
|
||||||
cp -r images manual
|
|
||||||
|
|
||||||
%.pdf: %.texi
|
%.pdf: %.texi
|
||||||
@printf "Generating $@\n"
|
@printf "Generating $@\n"
|
||||||
|
@ -1,442 +1,59 @@
|
|||||||
/* Import Inter font */
|
|
||||||
/* More info at https://github.com/xz/fonts */
|
|
||||||
@import url("https://fonts.xz.style/serve/inter.css");
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--nc-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
--border: #526980;
|
||||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif,
|
--code: #007;
|
||||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
--nc-font-mono: "Courier New", Courier, "Ubuntu Mono", "Liberation Mono",
|
|
||||||
monospace;
|
|
||||||
--nc-tx-1: #000000;
|
|
||||||
--nc-tx-2: #1a1a1a;
|
|
||||||
--nc-bg-1: #ffffff;
|
|
||||||
--nc-bg-2: #f6f8fa;
|
|
||||||
--nc-bg-3: #e5e7eb;
|
|
||||||
--nc-lk-1: #0070f3;
|
|
||||||
--nc-lk-2: #0366d6;
|
|
||||||
--nc-lk-tx: #ffffff;
|
|
||||||
--nc-ac-1: #79ffe1;
|
|
||||||
--nc-ac-tx: #0c4047;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--nc-tx-1: #ffffff;
|
|
||||||
--nc-tx-2: #eeeeee;
|
|
||||||
--nc-bg-1: #000000;
|
|
||||||
--nc-bg-2: #111111;
|
|
||||||
--nc-bg-3: #222222;
|
|
||||||
--nc-lk-1: #3291ff;
|
|
||||||
--nc-lk-2: #0070f3;
|
|
||||||
--nc-lk-tx: #ffffff;
|
|
||||||
--nc-ac-1: #7928ca;
|
|
||||||
--nc-ac-tx: #ffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
/* Reset margins and padding */
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
address,
|
|
||||||
area,
|
|
||||||
article,
|
|
||||||
aside,
|
|
||||||
audio,
|
|
||||||
blockquote,
|
|
||||||
datalist,
|
|
||||||
details,
|
|
||||||
dl,
|
|
||||||
fieldset,
|
|
||||||
figure,
|
|
||||||
form,
|
|
||||||
input,
|
|
||||||
iframe,
|
|
||||||
img,
|
|
||||||
meter,
|
|
||||||
nav,
|
|
||||||
ol,
|
|
||||||
optgroup,
|
|
||||||
option,
|
|
||||||
output,
|
|
||||||
p,
|
|
||||||
pre,
|
|
||||||
progress,
|
|
||||||
ruby,
|
|
||||||
section,
|
|
||||||
table,
|
|
||||||
textarea,
|
|
||||||
ul,
|
|
||||||
video {
|
|
||||||
/* Margins for most elements */
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
html,
|
|
||||||
input,
|
|
||||||
select,
|
|
||||||
button {
|
|
||||||
/* Set body font family and some finicky elements */
|
|
||||||
font-family: var(--nc-font-sans);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
/* Center body in page */
|
margin: 5ex 10ex;
|
||||||
margin: 0 auto;
|
max-width: 80ex;
|
||||||
max-width: 750px;
|
line-height: 1.5;
|
||||||
padding: 2rem;
|
font-family: sans-serif;
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
background: var(--nc-bg-1);
|
|
||||||
|
|
||||||
/* Main body text */
|
|
||||||
color: var(--nc-tx-2);
|
|
||||||
font-size: 1.03rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
h1, h2, h3 {
|
||||||
/* Set background color for selected text */
|
font-weight: normal;
|
||||||
background: var(--nc-ac-1);
|
|
||||||
color: var(--nc-ac-tx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
pre, code {
|
||||||
margin-bottom: 1rem;
|
font-family: x, monospace;
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
line-height: 1;
|
|
||||||
color: var(--nc-tx-1);
|
|
||||||
padding-top: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3 {
|
|
||||||
color: var(--nc-tx-1);
|
|
||||||
padding-bottom: 2px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
border-bottom: 1px solid var(--nc-bg-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
margin-bottom: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.85rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.55rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--nc-lk-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: var(--nc-lk-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr:hover {
|
|
||||||
/* Set the '?' cursor while hovering an abbreviation */
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
padding: 1.5rem;
|
|
||||||
background: var(--nc-bg-2);
|
|
||||||
border-left: 5px solid var(--nc-bg-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr {
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote *:last-child {
|
|
||||||
padding-bottom: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
background: var(--nc-bg-2);
|
|
||||||
border-bottom: 1px solid var(--nc-bg-3);
|
|
||||||
padding: 2rem 1.5rem;
|
|
||||||
|
|
||||||
/* This sets the right and left margins to cancel out the body's margins. It's width is still the same, but the background stretches across the page's width. */
|
|
||||||
|
|
||||||
margin: -2rem calc(0px - (50vw - 50%)) 2rem;
|
|
||||||
|
|
||||||
/* Shorthand for:
|
|
||||||
|
|
||||||
margin-top: -2rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
|
|
||||||
margin-left: calc(0px - (50vw - 50%));
|
|
||||||
margin-right: calc(0px - (50vw - 50%)); */
|
|
||||||
|
|
||||||
padding-left: calc(50vw - 50%);
|
|
||||||
padding-right: calc(50vw - 50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1,
|
|
||||||
header h2,
|
|
||||||
header h3 {
|
|
||||||
padding-bottom: 0;
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header > *:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header > *:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button,
|
|
||||||
button,
|
|
||||||
input[type="submit"],
|
|
||||||
input[type="reset"],
|
|
||||||
input[type="button"] {
|
|
||||||
font-size: 1rem;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 6px 12px;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
background: var(--nc-lk-1);
|
|
||||||
color: var(--nc-lk-tx);
|
|
||||||
border: 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--nc-lk-tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button[disabled],
|
|
||||||
button[disabled],
|
|
||||||
input[type="submit"][disabled],
|
|
||||||
input[type="reset"][disabled],
|
|
||||||
input[type="button"][disabled] {
|
|
||||||
cursor: default;
|
|
||||||
opacity: 0.5;
|
|
||||||
|
|
||||||
/* Set the [X] cursor while hovering a disabled link */
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:focus,
|
|
||||||
.button:hover,
|
|
||||||
button:focus,
|
|
||||||
button:hover,
|
|
||||||
input[type="submit"]:focus,
|
|
||||||
input[type="submit"]:hover,
|
|
||||||
input[type="reset"]:focus,
|
|
||||||
input[type="reset"]:hover,
|
|
||||||
input[type="button"]:focus,
|
|
||||||
input[type="button"]:hover {
|
|
||||||
background: var(--nc-lk-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
code,
|
|
||||||
pre,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
/* Set the font family for monospaced elements */
|
|
||||||
font-family: var(--nc-font-mono);
|
|
||||||
}
|
|
||||||
|
|
||||||
code,
|
|
||||||
samp,
|
|
||||||
kbd,
|
|
||||||
pre {
|
|
||||||
/* The main preformatted style. This is changed slightly across different cases. */
|
|
||||||
background: var(--nc-bg-2);
|
|
||||||
border: 1px solid var(--nc-bg-3);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 3px 6px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
kbd {
|
|
||||||
/* Makes the kbd element look like a keyboard key */
|
|
||||||
border-bottom: 3px solid var(--nc-bg-3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
padding: 1rem 1.4rem;
|
padding: 1ex;
|
||||||
max-width: 100%;
|
background: #eee;
|
||||||
overflow: auto;
|
border: solid 1px #ddd;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 80%;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre code {
|
code {
|
||||||
/* When <code> is in a <pre>, reset it's formatting to blend in */
|
color: var(--code);
|
||||||
background: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
color: inherit;
|
|
||||||
border: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
code pre {
|
|
||||||
/* When <pre> is in a <code>, reset it's formatting to blend in */
|
|
||||||
display: inline;
|
|
||||||
background: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
color: inherit;
|
|
||||||
border: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
details {
|
|
||||||
/* Make the <details> look more "clickable" */
|
|
||||||
padding: 0.6rem 1rem;
|
|
||||||
background: var(--nc-bg-2);
|
|
||||||
border: 1px solid var(--nc-bg-3);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary {
|
|
||||||
/* Makes the <summary> look more like a "clickable" link with the pointer cursor */
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
details[open] {
|
|
||||||
/* Adjust the <details> padding while open */
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
details[open] summary {
|
|
||||||
/* Adjust the <details> padding while open */
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
details[open] > *:last-child {
|
|
||||||
/* Resets the bottom margin of the last element in the <details> while <details> is opened. This prevents double margins/paddings. */
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd::before {
|
|
||||||
/* Add an arrow to data table definitions */
|
|
||||||
content: "→ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
/* Reset the border of the <hr> separator, then set a better line */
|
|
||||||
border: 0;
|
|
||||||
border-bottom: 1px solid var(--nc-bg-3);
|
|
||||||
margin: 1rem auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding: 2rem;
|
|
||||||
border: 1px solid var(--nc-bg-3);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
padding: auto 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
/* Don't let the <textarea> extend off the screen naturally or when dragged by the user */
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul {
|
|
||||||
/* Replace the browser default padding */
|
|
||||||
padding-left: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-top: 0.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul ul,
|
|
||||||
ol ul,
|
|
||||||
ul ol,
|
|
||||||
ol ol {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mark {
|
|
||||||
padding: 3px 6px;
|
|
||||||
background: var(--nc-ac-1);
|
|
||||||
color: var(--nc-ac-tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea,
|
|
||||||
select,
|
|
||||||
input {
|
|
||||||
padding: 6px 12px;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
background: var(--nc-bg-2);
|
|
||||||
color: var(--nc-tx-2);
|
|
||||||
|
|
||||||
/* Set a border of the same color as the main background. It isn't visible on idle, but prevents the cell from growing in size when a darker border is set on focus. */
|
|
||||||
border: 1px solid var(--nc-bg-2);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea:focus,
|
|
||||||
select:focus,
|
|
||||||
input[type]:focus {
|
|
||||||
border: 1px solid var(--nc-bg-3);
|
|
||||||
|
|
||||||
/* Reset any browser default outlines */
|
|
||||||
outline: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Customizations */
|
table {
|
||||||
.menu-comment {
|
border-collapse: collapse;
|
||||||
font-weight: bold;
|
width: 100%;
|
||||||
border: 0;
|
}
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
thead {
|
||||||
font-size: 1.2rem;
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
tfoot {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-style: italic;
|
||||||
|
font-family: serif;
|
||||||
|
border-left: 3px solid;
|
||||||
|
border-left-color: currentcolor;
|
||||||
|
border-color: var(--text-color);
|
||||||
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@
|
|||||||
You can find us on Discourse and Slack.
|
You can find us on Discourse and Slack.
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Read our documentation within Emacs, or on the <a href="https://www.orgroam.com/manual/">Online Manual</a></li>
|
<li>Read our documentation within Emacs, or on the <a href="https://www.orgroam.com/manual.html">Online Manual</a></li>
|
||||||
<li>Participate in our forum discussions on <a href="https://org-roam.discourse.group">Discourse</a></li>
|
<li>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>
|
<li>Chat with us on <a href="https://join.slack.com/t/orgroam/shared_invite/zt-deoqamys-043YQ~s5Tay3iJ5QRI~Lxg">Slack</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -120,13 +120,6 @@
|
|||||||
>org-roam-server</a
|
>org-roam-server</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<a
|
|
||||||
class="content footer-links"
|
|
||||||
href="https://github.com/org-roam/company-org-roam"
|
|
||||||
>company-org-roam</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
606
doc/org-roam.org
606
doc/org-roam.org
@ -1,20 +1,20 @@
|
|||||||
#+title: Org-roam User Manual
|
#+title: Org-roam User Manual
|
||||||
:PREAMBLE:
|
|
||||||
#+author: Jethro Kuan
|
#+author: Jethro Kuan
|
||||||
#+email: jethrokuan95@gmail.com
|
#+email: jethrokuan95@gmail.com
|
||||||
#+date: 2020-2020
|
#+date: 2020-2020
|
||||||
#+language: en
|
#+language: en
|
||||||
|
|
||||||
|
#+texinfo_deffn: t
|
||||||
#+texinfo_dir_category: Emacs
|
#+texinfo_dir_category: Emacs
|
||||||
#+texinfo_dir_title: Org-roam: (org-roam).
|
#+texinfo_dir_title: Org-roam: (org-roam).
|
||||||
#+texinfo_dir_desc: Rudimentary Roam Replica for Emacs.
|
#+texinfo_dir_desc: Rudimentary Roam Replica for Emacs.
|
||||||
#+subtitle: for version 1.2.2
|
#+subtitle: for version 1.2.3
|
||||||
|
|
||||||
#+options: H:4 num:3 toc:2 creator:t
|
#+options: H:4 num:3 toc:nil creator:t ':t
|
||||||
#+property: header-args :eval never
|
#+property: header-args :eval never
|
||||||
#+texinfo: @noindent
|
#+texinfo: @noindent
|
||||||
|
|
||||||
This manual is for Org-roam version 1.2.2.
|
This manual is for Org-roam version 1.2.3.
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
@ -29,20 +29,19 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
#+END_QUOTE
|
#+END_QUOTE
|
||||||
|
|
||||||
:END:
|
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
|
|
||||||
Org-roam is a [[https://roamresearch.com/][Roam Research]] replica built around the
|
Org-roam is a tool for network thought. It reproduces some of [[https://roamresearch.com/][Roam
|
||||||
all-powerful [[https://orgmode.org/][Org-mode]].
|
Research's]] [fn:roam] features within the all-powerful [[https://orgmode.org/][Org-mode]].
|
||||||
|
|
||||||
Org-roam is a solution for effortless non-hierarchical note-taking
|
Org-roam is a solution for effortless non-hierarchical note-taking with
|
||||||
with Org-mode. With Org-roam, notes flow naturally, making note-taking
|
Org-mode. With Org-roam, notes flow naturally, making note-taking fun and easy.
|
||||||
fun and easy. Org-roam should also work as a plug-and-play solution
|
Org-roam keeps closely to Org syntax, and will work for anyone already using
|
||||||
for anyone already using Org-mode for their personal wiki.
|
Org-mode for their personal wiki.
|
||||||
|
|
||||||
To understand more about Roam, a collection of links are available in
|
Org-roam gains its superpowers by leveraging the mature ecosystem around
|
||||||
[[*Note-taking Workflows][Note-taking Workflows]].
|
Org-mode. For example, it has first-class support for [[https://github.com/jkitchin/org-ref][org-ref]] for citation
|
||||||
|
management.
|
||||||
|
|
||||||
Org-roam aims to implement the core features of Roam, leveraging the
|
Org-roam aims to implement the core features of Roam, leveraging the
|
||||||
mature ecosystem around Org-mode where possible. Eventually, we hope
|
mature ecosystem around Org-mode where possible. Eventually, we hope
|
||||||
@ -50,11 +49,23 @@ to further introduce features enabled by the Emacs ecosystem.
|
|||||||
|
|
||||||
Org-roam provides several benefits over other tooling:
|
Org-roam provides several benefits over other tooling:
|
||||||
|
|
||||||
- Privacy and Security :: Edit your personal wiki completely offline, entirely in your control. Encrypt your notes with GPG.
|
- *Privacy and Security:* Keep your personal wiki entirely offline and in your
|
||||||
- Longevity of Plain Text :: Unlike web solutions like Roam research, the notes are first and foremost plain Org-mode files -- Org-roam simply builds up an auxilliary database to give the personal wiki superpowers. Having your notes in plain-text is crucial for the longevity of your wiki. Never have to worry about proprietary web solutions being taken down. Edit your plain-text notes in notepad if all other editors cease to exist
|
control. Encrypt your notes with GPG.
|
||||||
- Free and Open Source :: Org-roam is free and open-source, which means that if you feel unhappy with any part of Org-roam, you may choose to extend Org-roam, or open a PR.
|
- *Longevity of Plain Text:* Unlike web solutions like Roam Research, the notes
|
||||||
- Leverages the Org-mode ecosystem :: Over the years, Emacs and Org-mode has developed into a mature system for plain-text organization. Building upon Org-mode already puts Org-roam light-years ahead of many other solutions.
|
are first and foremost plain Org-mode files -- Org-roam simply builds an
|
||||||
- Built on Emacs :: Emacs is also a fantastic interface for editing text, and we can inherit many of the powerful text-navigation and editing packages available to Emacs.
|
auxiliary database to give the personal wiki superpowers. Having your notes
|
||||||
|
in plain-text is crucial for the longevity of your wiki. Never have to worry
|
||||||
|
about proprietary web solutions being taken down. The notes are still
|
||||||
|
functional even if Org-roam ceases to exist.
|
||||||
|
- *Free and Open Source:* Org-roam is free and open-source, which means that if
|
||||||
|
you feel unhappy with any part of Org-roam, you may choose to extend Org-roam,
|
||||||
|
or open a pull request.
|
||||||
|
- *Leverage the Org-mode ecosystem:* Over the years, Emacs and Org-mode has
|
||||||
|
developed into a mature system for plain-text organization. Building upon
|
||||||
|
Org-mode already puts Org-roam light-years ahead of many other solutions.
|
||||||
|
- *Built on Emacs:* Emacs is also a fantastic interface for editing text, and we
|
||||||
|
can inherit many of the powerful text-navigation and editing packages
|
||||||
|
available to Emacs.
|
||||||
|
|
||||||
* Target Audience
|
* Target Audience
|
||||||
|
|
||||||
@ -94,38 +105,44 @@ Org-roam provides utilities for maintaining a digital slip-box. This section
|
|||||||
aims to provide a brief introduction to the "slip-box", or "Zettelkasten"
|
aims to provide a brief introduction to the "slip-box", or "Zettelkasten"
|
||||||
method. By providing some background on the method, we hope that the design
|
method. By providing some background on the method, we hope that the design
|
||||||
decisions of Org-roam will become clear, and that will aid in using Org-roam
|
decisions of Org-roam will become clear, and that will aid in using Org-roam
|
||||||
appropriately. In this section we will also introduce terms commonly used within
|
appropriately. In this section we will introduce terms commonly used within the
|
||||||
the Zettelkasten community, which will also commonly appear in the Org-roam
|
Zettelkasten community and the Org-roam forums.
|
||||||
forums and channels of discussion.
|
|
||||||
|
|
||||||
The Zettelkasten method of note-taking is designed to increase research
|
The Zettelkasten is a personal tool for thinking and writing. It places heavy
|
||||||
productivity: in particular, it acts as a research partner, where conversations
|
emphasis on connecting ideas, building up a web of thought. Hence, it is well
|
||||||
with it may produce new and surprising lines of thought. This method is
|
suited for knowledge workers and intellectual tasks, such as conducting
|
||||||
attributed to German sociologist Niklas Luhmann, who using the method had
|
research. The Zettelkasten can act as a research partner, where conversations
|
||||||
produced volumes of written works.
|
with it may produce new and surprising lines of thought.
|
||||||
|
|
||||||
In its paper form, the slip-box is simply a box of cards. These cards are small
|
This method is attributed to German sociologist Niklas Luhmann, who using the
|
||||||
-- often only large enough to fit a single concept. The size limitation
|
method had produced volumes of written works. Luhmann's slip-box was simply a
|
||||||
encourages ideas to be broken down into individual concepts. These ideas are
|
box of cards. These cards are small -- often only large enough to fit a single
|
||||||
explicitly linked together. The breakdown of ideas encourages tangential
|
concept. The size limitation encourages ideas to be broken down into individual
|
||||||
exploration of ideas, increasing the surface for thought. Making linking
|
concepts. These ideas are explicitly linked together. The breakdown of ideas
|
||||||
explicit between notes also encourages one to think about the connections
|
encourages tangential exploration of ideas, increasing the surface for thought.
|
||||||
between concepts.
|
Making linking explicit between notes also encourages one to think about the
|
||||||
|
connections between concepts.
|
||||||
|
|
||||||
|
At the corner of each note, Luhmann ascribed each note with an ordered ID,
|
||||||
|
allowing him to link and jump between notes. In Org-roam, we simply use
|
||||||
|
hyperlinks.
|
||||||
|
|
||||||
Org-roam is the slip-box, digitalized in Org-mode. Every zettel (card) is a
|
Org-roam is the slip-box, digitalized in Org-mode. Every zettel (card) is a
|
||||||
plain-text, Org-mode file. These files are often placed in the same directory.
|
plain-text, Org-mode file. In the same way one would maintain a paper slip-box,
|
||||||
In the same way one would maintain a paper slip-box, Org-roam makes it easy to
|
Org-roam makes it easy to create new zettels, pre-filling boilerplate content
|
||||||
create new zettels, pre-filling boilerplate content using a powerful templating
|
using a powerful templating system.
|
||||||
system. Org-roam also facilitates the linking of zettels using Org-mode ~file:~
|
|
||||||
links.
|
|
||||||
|
|
||||||
A slip-box requires a method of quickly capturing ideas. These are called
|
** Fleeting notes
|
||||||
|
|
||||||
|
A slip-box requires a method for quickly capturing ideas. These are called
|
||||||
*fleeting notes*: they are simple reminders of information or ideas that will
|
*fleeting notes*: they are simple reminders of information or ideas that will
|
||||||
need to be processed later on, or trashed. This is typically accomplished using
|
need to be processed later on, or trashed. This is typically accomplished using
|
||||||
~org-capture~ (see info:org#capture), or using Org-roam's daily notes
|
~org-capture~ (see info:org#capture), or using Org-roam's daily notes
|
||||||
functionality (see [[*Daily Notes][Daily Notes]]). This provides a central inbox for collecting
|
functionality (see [[*Daily-notes][Daily-notes]]). This provides a central inbox for collecting
|
||||||
thoughts, to be processed later into permanent notes.
|
thoughts, to be processed later into permanent notes.
|
||||||
|
|
||||||
|
** Permanent notes
|
||||||
|
|
||||||
Permanent notes are further split into two categories: *literature notes* and
|
Permanent notes are further split into two categories: *literature notes* and
|
||||||
*concept notes*. Literature notes can be brief annotations on a particular
|
*concept notes*. Literature notes can be brief annotations on a particular
|
||||||
source (e.g. book, website or paper), that you'd like to access later on.
|
source (e.g. book, website or paper), that you'd like to access later on.
|
||||||
@ -197,9 +214,16 @@ Org-roam will then be autoloaded into Emacs.
|
|||||||
|
|
||||||
** Installing from the Git Repository
|
** Installing from the Git Repository
|
||||||
|
|
||||||
You may install Org-roam directly from the repository on [[https://github.com/org-roam/org-roam][GitHub]] if you like. This will give you access to the latest version hours or days before it appears on MELPA, and months (or more) before it is added to the Debian or Ubuntu repositories. This will also give you access to various developmental branches that may be available.
|
You may install Org-roam directly from the repository on [[https://github.com/org-roam/org-roam][GitHub]] if you like.
|
||||||
|
This will give you access to the latest version hours or days before it appears
|
||||||
|
on MELPA, and months (or more) before it is added to the Debian or Ubuntu
|
||||||
|
repositories. This will also give you access to various developmental branches
|
||||||
|
that may be available.
|
||||||
|
|
||||||
Note, however, that development version, and especially any feature branches, may not always be in working order. You'll need to be prepared to do some debugging, or to manually roll-back to working versions, if you install from GitHub.
|
Note, however, that development version, and especially any feature branches,
|
||||||
|
may not always be in working order. You'll need to be prepared to do some
|
||||||
|
debugging, or to manually roll-back to working versions, if you install from
|
||||||
|
GitHub.
|
||||||
|
|
||||||
Installing from GitHub requires that you clone the repository:
|
Installing from GitHub requires that you clone the repository:
|
||||||
|
|
||||||
@ -209,14 +233,16 @@ git clone https://github.com/org-roam/org-roam.git /path/to/org/roam
|
|||||||
|
|
||||||
where ~./path/to/org/roam~ is the location you will store your copy of the code.
|
where ~./path/to/org/roam~ is the location you will store your copy of the code.
|
||||||
|
|
||||||
Next, you need to add this location to your load path, and ~require~ the Org-roam library. Add the following code to your ~.emacs~:
|
Next, you need to add this location to your load path, and ~require~ the
|
||||||
|
Org-roam library. Add the following code to your ~.emacs~:
|
||||||
|
|
||||||
#+begin_src elisp
|
#+begin_src elisp
|
||||||
(add-to-list 'load-path "/path/to/org/roam")
|
(add-to-list 'load-path "/path/to/org/roam")
|
||||||
(require 'org-roam)
|
(require 'org-roam)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
You now have Org-roam installed. However, you don't necessarily have the dependencies that it requires. These include:
|
You now have Org-roam installed. However, you don't necessarily have the
|
||||||
|
dependencies that it requires. These include:
|
||||||
|
|
||||||
- dash
|
- dash
|
||||||
- f
|
- f
|
||||||
@ -225,22 +251,29 @@ You now have Org-roam installed. However, you don't necessarily have the depende
|
|||||||
- emacsql
|
- emacsql
|
||||||
- emacsql-sqlite3
|
- emacsql-sqlite3
|
||||||
|
|
||||||
You can install this manually as well, or get the latest version from MELPA. You may wish to use [[https://github.com/jwiegley/use-package][use-package]], [[https://github.com/raxod502/straight.el][straight.el]], or some other tool or tools to help manage this.
|
You can install this manually as well, or get the latest version from MELPA. You
|
||||||
|
may wish to use [[https://github.com/jwiegley/use-package][use-package]], [[https://github.com/raxod502/straight.el][straight.el]] to help manage this.
|
||||||
|
|
||||||
If you would like to install the manual for access from Emacs' built-in Info system, you'll need to compile the .texi source file, and install it in an appropriate location.
|
If you would like to install the manual for access from Emacs' built-in Info
|
||||||
|
system, you'll need to compile the .texi source file, and install it in an
|
||||||
|
appropriate location.
|
||||||
|
|
||||||
To compile the .texi source file, from a terminal navigate to the ~/doc~ subdirectory of the Org-roam repository, and run the following:
|
To compile the .texi source file, from a terminal navigate to the ~/doc~
|
||||||
|
subdirectory of the Org-roam repository, and run the following:
|
||||||
|
|
||||||
#+begin_src bash
|
#+begin_src bash
|
||||||
make infodir=/path/to/my/info/files install-info
|
make infodir=/path/to/my/info/files install-info
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Where ~/path/to/my/info/files~ is the location where you keep info files. This target directory needs to be stored in the variable `Info-default-directory-list`. If you aren't using one of the default info locations, you can configure this with the following in your ~.emacs~ file:
|
Where ~/path/to/my/info/files~ is the location where you keep info files. This
|
||||||
|
target directory needs to be stored in the variable
|
||||||
|
`Info-default-directory-list`. If you aren't using one of the default info
|
||||||
|
locations, you can configure this with the following in your ~.emacs~ file:
|
||||||
|
|
||||||
#+begin_src elisp
|
#+begin_src elisp
|
||||||
(require 'info)
|
(require 'info)
|
||||||
(add-to-list 'Info-default-directory-list
|
(add-to-list 'Info-default-directory-list
|
||||||
"/path/to/my/info/files")
|
"/path/to/my/info/files")
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
You can also use one of the default locations, such as:
|
You can also use one of the default locations, such as:
|
||||||
@ -249,9 +282,11 @@ You can also use one of the default locations, such as:
|
|||||||
- /usr/share/info/
|
- /usr/share/info/
|
||||||
- /usr/local/share/info/
|
- /usr/local/share/info/
|
||||||
|
|
||||||
If you do this, you'll need to make sure you have write-access to that location, or run the above ~make~ command as root.
|
If you do this, you'll need to make sure you have write-access to that location,
|
||||||
|
or run the above ~make~ command as root.
|
||||||
|
|
||||||
Now that the info file is ready, you need to add it to the corresponding ~dir~ file:
|
Now that the info file is ready, you need to add it to the corresponding ~dir~
|
||||||
|
file:
|
||||||
|
|
||||||
#+begin_src bash
|
#+begin_src bash
|
||||||
install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir
|
install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir
|
||||||
@ -289,10 +324,10 @@ 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]].
|
more about the methods and madness, see [[*Note-taking Workflows][Note-taking Workflows]].
|
||||||
|
|
||||||
To first start using Org-roam, one needs to pick a location to store the
|
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
|
Org-roam files. The directory that will contain your notes is specified by the
|
||||||
is specified by the variable ~org-roam-directory~. This variable needs to be set
|
variable ~org-roam-directory~. This variable needs to be set before any calls to
|
||||||
before any calls to Org-roam functions, including enabling ~org-roam-mode~. For
|
Org-roam functions, including enabling ~org-roam-mode~. For this tutorial,
|
||||||
this tutorial, create an empty directory, and set ~org-roam-directory~:
|
create an empty directory, and set ~org-roam-directory~:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(make-directory "~/org-roam")
|
(make-directory "~/org-roam")
|
||||||
@ -301,39 +336,38 @@ this tutorial, create an empty directory, and set ~org-roam-directory~:
|
|||||||
|
|
||||||
We encourage using a flat hierarchy for storing notes, but some prefer using
|
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
|
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 notes.
|
||||||
Instead of relying on the file hierarchy for any form of categorization, we
|
Instead of relying on the file hierarchy for any form of categorization, one
|
||||||
solely rely on links between files to establish connections between notes.
|
should use 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
|
||||||
with several hooks, builds a cache and keeps it consistent. We recommend
|
Emacs with several hooks, building a cache that is kept consistent as your
|
||||||
starting ~org-roam-mode~ on startup:
|
slip-box grows. We recommend starting ~org-roam-mode~ on startup:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(add-hook 'after-init-hook 'org-roam-mode)
|
(add-hook 'after-init-hook 'org-roam-mode)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
To build the cache manually, one can run ~M-x org-roam-db-build-cache~. The
|
To build the cache manually, one can run ~M-x org-roam-db-build-cache~. Cache
|
||||||
cache is a sqlite database named ~org-roam.db~, which defaults to residing in
|
builds may take a while the first time, but is often instantaneous in subsequent
|
||||||
the root ~org-roam-directory~. Cache builds may take a while the first time, but
|
runs because it only reprocesses modified files.
|
||||||
is often instantaneous in subsequent runs.
|
|
||||||
|
|
||||||
Let us now create our first note. Call ~M-x org-roam-find-file~. This shows a list
|
Let us now create our first note. Call ~M-x org-roam-find-file~. This shows a
|
||||||
of titles for notes that reside in ~org-roam-directory~. It should show nothing
|
list of titles for notes that reside in ~org-roam-directory~. It should show
|
||||||
right now, since there are no notes in the directory. Entering the title of the
|
nothing right now, since there are no notes in the directory. Entering the title
|
||||||
note you wish to create, and pressing ~RET~ should begin the note creation
|
of the note you wish to create, and pressing ~RET~ should begin the note
|
||||||
process. This process uses ~org-capture~'s templating system, and can be freely
|
creation process. This process uses ~org-capture~'s templating system, and can
|
||||||
customized (see [[*The Templating System][The Templating System]]). Using the default template, pressing ~C-c
|
be customized (see [[*The Templating System][The Templating System]]). Using the default template, pressing
|
||||||
C-c~ finishes the note capture. Running ~M-x org-roam-find-file~ again should show
|
~C-c C-c~ finishes the note capture. Running ~M-x org-roam-find-file~ again
|
||||||
the note you have created, and selecting that entry will bring you to that note.
|
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.
|
Org-roam makes it easy to create notes, and link them together. To link notes
|
||||||
To link notes together, we call ~M-x org-roam-insert~. This brings up a prompt
|
together, we call ~M-x org-roam-insert~. This brings up a prompt with a list of
|
||||||
with a list of title for existing notes. Selecting an existing entry will create
|
title for existing notes. Selecting an existing entry will create and insert a
|
||||||
and insert a link to the current file. Entering a non-existent title will create
|
link to the current file. Entering a non-existent title will create a new note
|
||||||
a new note with that title. Good usage of Org-roam requires liberally linking
|
with that title. Good usage of Org-roam requires liberally linking files: this
|
||||||
files: this facilitates building up a dense knowledge graph of inter-connected
|
facilitates building up a dense graph of inter-connected notes.
|
||||||
notes.
|
|
||||||
|
|
||||||
Org-roam provides an interface to view backlinks. It shows backlinks for the
|
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
|
currently active Org-roam note, along with some surrounding context. To toggle
|
||||||
@ -342,15 +376,14 @@ the visibility of this buffer, call ~M-x org-roam~.
|
|||||||
For a visual representation of the notes and their connections, Org-roam also
|
For a visual representation of the notes and their connections, Org-roam also
|
||||||
provides graphing capabilities, using Graphviz. It generates graphs with notes
|
provides graphing capabilities, using Graphviz. It generates graphs with notes
|
||||||
as nodes, and links between them as edges. The generated graph can be used to
|
as nodes, and links between them as edges. The generated graph can be used to
|
||||||
navigate to the files, but this requires some additional setup (see [[*Roam Protocol][Roam
|
navigate to the files, but this requires some additional setup (see [[*Roam
|
||||||
Protocol]]).
|
Protocol][Roam Protocol]]).
|
||||||
|
|
||||||
* Anatomy of an Org-roam File
|
* Anatomy of an Org-roam File
|
||||||
|
|
||||||
The bulk of Org-roam's functionality is built on top of vanilla
|
The bulk of Org-roam's functionality is built on top of vanilla Org-mode.
|
||||||
Org-mode. However, to support additional functionality, Org-roam adds
|
However, to support additional functionality, Org-roam adds several
|
||||||
several Org-roam-specific keywords. These functionality are not crucial
|
Org-roam-specific keywords.
|
||||||
to effective use of Org-roam.
|
|
||||||
|
|
||||||
** Titles
|
** Titles
|
||||||
|
|
||||||
@ -367,7 +400,7 @@ title extraction methods supported are:
|
|||||||
1. ~'title~: This extracts the title using the file ~#+title~ 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
|
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.
|
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
|
The aliases are space-delimited, and can be multi-worded using quotes.
|
||||||
|
|
||||||
Take for example the following org file:
|
Take for example the following org file:
|
||||||
|
|
||||||
@ -398,13 +431,15 @@ If you wish to add your own title extraction method, you may push a symbol
|
|||||||
|
|
||||||
Tags are used as meta-data for files: they facilitate interactions with notes
|
Tags are used as meta-data for files: they facilitate interactions with notes
|
||||||
where titles are insufficient. For example, tags allow for categorization of
|
where titles are insufficient. For example, tags allow for categorization of
|
||||||
notes: differentiating between bibliographical and structure notes during interactive commands.
|
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
|
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
|
variable ~org-roam-tag-sources~, to control how tags are extracted. The tag
|
||||||
extraction methods supported are:
|
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.
|
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
|
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
|
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~.
|
~foo/bar/file.org~, the file will have tags ~foo~ and ~bar~.
|
||||||
@ -429,29 +464,34 @@ accepts the absolute file path as its argument. See
|
|||||||
|
|
||||||
** File Refs
|
** File Refs
|
||||||
|
|
||||||
Refs are unique identifiers for files. Each note can only have 1 ref.
|
Refs are unique identifiers for files. For example, a note for a website may
|
||||||
For example, a note for a website may contain a ref:
|
contain a ref:
|
||||||
|
|
||||||
#+BEGIN_SRC org
|
#+BEGIN_SRC org
|
||||||
#+title: Google
|
#+title: Google
|
||||||
#+roam_key: https://www.google.com/
|
#+roam_key: https://www.google.com/
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
These keys come in useful for when taking website notes, using the
|
These keys allow references to the key to show up in the backlinks buffer. For
|
||||||
~roam-ref~ protocol (see [[*Roam Protocol][Roam Protocol]]).
|
instance, with the example above, if another file then links to
|
||||||
|
https://www.google.com, that will show up as a “Ref Backlink”.
|
||||||
|
|
||||||
Alternatively, add a ref for notes for a specific paper, using its
|
These keys also come in useful for when taking website notes, using the
|
||||||
[[https://github.com/jkitchin/org-ref][org-ref]] citation key:
|
~roam-ref~ protocol (see [[*Roam Protocol][Roam Protocol]]).
|
||||||
|
|
||||||
|
[[https://github.com/jkitchin/org-ref][org-ref]] citation keys can also be used as refs:
|
||||||
|
|
||||||
#+BEGIN_SRC org
|
#+BEGIN_SRC org
|
||||||
#+title: Neural Ordinary Differential Equations
|
#+title: Neural Ordinary Differential Equations
|
||||||
#+roam_key: cite:chen18_neural_ordin_differ_equat
|
#+roam_key: cite:chen18_neural_ordin_differ_equat
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
The backlinks buffer will show any cites of this key: e.g.
|
|
||||||
|
|
||||||
#+CAPTION: org-ref-citelink
|
#+CAPTION: org-ref-citelink
|
||||||
[[file:images/org-ref-citelink.png]]
|
[[file:images/org-ref-citelink.png]]
|
||||||
|
|
||||||
|
You may assign multiple refs to a single file, for example when you want
|
||||||
|
multiple papers in a series to share the same note, or an article has a citation
|
||||||
|
key and a URL at the same time.
|
||||||
* The Templating System
|
* The Templating System
|
||||||
|
|
||||||
Rather than creating blank files on ~org-roam-insert~ and ~org-roam-find-file~,
|
Rather than creating blank files on ~org-roam-insert~ and ~org-roam-find-file~,
|
||||||
@ -489,15 +529,14 @@ the default template, reproduced below.
|
|||||||
:unnarrowed t)
|
:unnarrowed t)
|
||||||
#+END_SRC
|
#+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
|
||||||
org-roam automatically chooses this template for you.
|
automatically chooses this template for you.
|
||||||
2. The template is given a description of ~"default"~.
|
2. The template is given a description of ~"default"~.
|
||||||
3. ~plain~ text is inserted. Other options include Org headings via
|
3. ~plain~ text is inserted. Other options include Org headings via
|
||||||
~entry~.
|
~entry~.
|
||||||
4. ~(function org-roam--capture-get-point)~ should not be changed.
|
4. ~(function org-roam--capture-get-point)~ should not be changed.
|
||||||
5. ~"%?"~ is the template inserted on each call to ~org-roam-capture--capture~.
|
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
|
This template means don't insert any content, but place the cursor here.
|
||||||
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
|
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
|
||||||
@ -526,9 +565,9 @@ 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
|
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
|
After doing this expansion, the org-capture's template expansion system is used
|
||||||
is used to fill up the rest of the template. You may read up more on
|
to fill up the rest of the template. You may read up more on this on
|
||||||
this on [[https://orgmode.org/manual/Template-expansion.html#Template-expansion][org-capture's documentation page]].
|
[[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:
|
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
|
~"%<%Y%m%d%H%M%S>-${title}"~, with the title ~"Foo"~. The template is first
|
||||||
@ -549,12 +588,12 @@ directly to provide its third argument to specify UTC.
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
* Concepts and Configuration
|
* Concepts and Configuration
|
||||||
The number of configuration options is deliberately kept small, to keep
|
The number of configuration options is deliberately kept small, to keep the
|
||||||
the Org-roam codebase manageable. However, we attempt to accommodate as
|
Org-roam codebase manageable. However, we attempt to accommodate as many usage
|
||||||
many usage styles as possible.
|
styles as possible.
|
||||||
|
|
||||||
All of Org-roam's customization options can be viewed via
|
All of Org-roam's customization options can be viewed via ~M-x customize-group
|
||||||
~M-x customize-group org-roam~.
|
org-roam~.
|
||||||
|
|
||||||
** Directories and Files
|
** Directories and Files
|
||||||
|
|
||||||
@ -600,15 +639,56 @@ The Org-roam buffer displays backlinks for the currently active Org-roam note.
|
|||||||
Height of ~org-roam-buffer~. Has an effect only if ~org-roam-buffer-position~ is
|
Height of ~org-roam-buffer~. Has an effect only if ~org-roam-buffer-position~ is
|
||||||
~'top~ or ~'bottom~.
|
~'top~ or ~'bottom~.
|
||||||
|
|
||||||
- User Option: org-roam-buffer-no-delete-other-windows
|
- User Option: org-roam-buffer-window-parameters
|
||||||
|
|
||||||
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~.
|
Additional window parameters for the org-roam-buffer side window.
|
||||||
|
|
||||||
|
For example one can prevent the window from being deleted when calling
|
||||||
|
~delete-other-windows~, by setting it with the following:
|
||||||
|
|
||||||
|
~(setq org-roam-buffer-window-parameters '((no-delete-other-windows . t)))~
|
||||||
|
|
||||||
** Org-roam Files
|
** Org-roam Files
|
||||||
|
|
||||||
Org-roam files are created and prefilled using Org-roam's templating
|
Org-roam files are created and prefilled using Org-roam's templating
|
||||||
system. The templating system is customizable (see [[*The Templating System][The Templating System]]).
|
system. The templating system is customizable (see [[*The Templating System][The Templating System]]).
|
||||||
|
|
||||||
|
** Org-roam Faces
|
||||||
|
|
||||||
|
Org-roam introduces several faces to distinguish links within the same buffer.
|
||||||
|
These faces are enabled by default in Org-roam notes.
|
||||||
|
|
||||||
|
- User Option: org-roam-link-use-custom-faces
|
||||||
|
|
||||||
|
When ~t~, use custom faces only inside Org-roam notes.
|
||||||
|
When ~everywhere~, the custom face is applied additionally to non Org-roam notes.
|
||||||
|
When ~nil~, do not use Org-roam's custom faces.
|
||||||
|
|
||||||
|
The ~org-roam-link~ face is the face applied to links to other Org-roam files.
|
||||||
|
This distinguishes internal links from external links (e.g. external web links).
|
||||||
|
|
||||||
|
The ~org-roam-link-current~ face corresponds to links to the same file it is in.
|
||||||
|
|
||||||
|
The ~org-roam-link-invalid~ face is applied to links that are broken. These are
|
||||||
|
links to files or IDs that cannot be found.
|
||||||
|
** TODO The Database
|
||||||
|
|
||||||
|
Org-roam is backed by a Sqlite database.
|
||||||
|
|
||||||
|
- User Option: org-roam-db-update-method
|
||||||
|
|
||||||
|
Method to update the Org-roam database.
|
||||||
|
|
||||||
|
~'immediate~: Update the database immediately upon file changes.
|
||||||
|
|
||||||
|
~'idle-timer~: Updates the database if dirty, if Emacs idles for
|
||||||
|
~org-roam-db-update-idle-seconds~.
|
||||||
|
|
||||||
|
- User Option: org-roam-db-update-idle-seconds
|
||||||
|
|
||||||
|
Number of idle seconds before triggering an Org-roam database update. This is
|
||||||
|
only valid if ~org-roam-db-update-method~ is ~'idle-timer~.
|
||||||
|
|
||||||
* Inserting Links
|
* Inserting Links
|
||||||
|
|
||||||
The preferred mode of linking is via ~file~ links to files, and ~id~ links for
|
The preferred mode of linking is via ~file~ links to files, and ~id~ links for
|
||||||
@ -626,14 +706,17 @@ An alternative mode of insertion is using Org-roam's ~roam~ links. Org-roam
|
|||||||
registers this link type, and interprets the path as follows:
|
registers this link type, and interprets the path as follows:
|
||||||
|
|
||||||
- ~[[roam:title]]~ :: links to an Org-roam file with title or alias "title"
|
- ~[[roam:title]]~ :: links to an Org-roam file with title or alias "title"
|
||||||
- ~[[roam:*headline]]~ :: links to the headline "headline" in the current Org-roam file
|
- ~[[roam:*headline]]~ :: links to the headline "headline" in the current
|
||||||
- ~[[roam:title*headline]]~ :: links to the headline "headline" in the Org-roam file with title or alias "title"
|
Org-roam file
|
||||||
|
- ~[[roam:title*headline]]~ :: links to the headline "headline" in the Org-roam
|
||||||
|
file with title or alias "title"
|
||||||
|
|
||||||
~roam~ links support auto-completion via ~completion-at-point~: simply call
|
~roam~ links support auto-completion via ~completion-at-point~: simply call
|
||||||
~completion-at-point~ within a roam link. Users of ~company-mode~ may want to
|
~completion-at-point~ within a roam link. Users of ~company-mode~ may want to
|
||||||
prepend ~company-capf~ to the beginning of variable ~company-backends~.
|
prepend ~company-capf~ to the beginning of variable ~company-backends~.
|
||||||
|
|
||||||
To easily insert ~roam~ links, one may wish to use a package like [[https://github.com/emacsorphanage/key-chord/][key-chord]]. In the following example, typing "[[" will insert a stub ~roam~ link:
|
To easily insert ~roam~ links, one may wish to use a package like [[https://github.com/emacsorphanage/key-chord/][key-chord]]. In
|
||||||
|
the following example, typing "[[" will insert a stub ~roam~ link:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(key-chord-define org-mode-map "[[" #'my/insert-roam-link)
|
(key-chord-define org-mode-map "[[" #'my/insert-roam-link)
|
||||||
@ -667,7 +750,6 @@ To easily insert ~roam~ links, one may wish to use a package like [[https://gith
|
|||||||
harder to edit. Defaults to ~t~.
|
harder to edit. Defaults to ~t~.
|
||||||
|
|
||||||
* Navigating Around
|
* Navigating Around
|
||||||
|
|
||||||
** Index File
|
** Index File
|
||||||
|
|
||||||
As your collection grows, you might want to create an index where you keep links
|
As your collection grows, you might want to create an index where you keep links
|
||||||
@ -697,13 +779,14 @@ 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
|
to ~t~. When enabled, new files are created with the ~.org.gpg~ extension and
|
||||||
decryption are handled automatically by EasyPG.
|
decryption are handled automatically by EasyPG.
|
||||||
|
|
||||||
Note that Emacs will prompt for a password for encrypted files during
|
Note that Emacs will prompt for a password for encrypted files during cache
|
||||||
cache updates if it requires reading the encrypted file. To reduce the
|
updates if it requires reading the encrypted file. To reduce the number of
|
||||||
number of password prompts, you may wish to cache the password.
|
password prompts, you may wish to cache the password.
|
||||||
|
|
||||||
- Variable: org-roam-encrypt-files
|
- User Option: org-roam-encrypt-files
|
||||||
|
|
||||||
|
Whether to encrypt new files. If true, create files with .org.gpg extension.
|
||||||
|
|
||||||
Whether to encrypt new files. If true, create files with .org.gpg extension.
|
|
||||||
* Graphing
|
* Graphing
|
||||||
|
|
||||||
Org-roam provides graphing capabilities to explore interconnections between
|
Org-roam provides graphing capabilities to explore interconnections between
|
||||||
@ -727,21 +810,24 @@ The entry point to graph creation is ~org-roam-graph~.
|
|||||||
|
|
||||||
- User Option: org-roam-graph-executable
|
- 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.
|
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.
|
compact graph layout.
|
||||||
|
|
||||||
- User Option: org-roam-graph-viewer
|
- User Option: org-roam-graph-viewer
|
||||||
|
|
||||||
Org-roam defaults to using Firefox (located on PATH) to view the SVG, but you may choose to set it to:
|
Org-roam defaults to using Firefox (located on PATH) to view the SVG, but you
|
||||||
|
may choose to set it to:
|
||||||
|
|
||||||
1. A string, which is a path to the program used
|
1. A string, which is a path to the program used
|
||||||
2. a function accepting a single argument: the graph file path.
|
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:
|
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
|
#+BEGIN_SRC emacs-lisp
|
||||||
(setq org-roam-graph-viewer
|
(setq org-roam-graph-viewer
|
||||||
@ -752,7 +838,9 @@ The entry point to graph creation is ~org-roam-graph~.
|
|||||||
|
|
||||||
** Graph Options
|
** Graph Options
|
||||||
|
|
||||||
Graphviz provides many options for customizing the graph output, and Org-roam supports some of them. See https://graphviz.gitlab.io/_pages/doc/info/attrs.html for customizable options.
|
Graphviz provides many options for customizing the graph output, and Org-roam
|
||||||
|
supports some of them. See https://graphviz.gitlab.io/_pages/doc/info/attrs.html
|
||||||
|
for customizable options.
|
||||||
|
|
||||||
- User Option: org-roam-graph-extra-config
|
- User Option: org-roam-graph-extra-config
|
||||||
|
|
||||||
@ -817,13 +905,14 @@ commands, set:
|
|||||||
Other options include ~'ido~, and ~'ivy~.
|
Other options include ~'ido~, and ~'ivy~.
|
||||||
|
|
||||||
* Roam Protocol
|
* Roam Protocol
|
||||||
** _ :ignore:
|
|
||||||
Org-roam extending ~org-protocol~ with 2 protocols: the ~roam-file~
|
Org-roam extends ~org-protocol~ with 2 protocols: the ~roam-file~ and ~roam-ref~
|
||||||
and ~roam-ref~ protocol.
|
protocols.
|
||||||
|
|
||||||
** Installation
|
** Installation
|
||||||
|
|
||||||
To enable Org-roam's protocol extensions, you have to add the following to your init file:
|
To enable Org-roam's protocol extensions, you have to add the following to your
|
||||||
|
init file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(require 'org-roam-protocol)
|
(require 'org-roam-protocol)
|
||||||
@ -834,7 +923,8 @@ 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.
|
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
|
#+begin_example
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
@ -853,9 +943,9 @@ running in your shell:
|
|||||||
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
|
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
To disable the "confirm" prompt in Chrome, you can also make Chrome
|
To disable the "confirm" prompt in Chrome, you can also make Chrome show a
|
||||||
show a checkbox to tick, so that the ~Org-Protocol Client~ app will be used
|
checkbox to tick, so that the ~Org-Protocol Client~ app will be used without
|
||||||
without confirmation. To do this, run in a shell:
|
confirmation. To do this, run in a shell:
|
||||||
|
|
||||||
#+BEGIN_SRC bash
|
#+BEGIN_SRC bash
|
||||||
sudo mkdir -p /etc/opt/chrome/policies/managed/
|
sudo mkdir -p /etc/opt/chrome/policies/managed/
|
||||||
@ -891,7 +981,6 @@ brew cask install platypus
|
|||||||
|
|
||||||
3. Create a Platypus app with the following settings:
|
3. Create a Platypus app with the following settings:
|
||||||
|
|
||||||
#+begin_example
|
|
||||||
| Setting | Value |
|
| Setting | Value |
|
||||||
|--------------------------------+---------------------------|
|
|--------------------------------+---------------------------|
|
||||||
| App Name | "OrgProtocol" |
|
| App Name | "OrgProtocol" |
|
||||||
@ -900,18 +989,15 @@ brew cask install platypus
|
|||||||
| Interface | None |
|
| Interface | None |
|
||||||
| Accept dropped items | true |
|
| Accept dropped items | true |
|
||||||
| Remain running after execution | false |
|
| Remain running after execution | false |
|
||||||
#+end_example
|
|
||||||
|
|
||||||
|
|
||||||
Inside ~Settings~:
|
Inside ~Settings~:
|
||||||
|
|
||||||
#+begin_example
|
|
||||||
| Setting | Value |
|
| Setting | Value |
|
||||||
|--------------------------------+----------------|
|
|--------------------------------+----------------|
|
||||||
| Accept dropped files | true |
|
| Accept dropped files | true |
|
||||||
| Register as URI scheme handler | true |
|
| Register as URI scheme handler | true |
|
||||||
| Protocol | "org-protocol" |
|
| Protocol | "org-protocol" |
|
||||||
#+end_example
|
|
||||||
|
|
||||||
To disable the "confirm" prompt in Chrome, you can also make Chrome
|
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
|
||||||
@ -947,13 +1033,15 @@ REGEDIT4
|
|||||||
@="\"C:\\Windows\\System32\\wsl.exe\" emacsclient \"%1\""
|
@="\"C:\\Windows\\System32\\wsl.exe\" emacsclient \"%1\""
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
The above will forward the protocol to WSL. If you run Emacs natively on Windows, replace the last line with:
|
The above will forward the protocol to WSL. If you run Emacs natively on
|
||||||
|
Windows, replace the last line with:
|
||||||
|
|
||||||
#+BEGIN_SRC text
|
#+BEGIN_SRC text
|
||||||
@="\"c:\\path\\to\\emacs\\bin\\emacsclientw.exe\" \"%1\""
|
@="\"c:\\path\\to\\emacs\\bin\\emacsclientw.exe\" \"%1\""
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
After executing the .reg file, the protocol is registered and you can delete the file.
|
After executing the .reg file, the protocol is registered and you can delete the
|
||||||
|
file.
|
||||||
|
|
||||||
** The roam-file protocol
|
** The roam-file protocol
|
||||||
|
|
||||||
@ -970,11 +1058,13 @@ This protocol finds or creates a new note with a given ~roam_key~ (see [[*Anatom
|
|||||||
To use this, create the following [[https://en.wikipedia.org/wiki/Bookmarklet][bookmarklet]] in your browser:
|
To use this, create the following [[https://en.wikipedia.org/wiki/Bookmarklet][bookmarklet]] in your browser:
|
||||||
|
|
||||||
#+BEGIN_SRC javascript
|
#+BEGIN_SRC javascript
|
||||||
javascript:location.href =
|
javascript:location.href =
|
||||||
'org-protocol://roam-ref?template=r&ref='
|
'org-protocol://roam-ref?template=r&ref='
|
||||||
+ encodeURIComponent(location.href)
|
+ encodeURIComponent(location.href)
|
||||||
+ '&title='
|
+ '&title='
|
||||||
+ encodeURIComponent(document.title)
|
+ encodeURIComponent(document.title)
|
||||||
|
+ '&body='
|
||||||
|
+ encodeURIComponent(window.getSelection())
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
or as a keybinding in ~qutebrowser~ in , using the ~config.py~ file (see
|
or as a keybinding in ~qutebrowser~ in , using the ~config.py~ file (see
|
||||||
@ -988,7 +1078,122 @@ where ~template~ is the template key for a template in
|
|||||||
~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]). These templates
|
~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]). These templates
|
||||||
should contain a ~#+roam_key: ${ref}~ in it.
|
should contain a ~#+roam_key: ${ref}~ in it.
|
||||||
|
|
||||||
* TODO Daily Notes
|
* Daily-notes
|
||||||
|
|
||||||
|
Org-roam provides journaling capabilities akin to
|
||||||
|
[[#org-journal][Org-journal]] with ~org-roam-dailies~.
|
||||||
|
|
||||||
|
** Configuration
|
||||||
|
|
||||||
|
For ~org-roam-dailies~ to work, you need to define two variables:
|
||||||
|
|
||||||
|
- Variable: ~org-roam-dailies-directory~
|
||||||
|
|
||||||
|
Path to daily-notes.
|
||||||
|
|
||||||
|
- Variable: ~org-roam-dailies-capture-templates~
|
||||||
|
|
||||||
|
Capture templates for daily-notes in Org-roam.
|
||||||
|
|
||||||
|
Here is a sane default configuration:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq org-roam-dailies-directory "daily/")
|
||||||
|
|
||||||
|
(setq org-roam-dailies-capture-templates
|
||||||
|
'(("d" "default" entry
|
||||||
|
#'org-roam-capture--get-point
|
||||||
|
"* %?"
|
||||||
|
:file-name "daily/%<%Y-%m-%d>"
|
||||||
|
:head "#+title: %<%Y-%m-%d>\n\n")))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Make sure that ~org-roam-dailies-directory~ appears in ~:file-name~ for your
|
||||||
|
notes to be recognized as daily-notes. You can have different templates placing
|
||||||
|
their notes in different directories, but the one in
|
||||||
|
~org-roam-dailies-directory~ will be considered as the main one in commands.
|
||||||
|
|
||||||
|
See [[*The Templating System][The Templating System]] for creating new
|
||||||
|
templates. ~org-roam-dailies~ provides an extra ~:olp~ option which allows
|
||||||
|
specifying the outline-path to a heading:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq org-roam-dailies-capture-templates
|
||||||
|
'(("l" "lab" entry
|
||||||
|
#'org-roam-capture--get-point
|
||||||
|
"* %?"
|
||||||
|
:file-name "daily/%<%Y-%m-%d>"
|
||||||
|
:head "#+title: %<%Y-%m-%d>\n\n* Lab notes\n* Journal"
|
||||||
|
:olp ("Journal"))
|
||||||
|
|
||||||
|
("j" "journal" entry
|
||||||
|
#'org-roam-capture--get-point
|
||||||
|
"* %?"
|
||||||
|
:file-name "daily/%<%Y-%m-%d>"
|
||||||
|
:head "#+title: %<%Y-%m-%d>\n\n* Lab notes\n* Journal"
|
||||||
|
:olp ("Lab notes"))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The template ~l~ will put its notes under the heading ‘Lab notes’, and the
|
||||||
|
template ~j~ will put its notes under the heading ‘Journal’. When you use
|
||||||
|
~:olp~, make sure that the headings are present in ~:head~.
|
||||||
|
|
||||||
|
** Capturing and finding daily-notes
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-capture-today~ &optional goto
|
||||||
|
|
||||||
|
Create an entry in the daily note for today.
|
||||||
|
|
||||||
|
When ~goto~ is non-nil, go the note without creating an entry.
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-find-today~
|
||||||
|
|
||||||
|
Find the daily note for today, creating it if necessary.
|
||||||
|
|
||||||
|
There are variants of those commands for ~-yesterday~ and ~-tomorrow~:
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-capture-yesterday~ n &optional goto
|
||||||
|
|
||||||
|
Create an entry in the daily note for yesteday.
|
||||||
|
|
||||||
|
With numeric argument ~n~, use the daily note ~n~ days in the past.
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-find-yesterday~
|
||||||
|
|
||||||
|
With numeric argument N, use the daily-note N days in the future.
|
||||||
|
|
||||||
|
There are also commands which allow you to use Emacs’s ~calendar~ to find the date
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-capture-date~
|
||||||
|
|
||||||
|
Create an entry in the daily note for a date using the calendar.
|
||||||
|
|
||||||
|
Prefer past dates, unless ~prefer-future~ is non-nil.
|
||||||
|
|
||||||
|
With a 'C-u' prefix or when ~goto~ is non-nil, go the note without
|
||||||
|
creating an entry.
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-find-date~
|
||||||
|
|
||||||
|
Find the daily note for a date using the calendar, creating it if necessary.
|
||||||
|
|
||||||
|
Prefer past dates, unless ~prefer-future~ is non-nil.
|
||||||
|
|
||||||
|
** Navigation
|
||||||
|
|
||||||
|
You can navigate between daily-notes:
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-find-directory~
|
||||||
|
|
||||||
|
Find and open ~org-roam-dailies-directory~.
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-find-previous-note~
|
||||||
|
|
||||||
|
When in an daily-note, find the previous one.
|
||||||
|
|
||||||
|
- Function: ~org-roam-dailies-find-next-note~
|
||||||
|
|
||||||
|
When in an daily-note, find the next one.
|
||||||
|
|
||||||
* Diagnosing and Repairing Files
|
* Diagnosing and Repairing Files
|
||||||
|
|
||||||
@ -1002,9 +1207,11 @@ org-roam-doctor~, but note that this may take some time.
|
|||||||
Perform a check on Org-roam files to ensure cleanliness. If THIS-BUFFER, run
|
Perform a check on Org-roam files to ensure cleanliness. If THIS-BUFFER, run
|
||||||
the check only for the current buffer.
|
the check only for the current buffer.
|
||||||
|
|
||||||
The checks run are defined in ~org-roam-doctor--checkers~. Each checker is an
|
The checks run are defined in ~org-roam-doctor--checkers~. By default, there are
|
||||||
instance of ~org-roam-doctor-checker~. To define a checker, use
|
checkers for broken links and invalid =#+roam_*= properties.
|
||||||
~make-org-roam-doctor-checker~. Here is a sample definition:
|
|
||||||
|
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
|
#+BEGIN_SRC emacs-lisp
|
||||||
(make-org-roam-doctor-checker
|
(make-org-roam-doctor-checker
|
||||||
@ -1016,10 +1223,10 @@ instance of ~org-roam-doctor-checker~. To define a checker, use
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
The ~:name~ property is the name of the function run. The function takes in the
|
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
|
Org parse tree, and returns a list of ~(point error-message)~. ~:description~ is
|
||||||
short description of what the checker does. ~:actions~ is an alist containing
|
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
|
elements of the form ~(char . (prompt . function))~. These actions are defined
|
||||||
checker, to perform autofixes for the errors. For each error detected,
|
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
|
window displaying the error message, as well as the list of actions that can be
|
||||||
taken provided in ~:actions~.
|
taken provided in ~:actions~.
|
||||||
@ -1032,17 +1239,24 @@ facilities for discovering these unlinked references, so one may decide whether
|
|||||||
to convert them into links.
|
to convert them into links.
|
||||||
|
|
||||||
To use this feature, simply call ~M-x org-roam-unlinked-references~ from within
|
To use this feature, simply call ~M-x org-roam-unlinked-references~ from within
|
||||||
an Org-roam note. Org-roam uses [[https://github.com/BurntSushi/ripgrep][ripgrep]], specifically a clever PCRE regex to
|
an Org-roam note. Internally, Org-roam uses [[https://github.com/BurntSushi/ripgrep][ripgrep]] and a clever PCRE regex to
|
||||||
find occurrences of the title or aliases of the currently open note in all
|
find occurrences of the title or aliases of the currently open note in all
|
||||||
Org-roam files. This thus requires a version of ripgrep that is compiled with
|
Org-roam files. Hence, this requires a version of ripgrep that is compiled with
|
||||||
PCRE support.
|
PCRE support.
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
NOTE: Since ripgrep cannot read encrypted files, this function cannot find
|
||||||
|
unlinked references within encrypted files.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
* Performance Optimization
|
* Performance Optimization
|
||||||
** TODO Profiling Key Operations
|
** TODO Profiling Key Operations
|
||||||
** Garbage Collection
|
** Garbage Collection
|
||||||
|
|
||||||
During the cache-build process, Org-roam generates a lot of in-memory
|
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]]).
|
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
|
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
|
the threshold value for GC to be triggered during these memory-intensive
|
||||||
@ -1090,9 +1304,14 @@ General Public License for more details.
|
|||||||
|
|
||||||
*** Browsing History with winner-mode
|
*** 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~ 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:
|
~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
|
#+BEGIN_SRC emacs-lisp
|
||||||
(winner-mode +1)
|
(winner-mode +1)
|
||||||
@ -1130,10 +1349,9 @@ versions of a tracked Org-roam note.
|
|||||||
(deft-directory "/path/to/org-roam-files/"))
|
(deft-directory "/path/to/org-roam-files/"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
If the title of the Org file is not the first line, you might not get
|
If the title of the Org file is not the first line, you might not get nice
|
||||||
nice titles. You may choose to patch this to use ~org-roam~'s
|
titles. You may choose to patch this to use ~org-roam~'s functionality. Here I'm
|
||||||
functionality. Here I'm using
|
using [[https://github.com/raxod502/el-patch][el-patch]]:
|
||||||
[[https://github.com/raxod502/el-patch][el-patch]]:
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package el-patch
|
(use-package el-patch
|
||||||
@ -1161,19 +1379,18 @@ functionality. Here I'm using
|
|||||||
(org-roam--get-title-or-slug file))))
|
(org-roam--get-title-or-slug file))))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
The Deft interface can slow down quickly when the number of files get
|
The Deft interface can slow down quickly when the number of files get huge.
|
||||||
huge. [[https://github.com/hasu/notdeft][Notdeft]] is a fork of Deft
|
[[https://github.com/hasu/notdeft][Notdeft]] is a fork of Deft that uses an external search engine and indexer.
|
||||||
that uses an external search engine and indexer.
|
|
||||||
|
|
||||||
*** Org-journal
|
*** Org-journal
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: org-journal
|
:CUSTOM_ID: org-journal
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
[[https://github.com/bastibe/org-journal][Org-journal]] is a more
|
[[https://github.com/bastibe/org-journal][Org-journal]] provides journaling capabilities to Org-mode. A lot of its
|
||||||
powerful alternative to the simple function ~org-roam-dailies-today~. It
|
functionalities have been incorporated into Org-roam under the name
|
||||||
provides better journaling capabilities, and a nice calendar interface
|
[[*Daily-notes][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose
|
||||||
to see all dated entries.
|
journal entries from the ideas you would write on a scratchpad.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package org-journal
|
(use-package org-journal
|
||||||
@ -1182,7 +1399,7 @@ to see all dated entries.
|
|||||||
:custom
|
:custom
|
||||||
(org-journal-date-prefix "#+title: ")
|
(org-journal-date-prefix "#+title: ")
|
||||||
(org-journal-file-format "%Y-%m-%d.org")
|
(org-journal-file-format "%Y-%m-%d.org")
|
||||||
(org-journal-dir "/path/to/org-roam-files/")
|
(org-journal-dir "/path/to/journal/files/")
|
||||||
(org-journal-date-format "%A, %d %B %Y"))
|
(org-journal-date-format "%A, %d %B %Y"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
@ -1253,6 +1470,10 @@ tight integration between
|
|||||||
~org-roam~. This helps you manage your bibliographic notes under
|
~org-roam~. This helps you manage your bibliographic notes under
|
||||||
~org-roam~.
|
~org-roam~.
|
||||||
|
|
||||||
|
For example, though helm-bibtex provides the ability to visit notes for
|
||||||
|
bibliographic entries, org-roam-bibtex extends it with the ability to visit the
|
||||||
|
file with the right =#+roam_key=.
|
||||||
|
|
||||||
**** Spaced Repetition
|
**** Spaced Repetition
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: spaced-repetition
|
:CUSTOM_ID: spaced-repetition
|
||||||
@ -1277,13 +1498,15 @@ contain:
|
|||||||
(org-roam-db-location . "./org-roam.db"))))
|
(org-roam-db-location . "./org-roam.db"))))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
All files within that directory will be treated as their own separate
|
All files within that directory will be treated as their own separate set of
|
||||||
set of Org-roam files. Remember to run ~org-roam-db-build-cache~ from a
|
Org-roam files. Remember to run ~org-roam-db-build-cache~ from a file within
|
||||||
file within that directory, at least once.
|
that directory, at least once.
|
||||||
|
|
||||||
** How do I migrate from Roam Research?
|
** How do I migrate from Roam Research?
|
||||||
|
|
||||||
Fabio has produced a command-line tool that converts markdown files exported from Roam Research into Org-roam compatible markdown. More instructions are provided [[https://github.com/fabioberger/roam-migration][in the repository]].
|
Fabio has produced a command-line tool that converts markdown files exported
|
||||||
|
from Roam Research into Org-roam compatible markdown. More instructions are
|
||||||
|
provided [[https://github.com/fabioberger/roam-migration][in the repository]].
|
||||||
|
|
||||||
** How do I create a note whose title already matches one of the candidates?
|
** How do I create a note whose title already matches one of the candidates?
|
||||||
|
|
||||||
@ -1293,11 +1516,40 @@ This situation arises when, for example, one would like to create a note titled
|
|||||||
The solution is dependent on the mini-buffer completion framework in use. Here
|
The solution is dependent on the mini-buffer completion framework in use. Here
|
||||||
are the solutions:
|
are the solutions:
|
||||||
|
|
||||||
- Ivy :: call ~ivy-immediate-done~, typically bound to ~C-M-j~. Alternatively, set ~ivy-use-selectable-prompt~ to ~t~, so that "bar" is now selectable.
|
- Ivy :: call ~ivy-immediate-done~, typically bound to ~C-M-j~. Alternatively,
|
||||||
- Helm :: Org-roam should provide a selectable "[?] bar" candidate at the top of the candidate list.
|
set ~ivy-use-selectable-prompt~ to ~t~, so that "bar" is now selectable.
|
||||||
|
- Helm :: Org-roam should provide a selectable "[?] bar" candidate at the top of
|
||||||
|
the candidate list.
|
||||||
|
|
||||||
|
* Keystroke Index
|
||||||
|
:PROPERTIES:
|
||||||
|
:APPENDIX: t
|
||||||
|
:INDEX: ky
|
||||||
|
:COOKIE_DATA: recursive
|
||||||
|
:END:
|
||||||
|
* Command Index
|
||||||
|
:PROPERTIES:
|
||||||
|
:APPENDIX: t
|
||||||
|
:INDEX: cp
|
||||||
|
:END:
|
||||||
|
* Function Index
|
||||||
|
:PROPERTIES:
|
||||||
|
:APPENDIX: t
|
||||||
|
:INDEX: fn
|
||||||
|
:END:
|
||||||
|
* Variable Index
|
||||||
|
:PROPERTIES:
|
||||||
|
:APPENDIX: t
|
||||||
|
:INDEX: vr
|
||||||
|
:END:
|
||||||
|
|
||||||
|
* Footnotes
|
||||||
|
[fn:roam] To understand more about Roam, a collection of links are available in [[*Note-taking Workflows][Note-taking Workflows]].
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# eval: (require 'ol-info)
|
# eval: (require 'ol-info)
|
||||||
|
# eval: (require 'ox-texinfo+ nil t)
|
||||||
|
# eval: (auto-fill-mode +1)
|
||||||
# before-save-hook: org-make-toc
|
# before-save-hook: org-make-toc
|
||||||
# after-save-hook: (lambda nil (progn (require 'ox-texinfo nil t) (org-texinfo-export-to-info)))
|
# after-save-hook: (lambda nil (progn (require 'ox-texinfo nil t) (org-texinfo-export-to-info)))
|
||||||
# indent-tabs-mode: nil
|
# indent-tabs-mode: nil
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -47,7 +47,7 @@
|
|||||||
(defvar org-roam--org-link-bracket-typed-re)
|
(defvar org-roam--org-link-bracket-typed-re)
|
||||||
|
|
||||||
(declare-function org-roam-db--ensure-built "org-roam-db")
|
(declare-function org-roam-db--ensure-built "org-roam-db")
|
||||||
(declare-function org-roam--extract-ref "org-roam")
|
(declare-function org-roam--extract-refs "org-roam")
|
||||||
(declare-function org-roam--extract-titles "org-roam")
|
(declare-function org-roam--extract-titles "org-roam")
|
||||||
(declare-function org-roam--get-title-or-slug "org-roam")
|
(declare-function org-roam--get-title-or-slug "org-roam")
|
||||||
(declare-function org-roam--get-backlinks "org-roam")
|
(declare-function org-roam--get-backlinks "org-roam")
|
||||||
@ -107,11 +107,12 @@ For example: (setq org-roam-buffer-window-parameters '((no-other-window . t)))"
|
|||||||
(defun org-roam-buffer--find-file (file)
|
(defun org-roam-buffer--find-file (file)
|
||||||
"Open FILE in the window `org-roam' was called from."
|
"Open FILE in the window `org-roam' was called from."
|
||||||
(setq file (expand-file-name file))
|
(setq file (expand-file-name file))
|
||||||
(if (and org-roam-last-window (window-valid-p org-roam-last-window))
|
(let ((last-window org-roam-last-window))
|
||||||
(progn (with-selected-window org-roam-last-window
|
(if (window-valid-p last-window)
|
||||||
(org-roam--find-file file))
|
(progn (with-selected-window last-window
|
||||||
(select-window org-roam-last-window))
|
(org-roam--find-file file))
|
||||||
(org-roam--find-file file)))
|
(select-window last-window))
|
||||||
|
(org-roam--find-file file))))
|
||||||
|
|
||||||
(defun org-roam-buffer--insert-title ()
|
(defun org-roam-buffer--insert-title ()
|
||||||
"Insert the org-roam-buffer title."
|
"Insert the org-roam-buffer title."
|
||||||
@ -148,10 +149,11 @@ ORIG-PATH is the path where the CONTENT originated."
|
|||||||
|
|
||||||
(defun org-roam-buffer--insert-ref-links ()
|
(defun org-roam-buffer--insert-ref-links ()
|
||||||
"Insert ref backlinks for the current buffer."
|
"Insert ref backlinks for the current buffer."
|
||||||
(when-let ((path (cdr (with-temp-buffer
|
(when-let* ((refs (with-temp-buffer
|
||||||
(insert-buffer-substring org-roam-buffer--current)
|
(insert-buffer-substring org-roam-buffer--current)
|
||||||
(org-roam--extract-ref)))))
|
(org-roam--extract-refs)))
|
||||||
(if-let* ((key-backlinks (org-roam--get-backlinks path))
|
(paths (mapcar #'cdr refs)))
|
||||||
|
(if-let* ((key-backlinks (mapcan #'org-roam--get-backlinks paths))
|
||||||
(grouped-backlinks (--group-by (nth 0 it) key-backlinks)))
|
(grouped-backlinks (--group-by (nth 0 it) key-backlinks)))
|
||||||
(progn
|
(progn
|
||||||
(insert (let ((l (length key-backlinks)))
|
(insert (let ((l (length key-backlinks)))
|
||||||
@ -162,57 +164,56 @@ ORIG-PATH is the path where the CONTENT originated."
|
|||||||
(bls (cdr group)))
|
(bls (cdr group)))
|
||||||
(insert (format "** %s\n"
|
(insert (format "** %s\n"
|
||||||
(org-roam-format-link file-from
|
(org-roam-format-link file-from
|
||||||
(org-roam--get-title-or-slug file-from)
|
(org-roam--get-title-or-slug file-from)
|
||||||
"file")))
|
"file")))
|
||||||
(dolist (backlink bls)
|
(dolist (backlink bls)
|
||||||
(pcase-let ((`(,file-from _ ,props) backlink))
|
(pcase-let ((`(,file-from _ ,props) backlink))
|
||||||
(insert (propertize (org-roam-buffer-expand-links (plist-get props :content) file-from)
|
(insert (if-let ((content (plist-get props :content)))
|
||||||
'help-echo "mouse-1: visit backlinked note"
|
(propertize (org-roam-buffer-expand-links content file-from)
|
||||||
'file-from file-from
|
'help-echo "mouse-1: visit backlinked note"
|
||||||
'file-from-point (plist-get props :point)))
|
'file-from file-from
|
||||||
(insert "\n\n"))))))
|
'file-from-point (plist-get props :point))
|
||||||
|
"")
|
||||||
|
"\n\n"))))))
|
||||||
(insert "\n\n* No ref backlinks!"))))
|
(insert "\n\n* No ref backlinks!"))))
|
||||||
|
|
||||||
(defun org-roam-buffer--insert-backlinks ()
|
(defun org-roam-buffer--insert-backlinks ()
|
||||||
"Insert the org-roam-buffer backlinks string for the current buffer."
|
"Insert the org-roam-buffer backlinks string for the current buffer."
|
||||||
(if-let* ((file-path (buffer-file-name org-roam-buffer--current))
|
(let (props file-from)
|
||||||
(titles (with-current-buffer org-roam-buffer--current
|
(if-let* ((file-path (buffer-file-name org-roam-buffer--current))
|
||||||
(org-roam--extract-titles)))
|
(titles (with-current-buffer org-roam-buffer--current
|
||||||
(backlinks (org-roam--get-backlinks (push file-path titles)))
|
(org-roam--extract-titles)))
|
||||||
(grouped-backlinks (--group-by (nth 0 it) backlinks)))
|
(backlinks (org-roam--get-backlinks (push file-path titles)))
|
||||||
(progn
|
(grouped-backlinks (--group-by (nth 0 it) backlinks)))
|
||||||
(insert (let ((l (length backlinks)))
|
(progn
|
||||||
(format "\n\n* %d %s\n"
|
(insert (let ((l (length backlinks)))
|
||||||
l (org-roam-buffer--pluralize "Backlink" l))))
|
(format "\n\n* %d %s\n"
|
||||||
(dolist (group grouped-backlinks)
|
l (org-roam-buffer--pluralize "Backlink" l))))
|
||||||
(let ((file-from (car group))
|
(dolist (group grouped-backlinks)
|
||||||
(bls (mapcar (lambda (row)
|
(setq file-from (car group))
|
||||||
(nth 2 row)) (cdr group))))
|
(setq props (mapcar (lambda (row) (nth 2 row)) (cdr group)))
|
||||||
|
(setq props (seq-sort-by (lambda (p) (plist-get p :point)) #'< props))
|
||||||
(insert (format "** %s\n"
|
(insert (format "** %s\n"
|
||||||
(org-roam-format-link file-from
|
(org-roam-format-link file-from
|
||||||
(org-roam--get-title-or-slug file-from)
|
(org-roam--get-title-or-slug file-from)
|
||||||
"file")))
|
"file")))
|
||||||
;; Sort backlinks according to time of occurrence in buffer
|
(dolist (prop props)
|
||||||
(setq bls (seq-sort-by (lambda (bl)
|
|
||||||
(plist-get bl :point))
|
|
||||||
#'<
|
|
||||||
bls))
|
|
||||||
(dolist (props bls)
|
|
||||||
(insert "*** "
|
(insert "*** "
|
||||||
(if-let ((outline (plist-get props :outline)))
|
(if-let ((outline (plist-get prop :outline)))
|
||||||
(-> outline
|
(-> outline
|
||||||
(string-join " > ")
|
(string-join " > ")
|
||||||
(org-roam-buffer-expand-links file-from))
|
(org-roam-buffer-expand-links file-from))
|
||||||
"Top")
|
"Top")
|
||||||
"\n"
|
"\n"
|
||||||
(propertize
|
(if-let ((content (plist-get prop :content)))
|
||||||
(s-trim (s-replace "\n" " "
|
(propertize
|
||||||
(org-roam-buffer-expand-links (plist-get props :content) file-from)))
|
(s-trim (s-replace "\n" " " (org-roam-buffer-expand-links content file-from)))
|
||||||
'help-echo "mouse-1: visit backlinked note"
|
'help-echo "mouse-1: visit backlinked note"
|
||||||
'file-from file-from
|
'file-from file-from
|
||||||
'file-from-point (plist-get props :point))
|
'file-from-point (plist-get prop :point))
|
||||||
"\n\n")))))
|
"")
|
||||||
(insert "\n\n* No backlinks!")))
|
"\n\n"))))
|
||||||
|
(insert "\n\n* No backlinks!"))))
|
||||||
|
|
||||||
(defun org-roam-buffer-update ()
|
(defun org-roam-buffer-update ()
|
||||||
"Update the `org-roam-buffer'."
|
"Update the `org-roam-buffer'."
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -41,6 +41,7 @@
|
|||||||
(defvar org-roam-directory)
|
(defvar org-roam-directory)
|
||||||
(defvar org-roam-mode)
|
(defvar org-roam-mode)
|
||||||
(defvar org-roam-title-to-slug-function)
|
(defvar org-roam-title-to-slug-function)
|
||||||
|
|
||||||
(declare-function org-roam--get-title-path-completions "org-roam")
|
(declare-function org-roam--get-title-path-completions "org-roam")
|
||||||
(declare-function org-roam--get-ref-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--file-path-from-id "org-roam")
|
||||||
@ -74,11 +75,11 @@ note with the given `ref'.")
|
|||||||
(defvar org-roam-capture-additional-template-props nil
|
(defvar org-roam-capture-additional-template-props nil
|
||||||
"Additional props to be added to the Org-roam template.")
|
"Additional props to be added to the Org-roam template.")
|
||||||
|
|
||||||
(defconst org-roam-capture--template-keywords '(:file-name :head)
|
(defconst org-roam-capture--template-keywords '(:file-name :head :olp)
|
||||||
"Keywords used in `org-roam-capture-templates' specific to Org-roam.")
|
"Keywords used in `org-roam-capture-templates' specific to Org-roam.")
|
||||||
|
|
||||||
(defcustom org-roam-capture-templates
|
(defcustom org-roam-capture-templates
|
||||||
'(("d" "default" plain (function org-roam-capture--get-point)
|
`(("d" "default" plain (function org-roam-capture--get-point)
|
||||||
"%?"
|
"%?"
|
||||||
:file-name "%<%Y%m%d%H%M%S>-${slug}"
|
:file-name "%<%Y%m%d%H%M%S>-${slug}"
|
||||||
:head "#+title: ${title}\n"
|
:head "#+title: ${title}\n"
|
||||||
@ -218,10 +219,10 @@ Template string :\n%v")
|
|||||||
((const :format "%v " :kill-buffer) (const t))))))
|
((const :format "%v " :kill-buffer) (const t))))))
|
||||||
|
|
||||||
(defcustom org-roam-capture-ref-templates
|
(defcustom org-roam-capture-ref-templates
|
||||||
'(("r" "ref" plain (function org-roam-capture--get-point)
|
'(("r" "ref" plain #'org-roam-capture--get-point
|
||||||
"%?"
|
"%?"
|
||||||
:file-name "${slug}"
|
:file-name "${slug}"
|
||||||
:head "#+title: ${title}\n#+roam_key: ${ref}\n"
|
:head "#+title: ${title}\n#+roam_key: ${ref}"
|
||||||
:unnarrowed t))
|
:unnarrowed t))
|
||||||
"The Org-roam templates used during a capture from the roam-ref protocol.
|
"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'."
|
||||||
@ -408,26 +409,37 @@ aborted, we do the following:
|
|||||||
3. Add a function on `org-capture-before-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
|
the file if the original value of :no-save is not t and
|
||||||
`org-note-abort' is not t."
|
`org-note-abort' is not t."
|
||||||
(let* ((name-templ (org-roam-capture--get :file-name))
|
(let* ((name-templ (or (org-roam-capture--get :file-name)
|
||||||
|
(user-error "Template needs to specify `:file-name'")))
|
||||||
(new-id (s-trim (org-roam-capture--fill-template
|
(new-id (s-trim (org-roam-capture--fill-template
|
||||||
name-templ)))
|
name-templ)))
|
||||||
(file-path (org-roam--file-path-from-id new-id))
|
(file-path (org-roam--file-path-from-id new-id))
|
||||||
(roam-head (org-roam-capture--get :head))
|
(roam-head (or (org-roam-capture--get :head)
|
||||||
|
""))
|
||||||
(org-template (org-capture-get :template))
|
(org-template (org-capture-get :template))
|
||||||
(roam-template (concat roam-head org-template)))
|
(roam-template (concat roam-head org-template)))
|
||||||
(unless (file-exists-p file-path)
|
(unless (or (file-exists-p file-path)
|
||||||
|
(cl-some (lambda (buffer)
|
||||||
|
(string= (buffer-file-name buffer)
|
||||||
|
file-path))
|
||||||
|
(buffer-list)))
|
||||||
(make-directory (file-name-directory file-path) t)
|
(make-directory (file-name-directory file-path) t)
|
||||||
(org-roam-capture--put :orig-no-save (org-capture-get :no-save)
|
(org-roam-capture--put :orig-no-save (org-capture-get :no-save)
|
||||||
:new-file t)
|
:new-file t)
|
||||||
(org-capture-put :template
|
(pcase org-roam-capture--context
|
||||||
;; Fixes org-capture-place-plain-text throwing 'invalid search bound'
|
('dailies
|
||||||
;; when both :unnarowed t and "%?" is missing from the template string;
|
;; Populate the header of the daily file before capture to prevent it
|
||||||
;; may become unnecessary when the upstream bug is fixed
|
;; from appearing in the buffer-restriction
|
||||||
(if (s-contains-p "%?" roam-template)
|
(save-window-excursion
|
||||||
roam-template
|
(find-file file-path)
|
||||||
(concat roam-template "%?"))
|
(insert (substring (org-capture-fill-template (concat roam-head "*"))
|
||||||
:type 'plain
|
0 -2))
|
||||||
:no-save t))
|
(set-buffer-modified-p nil))
|
||||||
|
(org-capture-put :template org-template))
|
||||||
|
(_
|
||||||
|
(org-capture-put :template roam-template
|
||||||
|
:type 'plain)))
|
||||||
|
(org-capture-put :no-save t))
|
||||||
file-path))
|
file-path))
|
||||||
|
|
||||||
(defun org-roam-capture--get-point ()
|
(defun org-roam-capture--get-point ()
|
||||||
@ -446,32 +458,53 @@ If there is no file with that ref, a file with that ref is created.
|
|||||||
|
|
||||||
This function is used solely in Org-roam's capture templates: see
|
This function is used solely in Org-roam's capture templates: see
|
||||||
`org-roam-capture-templates'."
|
`org-roam-capture-templates'."
|
||||||
(let ((file-path (pcase org-roam-capture--context
|
(let* ((file-path (pcase org-roam-capture--context
|
||||||
('capture
|
('capture
|
||||||
(or (cdr (assoc 'file org-roam-capture--info))
|
(or (cdr (assoc 'file org-roam-capture--info))
|
||||||
(org-roam-capture--new-file)))
|
(org-roam-capture--new-file)))
|
||||||
('title
|
('title
|
||||||
(org-roam-capture--new-file))
|
(org-roam-capture--new-file))
|
||||||
('dailies
|
('dailies
|
||||||
(org-capture-put :default-time (cdr (assoc 'time org-roam-capture--info)))
|
(org-capture-put :default-time (cdr (assoc 'time org-roam-capture--info)))
|
||||||
(org-roam-capture--new-file))
|
(org-roam-capture--new-file))
|
||||||
('ref
|
('ref
|
||||||
(let ((completions (org-roam--get-ref-path-completions))
|
(let ((completions (org-roam--get-ref-path-completions))
|
||||||
(ref (cdr (assoc 'ref org-roam-capture--info))))
|
(ref (cdr (assoc 'ref org-roam-capture--info))))
|
||||||
(if-let ((pl (cdr (assoc ref completions))))
|
(if-let ((pl (cdr (assoc ref completions))))
|
||||||
(plist-get pl :path)
|
(plist-get pl :path)
|
||||||
(org-roam-capture--new-file))))
|
(org-roam-capture--new-file))))
|
||||||
(_ (error "Invalid org-roam-capture-context")))))
|
(_ (error "Invalid org-roam-capture-context")))))
|
||||||
(org-capture-put :template
|
(org-capture-put :template
|
||||||
(org-roam-capture--fill-template (org-capture-get :template)))
|
(org-roam-capture--fill-template (org-capture-get :template)))
|
||||||
(org-roam-capture--put :file-path file-path)
|
(org-roam-capture--put :file-path file-path
|
||||||
|
:finalize (or (org-capture-get :finalize)
|
||||||
|
(org-roam-capture--get :finalize)))
|
||||||
(while org-roam-capture-additional-template-props
|
(while org-roam-capture-additional-template-props
|
||||||
(let ((prop (pop org-roam-capture-additional-template-props))
|
(let ((prop (pop org-roam-capture-additional-template-props))
|
||||||
(val (pop org-roam-capture-additional-template-props)))
|
(val (pop org-roam-capture-additional-template-props)))
|
||||||
(org-roam-capture--put prop val)))
|
(org-roam-capture--put prop val)))
|
||||||
(set-buffer (org-capture-target-buffer file-path))
|
(set-buffer (org-capture-target-buffer file-path))
|
||||||
(widen)
|
(widen)
|
||||||
(goto-char (point-max))))
|
(if-let* ((olp (when (eq org-roam-capture--context 'dailies)
|
||||||
|
(--> (org-roam-capture--get :olp)
|
||||||
|
(pcase it
|
||||||
|
((pred stringp)
|
||||||
|
(list it))
|
||||||
|
((pred listp)
|
||||||
|
it)
|
||||||
|
(wrong-type
|
||||||
|
(signal 'wrong-type-argument
|
||||||
|
`((stringp listp)
|
||||||
|
,wrong-type))))))))
|
||||||
|
(condition-case err
|
||||||
|
(when-let ((marker (org-find-olp `(,file-path ,@olp))))
|
||||||
|
(goto-char marker)
|
||||||
|
(set-marker marker nil))
|
||||||
|
(error
|
||||||
|
(when (org-roam-capture--get :new-file)
|
||||||
|
(kill-buffer))
|
||||||
|
(signal (car err) (cdr err))))
|
||||||
|
(goto-char (point-min)))))
|
||||||
|
|
||||||
(defun org-roam-capture--convert-template (template)
|
(defun org-roam-capture--convert-template (template)
|
||||||
"Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax."
|
"Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax."
|
||||||
@ -512,7 +545,8 @@ GOTO and KEYS argument have the same functionality as
|
|||||||
`org-capture'."
|
`org-capture'."
|
||||||
(let* ((org-capture-templates (mapcar #'org-roam-capture--convert-template org-roam-capture-templates))
|
(let* ((org-capture-templates (mapcar #'org-roam-capture--convert-template org-roam-capture-templates))
|
||||||
(one-template-p (= (length org-capture-templates) 1))
|
(one-template-p (= (length org-capture-templates) 1))
|
||||||
org-capture-templates-contexts)
|
org-capture-templates-contexts
|
||||||
|
(org-capture-link-is-already-stored t))
|
||||||
(when one-template-p
|
(when one-template-p
|
||||||
(setq keys (caar org-capture-templates)))
|
(setq keys (caar org-capture-templates)))
|
||||||
(if (or one-template-p
|
(if (or one-template-p
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -79,6 +79,14 @@
|
|||||||
"org-roam 1.1.0")
|
"org-roam 1.1.0")
|
||||||
(define-obsolete-function-alias 'org-roam-db--clear 'org-roam-db-clear
|
(define-obsolete-function-alias 'org-roam-db--clear 'org-roam-db-clear
|
||||||
"org-roam 1.2.0")
|
"org-roam 1.2.0")
|
||||||
|
(define-obsolete-function-alias 'org-roam-dailies-today 'org-roam-dailies-find-today
|
||||||
|
"org-roam 1.2.2")
|
||||||
|
(define-obsolete-function-alias 'org-roam-dailies-yesterday 'org-roam-dailies-find-yesterday
|
||||||
|
"org-roam 1.2.2")
|
||||||
|
(define-obsolete-function-alias 'org-roam-dailies-tomorrow 'org-roam-dailies-find-tomorrow
|
||||||
|
"org-roam 1.2.2")
|
||||||
|
(define-obsolete-function-alias 'org-roam-dailies-date 'org-roam-dailies-find-date
|
||||||
|
"org-roam 1.2.2")
|
||||||
|
|
||||||
;;;; Variables
|
;;;; Variables
|
||||||
(define-obsolete-variable-alias 'org-roam-graphviz-extra-options
|
(define-obsolete-variable-alias 'org-roam-graphviz-extra-options
|
||||||
@ -95,6 +103,9 @@
|
|||||||
'org-roam-dailies-capture-templates "org-roam 1.0.0")
|
'org-roam-dailies-capture-templates "org-roam 1.0.0")
|
||||||
(define-obsolete-variable-alias 'org-roam-date-filename-format
|
(define-obsolete-variable-alias 'org-roam-date-filename-format
|
||||||
'org-roam-dailies-capture-templates "org-roam 1.0.0")
|
'org-roam-dailies-capture-templates "org-roam 1.0.0")
|
||||||
|
(define-obsolete-variable-alias 'org-roam-update-db-idle-seconds
|
||||||
|
'org-roam-db-update-idle-seconds "org-roam 1.2.2")
|
||||||
|
|
||||||
(make-obsolete-variable 'org-roam-buffer-no-delete-other-windows
|
(make-obsolete-variable 'org-roam-buffer-no-delete-other-windows
|
||||||
'org-roam-buffer-window-parameters "org-roam 1.1.1")
|
'org-roam-buffer-window-parameters "org-roam 1.1.1")
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -79,6 +79,7 @@ Return user choice."
|
|||||||
(if (fboundp 'ivy-read)
|
(if (fboundp 'ivy-read)
|
||||||
(ivy-read prompt choices
|
(ivy-read prompt choices
|
||||||
:initial-input initial-input
|
:initial-input initial-input
|
||||||
|
:preselect initial-input
|
||||||
:require-match require-match
|
:require-match require-match
|
||||||
:action (prog1 action
|
:action (prog1 action
|
||||||
(setq action nil))
|
(setq action nil))
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
;;; org-roam-dailies.el --- Daily notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
;;; org-roam-dailies.el --- Daily-notes for Org-roam -*- coding: utf-8; lexical-binding: t; -*-
|
||||||
;;;
|
;;;
|
||||||
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
|
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
;; Copyright © 2020 Leo Vivier <leo.vivier+dev@gmail.com>
|
||||||
|
|
||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
;; Leo Vivier <leo.vivier+dev@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -27,7 +29,7 @@
|
|||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;
|
;;
|
||||||
;; This library provides functionality for creating daily notes. This is a
|
;; This library provides functionality for creating daily-notes. This is a
|
||||||
;; concept borrowed from Roam Research.
|
;; concept borrowed from Roam Research.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
@ -35,102 +37,330 @@
|
|||||||
(require 'org-capture)
|
(require 'org-capture)
|
||||||
(require 'org-roam-capture)
|
(require 'org-roam-capture)
|
||||||
(require 'org-roam-macs)
|
(require 'org-roam-macs)
|
||||||
|
(require 'f)
|
||||||
|
|
||||||
|
;;;; Declarations
|
||||||
|
(defvar org-roam-mode)
|
||||||
|
(defvar org-roam-directory)
|
||||||
|
(declare-function org-roam--org-file-p "org-roam")
|
||||||
|
(declare-function org-roam--file-path-from-id "org-roam")
|
||||||
|
(declare-function org-roam--find-file "org-roam")
|
||||||
|
(declare-function org-roam-mode "org-roam")
|
||||||
|
|
||||||
|
;;;; Customizable variables
|
||||||
|
(defcustom org-roam-dailies-directory "daily/"
|
||||||
|
"Path to daily-notes."
|
||||||
|
:group 'org-roam
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom org-roam-dailies-find-file-hook nil
|
||||||
|
"Hook that is run right after navigating to a daily-note."
|
||||||
|
:group 'org-roam
|
||||||
|
:type 'hook)
|
||||||
|
|
||||||
(defcustom org-roam-dailies-capture-templates
|
(defcustom org-roam-dailies-capture-templates
|
||||||
'(("d" "daily" plain (function org-roam-capture--get-point)
|
'(("d" "default" entry (function org-roam-capture--get-point)
|
||||||
""
|
"* %?"
|
||||||
:immediate-finish t
|
:file-name "daily/%<%Y-%m-%d>"
|
||||||
:file-name "%<%Y-%m-%d>"
|
:head "#+title: %<%Y-%m-%d>\n"))
|
||||||
:head "#+title: %<%Y-%m-%d>"))
|
"Capture templates for daily-notes in Org-roam."
|
||||||
"Capture templates for daily notes in Org-roam."
|
|
||||||
:group 'org-roam
|
:group 'org-roam
|
||||||
;; Adapted from `org-capture-templates'
|
;; Adapted from `org-capture-templates'
|
||||||
:type
|
:type
|
||||||
'(repeat
|
'(repeat
|
||||||
(choice :value ("d" "daily" plain (function org-roam-capture--get-point)
|
(choice :value ("d" "default" plain (function org-roam-capture--get-point)
|
||||||
""
|
"%?"
|
||||||
:immediate-finish t
|
:file-name "daily/%<%Y-%m-%d>"
|
||||||
:file-name "%<%Y-%m-%d>"
|
:head "#+title: %<%Y-%m-%d>\n"
|
||||||
:head "#+title: %<%Y-%m-%d>")
|
:unnarrowed t)
|
||||||
(list :tag "Multikey description"
|
(list :tag "Multikey description"
|
||||||
(string :tag "Keys ")
|
(string :tag "Keys ")
|
||||||
(string :tag "Description"))
|
(string :tag "Description"))
|
||||||
(list :tag "Template entry"
|
(list :tag "Template entry"
|
||||||
(string :tag "Keys ")
|
(string :tag "Keys ")
|
||||||
(string :tag "Description ")
|
(string :tag "Description ")
|
||||||
(const :format "" plain)
|
(choice :tag "Type "
|
||||||
(const :format "" (function org-roam-capture--get-point))
|
(const :tag "Plain" plain)
|
||||||
(choice :tag "Template "
|
(const :tag "Entry (for creating headlines)" entry))
|
||||||
(string :tag "String"
|
(const :format "" #'org-roam-capture--get-point)
|
||||||
:format "String:\n \
|
(choice :tag "Template "
|
||||||
|
(string :tag "String"
|
||||||
|
:format "String:\n \
|
||||||
Template string :\n%v")
|
Template string :\n%v")
|
||||||
(list :tag "File"
|
(list :tag "File"
|
||||||
(const :format "" file)
|
(const :format "" file)
|
||||||
(file :tag "Template file "))
|
(file :tag "Template file "))
|
||||||
(list :tag "Function"
|
(list :tag "Function"
|
||||||
(const :format "" function)
|
(const :format "" function)
|
||||||
(function :tag "Template function ")))
|
(function :tag "Template function ")))
|
||||||
(const :format "" :immediate-finish) (const :format "" t)
|
(const :format "File name format :" :file-name)
|
||||||
(const :format "File name format :" :file-name)
|
(string :format " %v" :value "daily/%<%Y-%m-%d>")
|
||||||
(string :format " %v" :value "#+title: ${title}\n")
|
(const :format "Header format :" :head)
|
||||||
(const :format "Header format :" :head)
|
(string :format " %v" :value "#+title: ${title}\n")
|
||||||
(string :format "\n%v" :value "%<%Y%m%d%H%M%S>-${slug}")
|
(plist :inline t
|
||||||
(plist :inline t
|
:tag "Options"
|
||||||
:tag "Options"
|
;; Give the most common options as checkboxes
|
||||||
;; Give the most common options as checkboxes
|
:options
|
||||||
:options
|
(((const :tag "Outline path" :olp)
|
||||||
(((const :format "%v " :prepend) (const t))
|
(repeat :tag "Headings"
|
||||||
((const :format "%v " :jump-to-captured) (const t))
|
(string :tag "Heading")))
|
||||||
((const :format "%v " :empty-lines) (const 1))
|
((const :format "%v " :unnarrowed) (const t))
|
||||||
((const :format "%v " :empty-lines-before) (const 1))
|
((const :format "%v " :prepend) (const t))
|
||||||
((const :format "%v " :empty-lines-after) (const 1))
|
((const :format "%v " :immediate-finish) (const t))
|
||||||
((const :format "%v " :clock-in) (const t))
|
((const :format "%v " :jump-to-captured) (const t))
|
||||||
((const :format "%v " :clock-keep) (const t))
|
((const :format "%v " :empty-lines) (const 1))
|
||||||
((const :format "%v " :clock-resume) (const t))
|
((const :format "%v " :empty-lines-before) (const 1))
|
||||||
((const :format "%v " :time-prompt) (const t))
|
((const :format "%v " :empty-lines-after) (const 1))
|
||||||
((const :format "%v " :tree-type) (const week))
|
((const :format "%v " :clock-in) (const t))
|
||||||
((const :format "%v " :table-line-pos) (string))
|
((const :format "%v " :clock-keep) (const t))
|
||||||
((const :format "%v " :kill-buffer) (const t))
|
((const :format "%v " :clock-resume) (const t))
|
||||||
((const :format "%v " :unnarrowed) (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))))))))
|
||||||
|
|
||||||
;; Declarations
|
;;;; Utilities
|
||||||
(defvar org-roam-mode)
|
(defun org-roam-dailies-directory--get-absolute-path ()
|
||||||
(declare-function org-roam--file-path-from-id "org-roam")
|
"Get absolute path to `org-roam-dailies-directory'."
|
||||||
(declare-function org-roam-mode "org-roam")
|
(-> (concat
|
||||||
|
(file-name-as-directory org-roam-directory)
|
||||||
|
org-roam-dailies-directory)
|
||||||
|
(file-truename)))
|
||||||
|
|
||||||
(defun org-roam-dailies--file-for-time (time)
|
(defun org-roam-dailies-find-directory ()
|
||||||
"Create and find file for TIME."
|
"Find and open `org-roam-dailies-directory'."
|
||||||
(let ((org-roam-capture-templates org-roam-dailies-capture-templates)
|
(interactive)
|
||||||
|
(org-roam--find-file (org-roam-dailies-directory--get-absolute-path)))
|
||||||
|
|
||||||
|
(defun org-roam-dailies--daily-note-p (&optional file)
|
||||||
|
"Return t if FILE is an Org-roam daily-note, nil otherwise.
|
||||||
|
|
||||||
|
If FILE is not specified, use the current buffer's file-path."
|
||||||
|
(when-let ((path (or file
|
||||||
|
(-> (buffer-base-buffer)
|
||||||
|
(buffer-file-name))))
|
||||||
|
(directory (org-roam-dailies-directory--get-absolute-path)))
|
||||||
|
(setq path (file-truename path))
|
||||||
|
(save-match-data
|
||||||
|
(and
|
||||||
|
(org-roam--org-file-p path)
|
||||||
|
(f-descendant-of-p path directory)))))
|
||||||
|
|
||||||
|
(defun org-roam-dailies--capture (time &optional goto)
|
||||||
|
"Capture an entry in a daily-note for TIME, creating it if necessary.
|
||||||
|
|
||||||
|
When GOTO is non-nil, go the note without creating an entry."
|
||||||
|
(unless org-roam-mode (org-roam-mode))
|
||||||
|
(let ((org-roam-capture-templates (--> org-roam-dailies-capture-templates
|
||||||
|
(if goto (list (car it)) it)))
|
||||||
(org-roam-capture--info (list (cons 'time time)))
|
(org-roam-capture--info (list (cons 'time time)))
|
||||||
(org-roam-capture--context 'dailies))
|
(org-roam-capture--context 'dailies))
|
||||||
(setq org-roam-capture-additional-template-props (list :finalize 'find-file))
|
(setq org-roam-capture-additional-template-props (list :finalize 'find-file))
|
||||||
(org-roam-capture--capture)))
|
(org-roam-capture--capture (when goto '(4)))))
|
||||||
|
|
||||||
(defun org-roam-dailies-today ()
|
;;;; Commands
|
||||||
"Create and find the daily note for today."
|
;;; Today
|
||||||
|
(defun org-roam-dailies-capture-today (&optional goto)
|
||||||
|
"Create an entry in the daily-note for today.
|
||||||
|
|
||||||
|
When GOTO is non-nil, go the note without creating an entry."
|
||||||
|
(interactive "P")
|
||||||
|
(org-roam-dailies--capture (current-time) goto)
|
||||||
|
(when goto
|
||||||
|
(run-hooks 'org-roam-dailies-find-file-hook)
|
||||||
|
(message "Showing daily-note for today")))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-find-today ()
|
||||||
|
"Find the daily-note for today, creating it if necessary."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless org-roam-mode (org-roam-mode))
|
(org-roam-dailies-capture-today t))
|
||||||
(org-roam-dailies--file-for-time (current-time)))
|
|
||||||
|
|
||||||
(defun org-roam-dailies-tomorrow (n)
|
;;; Tomorrow
|
||||||
"Create and find the daily note for tomorrow.
|
(defun org-roam-dailies-capture-tomorrow (n &optional goto)
|
||||||
With numeric argument N, use N days in the future."
|
"Create an entry in the daily-note for tomorrow.
|
||||||
|
|
||||||
|
With numeric argument N, use the daily-note N days in the future.
|
||||||
|
|
||||||
|
With a `C-u' prefix or when GOTO is non-nil, go the note without
|
||||||
|
creating an entry."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(unless org-roam-mode (org-roam-mode))
|
(org-roam-dailies--capture (time-add (* n 86400) (current-time)) goto))
|
||||||
(org-roam-dailies--file-for-time (time-add (* n 86400) (current-time))))
|
|
||||||
|
|
||||||
(defun org-roam-dailies-yesterday (n)
|
(defun org-roam-dailies-find-tomorrow (n)
|
||||||
"Create and find the file for yesterday.
|
"Find the daily-note for tomorrow, creating it if necessary.
|
||||||
With numeric argument N, use N days in the past."
|
|
||||||
|
With numeric argument N, use the daily-note N days in the
|
||||||
|
future."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(unless org-roam-mode (org-roam-mode))
|
(org-roam-dailies-capture-tomorrow n t))
|
||||||
(org-roam-dailies-tomorrow (- n)))
|
|
||||||
|
|
||||||
(defun org-roam-dailies-date ()
|
;;; Yesterday
|
||||||
"Create the file for any date using the calendar interface."
|
(defun org-roam-dailies-capture-yesterday (n &optional goto)
|
||||||
|
"Create an entry in the daily-note for yesteday.
|
||||||
|
|
||||||
|
With numeric argument N, use the daily-note N days in the past.
|
||||||
|
|
||||||
|
When GOTO is non-nil, go the note without creating an entry."
|
||||||
|
(interactive "p")
|
||||||
|
(org-roam-dailies-capture-tomorrow (- n) goto))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-find-yesterday (n)
|
||||||
|
"Find the daily-note for yesterday, creating it if necessary.
|
||||||
|
|
||||||
|
With numeric argument N, use the daily-note N days in the
|
||||||
|
future."
|
||||||
|
(interactive "p")
|
||||||
|
(org-roam-dailies-capture-tomorrow (- n) t))
|
||||||
|
|
||||||
|
;;; Calendar
|
||||||
|
(defvar org-roam-dailies-calendar-hook (list 'org-roam-dailies-calendar-mark-entries)
|
||||||
|
"Hooks to run when showing the `org-roam-dailies-calendar'.")
|
||||||
|
|
||||||
|
(defun org-roam-dailies-calendar--install-hook ()
|
||||||
|
"Install Org-roam-dailies hooks to calendar."
|
||||||
|
(add-hook 'calendar-today-visible-hook #'org-roam-dailies-calendar--run-hook)
|
||||||
|
(add-hook 'calendar-today-invisible-hook #'org-roam-dailies-calendar--run-hook))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-calendar--run-hook ()
|
||||||
|
"Run Org-roam-dailies hooks to calendar."
|
||||||
|
(run-hooks 'org-roam-dailies-calendar-hook)
|
||||||
|
(remove-hook 'calendar-today-visible-hook #'org-roam-dailies-calendar--run-hook)
|
||||||
|
(remove-hook 'calendar-today-invisible-hook #'org-roam-dailies-calendar--run-hook))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-calendar--file-to-date (&optional file)
|
||||||
|
"Convert FILE to date.
|
||||||
|
|
||||||
|
Return (MONTH DAY YEAR)."
|
||||||
|
(let ((file (or file
|
||||||
|
(-> (buffer-base-buffer)
|
||||||
|
(buffer-file-name)))))
|
||||||
|
(cl-destructuring-bind (_ _ _ d m y _ _ _)
|
||||||
|
(-> file
|
||||||
|
(file-name-nondirectory)
|
||||||
|
(file-name-sans-extension)
|
||||||
|
(org-parse-time-string))
|
||||||
|
(list m d y))))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-calendar--date-to-time (date)
|
||||||
|
"Convert DATE as returned from the calendar (MONTH DAY YEAR) to a time."
|
||||||
|
(encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-calendar-mark-entries ()
|
||||||
|
"Mark days in the calendar for which a daily-note is present."
|
||||||
|
(when (file-exists-p (org-roam-dailies-directory--get-absolute-path))
|
||||||
|
(dolist (date (mapcar #'org-roam-dailies-calendar--file-to-date
|
||||||
|
(org-roam-dailies--list-files)))
|
||||||
|
(when (calendar-date-is-visible-p date)
|
||||||
|
(calendar-mark-visible-date date 'org-roam-dailies-calendar-note)))))
|
||||||
|
|
||||||
|
;;; Date
|
||||||
|
(defun org-roam-dailies-capture-date (&optional goto prefer-future)
|
||||||
|
"Create an entry in the daily-note for a date using the calendar.
|
||||||
|
|
||||||
|
Prefer past dates, unless PREFER-FUTURE is non-nil.
|
||||||
|
|
||||||
|
With a `C-u' prefix or when GOTO is non-nil, go the note without
|
||||||
|
creating an entry."
|
||||||
|
(interactive "P")
|
||||||
|
(org-roam-dailies-calendar--install-hook)
|
||||||
|
(let* ((time-str (let ((org-read-date-prefer-future prefer-future))
|
||||||
|
(org-read-date nil nil nil (if goto
|
||||||
|
"Find daily-note: "
|
||||||
|
"Capture to daily-note: "))))
|
||||||
|
(time (org-read-date nil t time-str)))
|
||||||
|
(org-roam-dailies--capture time goto)
|
||||||
|
(when goto
|
||||||
|
(run-hooks 'org-roam-dailies-find-file-hook)
|
||||||
|
(message "Showing note for %s" time-str))))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-find-date (&optional prefer-future)
|
||||||
|
"Find the daily-note for a date using the calendar, creating it if necessary.
|
||||||
|
|
||||||
|
Prefer past dates, unless PREFER-FUTURE is non-nil."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((time (org-read-date nil 'to-time nil "Date: ")))
|
(org-roam-dailies-capture-date t prefer-future))
|
||||||
(org-roam-dailies--file-for-time time)))
|
|
||||||
|
;;; Navigation
|
||||||
|
(defun org-roam-dailies--list-files (&rest extra-files)
|
||||||
|
"List all files in `org-roam-dailies-directory'.
|
||||||
|
|
||||||
|
EXTRA-FILES can be used to append extra files to the list."
|
||||||
|
(let ((dir (org-roam-dailies-directory--get-absolute-path)))
|
||||||
|
(append (--remove (let ((file (file-name-nondirectory it)))
|
||||||
|
(when (or (auto-save-file-name-p file)
|
||||||
|
(backup-file-name-p file)
|
||||||
|
(string-match "^\\." file))
|
||||||
|
it))
|
||||||
|
(directory-files-recursively dir ""))
|
||||||
|
extra-files)))
|
||||||
|
|
||||||
|
(defun org-roam-dailies--find-next-note-path (&optional n file)
|
||||||
|
"Find next daily-note from FILE.
|
||||||
|
|
||||||
|
With numeric argument N, find note N days in the future. If N is
|
||||||
|
negative, find note N days in the past.
|
||||||
|
|
||||||
|
If FILE is not provided, use the file visited by the current
|
||||||
|
buffer."
|
||||||
|
(unless (org-roam-dailies--daily-note-p file)
|
||||||
|
(user-error "Not in a daily-note"))
|
||||||
|
(let ((n (or n 1))
|
||||||
|
(file (or file
|
||||||
|
(-> (buffer-base-buffer)
|
||||||
|
(buffer-file-name)))))
|
||||||
|
;; Ensure that the buffer is saved before moving
|
||||||
|
(save-buffer file)
|
||||||
|
(let* ((list (org-roam-dailies--list-files))
|
||||||
|
(position
|
||||||
|
(cl-position-if (lambda (candidate)
|
||||||
|
(string= file candidate))
|
||||||
|
list)))
|
||||||
|
(pcase n
|
||||||
|
((pred (natnump))
|
||||||
|
(if (eq position (- (length list) 1))
|
||||||
|
(user-error "Already at newest note")
|
||||||
|
(message "Showing next daily-note")))
|
||||||
|
((pred (integerp))
|
||||||
|
(if (eq position 0)
|
||||||
|
(user-error "Already at oldest note")
|
||||||
|
(message "Showing previous daily-note"))))
|
||||||
|
(nth (+ position n) list))))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-find-next-note (&optional n)
|
||||||
|
"Find next daily-note.
|
||||||
|
|
||||||
|
With numeric argument N, find note N days in the future. If N is
|
||||||
|
negative, find note N days in the past."
|
||||||
|
(interactive "p")
|
||||||
|
(let* ((n (or n 1))
|
||||||
|
(next (org-roam-dailies--find-next-note-path n)))
|
||||||
|
(find-file next)
|
||||||
|
(run-hooks 'org-roam-dailies-find-file-hook)))
|
||||||
|
|
||||||
|
(defun org-roam-dailies-find-previous-note (&optional n)
|
||||||
|
"Find previous daily-note.
|
||||||
|
|
||||||
|
With numeric argument N, find note N days in the past. If N is
|
||||||
|
negative, find note N days in the future."
|
||||||
|
(interactive "p")
|
||||||
|
(let ((n (if n (- n) -1)))
|
||||||
|
(org-roam-dailies-find-next-note n)))
|
||||||
|
|
||||||
|
;;;; Bindings
|
||||||
|
(defvar org-roam-dailies-map (make-sparse-keymap)
|
||||||
|
"Keymap for `org-roam-dailies'.")
|
||||||
|
|
||||||
|
(define-prefix-command 'org-roam-dailies-map)
|
||||||
|
|
||||||
|
(define-key org-roam-dailies-map (kbd "d") #'org-roam-dailies-find-today)
|
||||||
|
(define-key org-roam-dailies-map (kbd "y") #'org-roam-dailies-find-yesterday)
|
||||||
|
(define-key org-roam-dailies-map (kbd "t") #'org-roam-dailies-find-tomorrow)
|
||||||
|
(define-key org-roam-dailies-map (kbd "n") #'org-roam-dailies-capture-today)
|
||||||
|
(define-key org-roam-dailies-map (kbd "f") #'org-roam-dailies-find-next-note)
|
||||||
|
(define-key org-roam-dailies-map (kbd "b") #'org-roam-dailies-find-previous-note)
|
||||||
|
(define-key org-roam-dailies-map (kbd "c") #'org-roam-dailies-find-date)
|
||||||
|
(define-key org-roam-dailies-map (kbd "v") #'org-roam-dailies-capture-date)
|
||||||
|
(define-key org-roam-dailies-map (kbd ".") #'org-roam-dailies-find-directory)
|
||||||
|
|
||||||
(provide 'org-roam-dailies)
|
(provide 'org-roam-dailies)
|
||||||
|
|
||||||
|
458
org-roam-db.el
458
org-roam-db.el
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -35,17 +35,22 @@
|
|||||||
(require 'emacsql)
|
(require 'emacsql)
|
||||||
(require 'emacsql-sqlite3)
|
(require 'emacsql-sqlite3)
|
||||||
(require 'seq)
|
(require 'seq)
|
||||||
(require 'org-macs)
|
|
||||||
(require 'org-roam-macs)
|
(eval-and-compile
|
||||||
|
(require 'org-roam-macs)
|
||||||
|
;; For `org-with-wide-buffer'
|
||||||
|
(require 'org-macs))
|
||||||
|
|
||||||
(defvar org-roam-directory)
|
(defvar org-roam-directory)
|
||||||
(defvar org-roam-enable-headline-linking)
|
(defvar org-roam-enable-headline-linking)
|
||||||
(defvar org-roam-verbose)
|
(defvar org-roam-verbose)
|
||||||
(defvar org-roam-file-name)
|
(defvar org-roam-file-name)
|
||||||
|
|
||||||
|
(defvar org-agenda-files)
|
||||||
|
|
||||||
(declare-function org-roam--org-roam-file-p "org-roam")
|
(declare-function org-roam--org-roam-file-p "org-roam")
|
||||||
(declare-function org-roam--extract-titles "org-roam")
|
(declare-function org-roam--extract-titles "org-roam")
|
||||||
(declare-function org-roam--extract-ref "org-roam")
|
(declare-function org-roam--extract-refs "org-roam")
|
||||||
(declare-function org-roam--extract-tags "org-roam")
|
(declare-function org-roam--extract-tags "org-roam")
|
||||||
(declare-function org-roam--extract-ids "org-roam")
|
(declare-function org-roam--extract-ids "org-roam")
|
||||||
(declare-function org-roam--extract-links "org-roam")
|
(declare-function org-roam--extract-links "org-roam")
|
||||||
@ -79,11 +84,33 @@ value like `most-positive-fixnum'."
|
|||||||
:type 'int
|
:type 'int
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
(defconst org-roam-db--version 9)
|
(defconst org-roam-db--version 10)
|
||||||
|
|
||||||
(defvar org-roam-db--connection (make-hash-table :test #'equal)
|
(defvar org-roam-db--connection (make-hash-table :test #'equal)
|
||||||
"Database connection to Org-roam database.")
|
"Database connection to Org-roam database.")
|
||||||
|
|
||||||
|
(defvar org-roam-db-dirty nil
|
||||||
|
"Whether the org-roam database is dirty and requires an update.
|
||||||
|
Contains pairs of `org-roam-directory' and `org-roam-db-location'
|
||||||
|
so that multi-directories are updated.")
|
||||||
|
|
||||||
|
(defcustom org-roam-db-update-method 'idle-timer
|
||||||
|
"Method to update the Org-roam database.
|
||||||
|
|
||||||
|
`immediate'
|
||||||
|
Update the database immediately upon file changes.
|
||||||
|
|
||||||
|
`idle-timer'
|
||||||
|
Updates the database if dirty, if Emacs idles for `org-roam-db-update-idle-seconds'."
|
||||||
|
:type '(set (const :tag "idle-timer" idle-timer)
|
||||||
|
(const :tag "immediate" immediate))
|
||||||
|
:group 'org-roam)
|
||||||
|
|
||||||
|
(defcustom org-roam-db-update-idle-seconds 2
|
||||||
|
"Number of idle seconds before triggering an Org-roam database update."
|
||||||
|
:type 'integer
|
||||||
|
:group 'org-roam)
|
||||||
|
|
||||||
;;;; Core Functions
|
;;;; Core Functions
|
||||||
|
|
||||||
(defun org-roam-db--get-connection ()
|
(defun org-roam-db--get-connection ()
|
||||||
@ -141,8 +168,8 @@ SQL can be either the emacsql vector representation, or a string."
|
|||||||
(level :not-null)])
|
(level :not-null)])
|
||||||
|
|
||||||
(links
|
(links
|
||||||
[(from :not-null)
|
[(source :not-null)
|
||||||
(to :not-null)
|
(dest :not-null)
|
||||||
(type :not-null)
|
(type :not-null)
|
||||||
(properties :not-null)])
|
(properties :not-null)])
|
||||||
|
|
||||||
@ -191,6 +218,22 @@ the current `org-roam-directory'."
|
|||||||
(dolist (conn (hash-table-values org-roam-db--connection))
|
(dolist (conn (hash-table-values org-roam-db--connection))
|
||||||
(org-roam-db--close conn)))
|
(org-roam-db--close conn)))
|
||||||
|
|
||||||
|
;;;; Timer-based updating
|
||||||
|
(defvar org-roam-db-file-update-timer nil
|
||||||
|
"Timer for updating the database when dirty.")
|
||||||
|
|
||||||
|
(defun org-roam-db-mark-dirty ()
|
||||||
|
"Mark the Org-roam database as dirty."
|
||||||
|
(add-to-list 'org-roam-db-dirty (list org-roam-directory org-roam-db-location)
|
||||||
|
nil #'equal))
|
||||||
|
|
||||||
|
(defun org-roam-db-update-cache-on-timer ()
|
||||||
|
"Update the cache if the database is dirty.
|
||||||
|
This function is called on `org-roam-db-file-update-timer'."
|
||||||
|
(pcase-dolist (`(,org-roam-directory ,org-roam-db-location) org-roam-db-dirty)
|
||||||
|
(org-roam-db-build-cache))
|
||||||
|
(setq org-roam-db-dirty nil))
|
||||||
|
|
||||||
;;;; Database API
|
;;;; Database API
|
||||||
;;;;; Initialization
|
;;;;; Initialization
|
||||||
(defun org-roam-db--initialized-p ()
|
(defun org-roam-db--initialized-p ()
|
||||||
@ -219,82 +262,137 @@ This is equivalent to removing the node from the graph."
|
|||||||
(buffer-file-name (buffer-base-buffer))))))
|
(buffer-file-name (buffer-base-buffer))))))
|
||||||
(dolist (table (mapcar #'car org-roam-db--table-schemata))
|
(dolist (table (mapcar #'car org-roam-db--table-schemata))
|
||||||
(org-roam-db-query `[:delete :from ,table
|
(org-roam-db-query `[:delete :from ,table
|
||||||
:where (= ,(if (eq table 'links) 'from 'file) $s1)]
|
:where (= ,(if (eq table 'links) 'source 'file) $s1)]
|
||||||
file))))
|
file))))
|
||||||
|
|
||||||
;;;;; Insertion
|
;;;;; Inserting
|
||||||
(defun org-roam-db--insert-meta (file hash meta)
|
(defun org-roam-db--insert-meta (&optional update-p)
|
||||||
"Insert HASH and META for a FILE into the Org-roam cache."
|
"Update the metadata of the current buffer into the cache.
|
||||||
(org-roam-db-query
|
If UPDATE-P is non-nil, first remove the meta for the file in the database."
|
||||||
[:insert :into files
|
(let* ((file (or org-roam-file-name (buffer-file-name)))
|
||||||
:values $v1]
|
(attr (file-attributes file))
|
||||||
(list (vector file hash meta))))
|
(atime (file-attribute-access-time attr))
|
||||||
|
(mtime (file-attribute-modification-time attr))
|
||||||
|
(hash (org-roam-db--file-hash)))
|
||||||
|
(when update-p
|
||||||
|
(org-roam-db-query [:delete :from files
|
||||||
|
:where (= file $s1)]
|
||||||
|
file))
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into files
|
||||||
|
:values $v1]
|
||||||
|
(list (vector file hash (list :atime atime :mtime mtime))))))
|
||||||
|
|
||||||
(defun org-roam-db--insert-links (links)
|
(defun org-roam-db--insert-titles (&optional update-p)
|
||||||
"Insert LINKS into the Org-roam cache."
|
"Update the titles of the current buffer into the cache.
|
||||||
(org-roam-db-query
|
If UPDATE-P is non-nil, first remove titles for the file in the database.
|
||||||
[:insert :into links
|
Returns the number of rows inserted."
|
||||||
:values $v1]
|
(let* ((file (or org-roam-file-name (buffer-file-name)))
|
||||||
links))
|
(titles (or (org-roam--extract-titles)
|
||||||
|
(list (org-roam--path-to-slug file))))
|
||||||
|
(rows (mapcar (lambda (title)
|
||||||
|
(vector file title)) titles)))
|
||||||
|
(when update-p
|
||||||
|
(org-roam-db-query [:delete :from titles
|
||||||
|
:where (= file $s1)]
|
||||||
|
file))
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into titles
|
||||||
|
:values $v1]
|
||||||
|
rows)
|
||||||
|
(length rows)))
|
||||||
|
|
||||||
(defun org-roam-db--insert-titles (file titles)
|
(defun org-roam-db--insert-refs (&optional update-p)
|
||||||
"Insert TITLES for a FILE into the Org-roam cache."
|
"Update the refs of the current buffer into the cache.
|
||||||
(org-roam-db-query
|
If UPDATE-P is non-nil, first remove the ref for the file in the database."
|
||||||
[:insert :into titles
|
(let ((file (or org-roam-file-name (buffer-file-name)))
|
||||||
:values $v1]
|
(count 0))
|
||||||
(mapcar (lambda (title)
|
(when update-p
|
||||||
(vector file title)) titles)))
|
(org-roam-db-query [:delete :from refs
|
||||||
|
:where (= file $s1)]
|
||||||
|
file))
|
||||||
|
(when-let ((refs (org-roam--extract-refs)))
|
||||||
|
(dolist (ref refs)
|
||||||
|
(let ((key (cdr ref))
|
||||||
|
(type (car ref)))
|
||||||
|
(condition-case nil
|
||||||
|
(progn
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into refs :values $v1]
|
||||||
|
(list (vector key file type)))
|
||||||
|
(cl-incf count))
|
||||||
|
(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))))))))))
|
||||||
|
count))
|
||||||
|
|
||||||
(defun org-roam-db--insert-ids (ids)
|
(defun org-roam-db--insert-links (&optional update-p)
|
||||||
"Insert IDS into the Org-roam cache.
|
"Update the file links of the current buffer in the cache.
|
||||||
Returns t if the insertion was successful, nil otherwise.
|
If UPDATE-P is non-nil, first remove the links for the file in the database.
|
||||||
Insertions can fail when there is an ID conflict."
|
Return the number of rows inserted."
|
||||||
(condition-case nil
|
(let ((file (or org-roam-file-name (buffer-file-name))))
|
||||||
(progn
|
(when update-p
|
||||||
(org-roam-db-query
|
(org-roam-db-query [:delete :from links
|
||||||
[:insert :into ids
|
:where (= source $s1)]
|
||||||
:values $v1]
|
file))
|
||||||
ids)
|
(if-let ((links (org-roam--extract-links)))
|
||||||
t)
|
|
||||||
(error
|
|
||||||
(unless (listp ids)
|
|
||||||
(setq ids (list ids)))
|
|
||||||
(lwarn '(org-roam) :error
|
|
||||||
(format "Duplicate IDs in %s, one of:\n\n%s\n\nskipping..."
|
|
||||||
(aref (car ids) 1)
|
|
||||||
(string-join (mapcar (lambda (hl)
|
|
||||||
(aref hl 0)) ids) "\n")))
|
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun org-roam-db--insert-tags (file tags)
|
|
||||||
"Insert TAGS for a FILE into the Org-roam cache."
|
|
||||||
(org-roam-db-query
|
|
||||||
[:insert :into tags
|
|
||||||
:values $v1]
|
|
||||||
(list (vector file tags))))
|
|
||||||
|
|
||||||
(defun org-roam-db--insert-ref (file ref)
|
|
||||||
"Insert REF for FILE into the Org-roam cache.
|
|
||||||
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)))
|
|
||||||
(condition-case nil
|
|
||||||
(progn
|
(progn
|
||||||
(org-roam-db-query
|
(org-roam-db-query
|
||||||
[:insert :into refs :values $v1]
|
[:insert :into links
|
||||||
(list (vector key file type)))
|
:values $v1]
|
||||||
t)
|
links)
|
||||||
(error
|
(length links))
|
||||||
(lwarn '(org-roam) :error
|
0)))
|
||||||
(format "Duplicate ref %s in:\n\nA: %s\nB: %s\n\nskipping..."
|
|
||||||
key
|
(defun org-roam-db--insert-ids (&optional update-p)
|
||||||
file
|
"Update the ids of the current buffer into the cache.
|
||||||
(caar (org-roam-db-query
|
If UPDATE-P is non-nil, first remove ids for the file in the database.
|
||||||
[:select file :from refs
|
Returns the number of rows inserted."
|
||||||
:where (= ref $v1)]
|
(let ((file (or org-roam-file-name (buffer-file-name))))
|
||||||
(vector key)))))
|
(when update-p
|
||||||
nil))))
|
(org-roam-db-query [:delete :from ids
|
||||||
|
:where (= file $s1)]
|
||||||
|
file))
|
||||||
|
(if-let ((ids (org-roam--extract-ids file)))
|
||||||
|
(condition-case nil
|
||||||
|
(progn
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into ids
|
||||||
|
:values $v1]
|
||||||
|
ids)
|
||||||
|
(length ids))
|
||||||
|
(error
|
||||||
|
(lwarn '(org-roam) :error
|
||||||
|
(format "Duplicate IDs in %s, one of:\n\n%s\n\nskipping..."
|
||||||
|
(aref (car ids) 1)
|
||||||
|
(string-join (mapcar (lambda (hl)
|
||||||
|
(aref hl 0)) ids) "\n")))
|
||||||
|
0))
|
||||||
|
0)))
|
||||||
|
|
||||||
|
(defun org-roam-db--insert-tags (&optional update-p)
|
||||||
|
"Insert tags for the current buffer into the Org-roam cache.
|
||||||
|
If UPDATE-P is non-nil, first remove tags for the file in the database.
|
||||||
|
Return the number of rows inserted."
|
||||||
|
(let* ((file (or org-roam-file-name (buffer-file-name)))
|
||||||
|
(tags (org-roam--extract-tags file)))
|
||||||
|
(when update-p
|
||||||
|
(org-roam-db-query [:delete :from tags
|
||||||
|
:where (= file $s1)]
|
||||||
|
file))
|
||||||
|
(if tags
|
||||||
|
(progn (org-roam-db-query
|
||||||
|
[:insert :into tags
|
||||||
|
:values $v1]
|
||||||
|
(list (vector file tags)))
|
||||||
|
1)
|
||||||
|
0)))
|
||||||
|
|
||||||
;;;;; Fetching
|
;;;;; Fetching
|
||||||
(defun org-roam-db--get-current-files ()
|
(defun org-roam-db--get-current-files ()
|
||||||
@ -329,12 +427,12 @@ If the file does not have any connections, nil is returned."
|
|||||||
links_of(file, link) AS
|
links_of(file, link) AS
|
||||||
(WITH filelinks AS (SELECT * FROM links WHERE NOT \"type\" = '\"cite\"'),
|
(WITH filelinks AS (SELECT * FROM links WHERE NOT \"type\" = '\"cite\"'),
|
||||||
citelinks AS (SELECT * FROM links
|
citelinks AS (SELECT * FROM links
|
||||||
JOIN refs ON links.\"to\" = refs.\"ref\"
|
JOIN refs ON links.\"dest\" = refs.\"ref\"
|
||||||
AND links.\"type\" = '\"cite\"')
|
AND links.\"type\" = '\"cite\"')
|
||||||
SELECT \"from\", \"to\" FROM filelinks UNION
|
SELECT \"source\", \"dest\" FROM filelinks UNION
|
||||||
SELECT \"to\", \"from\" FROM filelinks UNION
|
SELECT \"dest\", \"source\" FROM filelinks UNION
|
||||||
SELECT \"file\", \"from\" FROM citelinks UNION
|
SELECT \"file\", \"source\" FROM citelinks UNION
|
||||||
SELECT \"from\", \"file\" FROM citelinks),
|
SELECT \"dest\", \"file\" FROM citelinks),
|
||||||
connected_component(file) AS
|
connected_component(file) AS
|
||||||
(SELECT link FROM links_of WHERE file = $s1
|
(SELECT link FROM links_of WHERE file = $s1
|
||||||
UNION
|
UNION
|
||||||
@ -351,12 +449,12 @@ connections, nil is returned."
|
|||||||
links_of(file, link) AS
|
links_of(file, link) AS
|
||||||
(WITH filelinks AS (SELECT * FROM links WHERE NOT \"type\" = '\"cite\"'),
|
(WITH filelinks AS (SELECT * FROM links WHERE NOT \"type\" = '\"cite\"'),
|
||||||
citelinks AS (SELECT * FROM links
|
citelinks AS (SELECT * FROM links
|
||||||
JOIN refs ON links.\"to\" = refs.\"ref\"
|
JOIN refs ON links.\"dest\" = refs.\"ref\"
|
||||||
AND links.\"type\" = '\"cite\"')
|
AND links.\"type\" = '\"cite\"')
|
||||||
SELECT \"from\", \"to\" FROM filelinks UNION
|
SELECT \"source\", \"dest\" FROM filelinks UNION
|
||||||
SELECT \"to\", \"from\" FROM filelinks UNION
|
SELECT \"dest\", \"source\" FROM filelinks UNION
|
||||||
SELECT \"file\", \"from\" FROM citelinks UNION
|
SELECT \"file\", \"source\" FROM citelinks UNION
|
||||||
SELECT \"from\", \"file\" FROM citelinks),
|
SELECT \"source\", \"file\" FROM citelinks),
|
||||||
-- Links are traversed in a breadth-first search. In order to calculate the
|
-- Links are traversed in a breadth-first search. In order to calculate the
|
||||||
-- distance of nodes and to avoid following cyclic links, the visited nodes
|
-- distance of nodes and to avoid following cyclic links, the visited nodes
|
||||||
-- are tracked in 'trace'.
|
-- are tracked in 'trace'.
|
||||||
@ -387,65 +485,6 @@ connections, nil is returned."
|
|||||||
(secure-hash 'sha1 (current-buffer)))))
|
(secure-hash 'sha1 (current-buffer)))))
|
||||||
|
|
||||||
;;;;; Updating
|
;;;;; Updating
|
||||||
(defun org-roam-db--update-meta ()
|
|
||||||
"Update the metadata of the current buffer into the cache."
|
|
||||||
(let* ((file (or org-roam-file-name (buffer-file-name)))
|
|
||||||
(attr (file-attributes file))
|
|
||||||
(atime (file-attribute-access-time attr))
|
|
||||||
(mtime (file-attribute-modification-time attr))
|
|
||||||
(hash (org-roam-db--file-hash)))
|
|
||||||
(org-roam-db-query [:delete :from files
|
|
||||||
:where (= file $s1)]
|
|
||||||
file)
|
|
||||||
(org-roam-db--insert-meta file hash (list :atime atime :mtime mtime))))
|
|
||||||
|
|
||||||
(defun org-roam-db--update-titles ()
|
|
||||||
"Update the title of the current buffer into the cache."
|
|
||||||
(let* ((file (or org-roam-file-name (buffer-file-name)))
|
|
||||||
(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 titles)))
|
|
||||||
|
|
||||||
(defun org-roam-db--update-tags ()
|
|
||||||
"Update the tags of the current buffer into the cache."
|
|
||||||
(let* ((file (or org-roam-file-name (buffer-file-name)))
|
|
||||||
(tags (org-roam--extract-tags file)))
|
|
||||||
(org-roam-db-query [:delete :from tags
|
|
||||||
:where (= file $s1)]
|
|
||||||
file)
|
|
||||||
(when tags
|
|
||||||
(org-roam-db--insert-tags file tags))))
|
|
||||||
|
|
||||||
(defun org-roam-db--update-refs ()
|
|
||||||
"Update the ref of the current buffer into the cache."
|
|
||||||
(let ((file (or org-roam-file-name (buffer-file-name))))
|
|
||||||
(org-roam-db-query [:delete :from refs
|
|
||||||
:where (= file $s1)]
|
|
||||||
file)
|
|
||||||
(when-let ((ref (org-roam--extract-ref)))
|
|
||||||
(org-roam-db--insert-ref file ref))))
|
|
||||||
|
|
||||||
(defun org-roam-db--update-links ()
|
|
||||||
"Update the file links of the current buffer in the cache."
|
|
||||||
(let ((file (or org-roam-file-name (buffer-file-name))))
|
|
||||||
(org-roam-db-query [:delete :from links
|
|
||||||
:where (= from $s1)]
|
|
||||||
file)
|
|
||||||
(when-let ((links (org-roam--extract-links)))
|
|
||||||
(org-roam-db--insert-links links))))
|
|
||||||
|
|
||||||
(defun org-roam-db--update-ids ()
|
|
||||||
"Update the ids of the current buffer into the cache."
|
|
||||||
(let* ((file (or org-roam-file-name (buffer-file-name))))
|
|
||||||
(org-roam-db-query [:delete :from ids
|
|
||||||
:where (= file $s1)]
|
|
||||||
file)
|
|
||||||
(when-let ((ids (org-roam--extract-ids file)))
|
|
||||||
(org-roam-db--insert-ids ids))))
|
|
||||||
|
|
||||||
(defun org-roam-db--update-file (&optional file-path)
|
(defun org-roam-db--update-file (&optional file-path)
|
||||||
"Update Org-roam cache for FILE-PATH.
|
"Update Org-roam cache for FILE-PATH.
|
||||||
If the file does not exist anymore, remove it from the cache.
|
If the file does not exist anymore, remove it from the cache.
|
||||||
@ -460,13 +499,13 @@ If the file exists, update the cache with information."
|
|||||||
(save-buffer)))
|
(save-buffer)))
|
||||||
(org-roam--with-temp-buffer file-path
|
(org-roam--with-temp-buffer file-path
|
||||||
(emacsql-with-transaction (org-roam-db)
|
(emacsql-with-transaction (org-roam-db)
|
||||||
(org-roam-db--update-meta)
|
(org-roam-db--insert-meta 'update)
|
||||||
(org-roam-db--update-tags)
|
(org-roam-db--insert-tags 'update)
|
||||||
(org-roam-db--update-titles)
|
(org-roam-db--insert-titles 'update)
|
||||||
(org-roam-db--update-refs)
|
(org-roam-db--insert-refs 'update)
|
||||||
(when org-roam-enable-headline-linking
|
(when org-roam-enable-headline-linking
|
||||||
(org-roam-db--update-ids))
|
(org-roam-db--insert-ids 'update))
|
||||||
(org-roam-db--update-links)))))
|
(org-roam-db--insert-links 'update)))))
|
||||||
|
|
||||||
(defun org-roam-db-build-cache (&optional force)
|
(defun org-roam-db-build-cache (&optional force)
|
||||||
"Build the cache for `org-roam-directory'.
|
"Build the cache for `org-roam-directory'.
|
||||||
@ -476,72 +515,67 @@ If FORCE, force a rebuild of the cache from scratch."
|
|||||||
(org-roam-db--close) ;; Force a reconnect
|
(org-roam-db--close) ;; Force a reconnect
|
||||||
(org-roam-db) ;; To initialize the database, no-op if already initialized
|
(org-roam-db) ;; To initialize the database, no-op if already initialized
|
||||||
(let* ((gc-cons-threshold org-roam-db-gc-threshold)
|
(let* ((gc-cons-threshold org-roam-db-gc-threshold)
|
||||||
(org-agenda-files nil)
|
(org-agenda-files nil)
|
||||||
(org-roam-files (org-roam--list-all-files))
|
(org-roam-files (org-roam--list-all-files))
|
||||||
(current-files (org-roam-db--get-current-files))
|
(current-files (org-roam-db--get-current-files))
|
||||||
(file-count 0)
|
|
||||||
(id-count 0)
|
(id-count 0)
|
||||||
(link-count 0)
|
(link-count 0)
|
||||||
(tag-count 0)
|
(tag-count 0)
|
||||||
(title-count 0)
|
(title-count 0)
|
||||||
(ref-count 0)
|
(ref-count 0)
|
||||||
(deleted-count 0)
|
(deleted-count 0)
|
||||||
(processed-count 0))
|
(modified-count 0)
|
||||||
(emacsql-with-transaction (org-roam-db)
|
(modified-files nil))
|
||||||
;; Two-step building
|
(dolist (file org-roam-files)
|
||||||
;; First step: Rebuild files and ids
|
(let ((contents-hash (org-roam-db--file-hash file)))
|
||||||
(dolist (file org-roam-files)
|
(unless (string= (gethash file current-files)
|
||||||
(org-roam-message "Processed %s/%s files..." processed-count (length org-roam-files))
|
contents-hash)
|
||||||
(let* ((attr (file-attributes file))
|
(push (cons file contents-hash) modified-files)))
|
||||||
(atime (file-attribute-access-time attr))
|
(remhash file current-files))
|
||||||
(mtime (file-attribute-modification-time attr)))
|
(dolist (file (hash-table-keys current-files))
|
||||||
(let ((contents-hash (org-roam-db--file-hash file)))
|
|
||||||
(unless (string= (gethash file current-files)
|
|
||||||
contents-hash)
|
|
||||||
(condition-case nil
|
|
||||||
(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 org-roam-enable-headline-linking
|
|
||||||
(when-let ((ids (org-roam--extract-ids file)))
|
|
||||||
(when (org-roam-db--insert-ids ids)
|
|
||||||
(setq id-count (+ id-count (length ids))))))
|
|
||||||
(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)))))
|
|
||||||
(file-error
|
|
||||||
(setq org-roam-files (remove file org-roam-files))
|
|
||||||
(org-roam-db--clear-file file)
|
|
||||||
(lwarn '(org-roam) :warning
|
|
||||||
"Skipping unreadable file while building cache: %s" file))))
|
|
||||||
(remhash file current-files)
|
|
||||||
(setq processed-count (+ processed-count 1)))))
|
|
||||||
(dolist (file (hash-table-keys current-files))
|
|
||||||
;; These files are no longer around, remove from cache...
|
;; These files are no longer around, remove from cache...
|
||||||
(org-roam-db--clear-file file)
|
(org-roam-db--clear-file file)
|
||||||
(setq deleted-count (1+ deleted-count))))
|
(setq deleted-count (1+ deleted-count)))
|
||||||
(org-roam-message "files: Δ%s, ids: Δ%s, links: Δ%s, tags: Δ%s, titles: Δ%s, refs: Δ%s, deleted: Δ%s"
|
(pcase-dolist (`(,file . _) modified-files)
|
||||||
file-count
|
(org-roam-db--clear-file file))
|
||||||
|
;; Process all the files for IDs first
|
||||||
|
;;
|
||||||
|
;; We do this so that link extraction is cheaper: this eliminates the need
|
||||||
|
;; to read the file to check if the ID really exists
|
||||||
|
(pcase-dolist (`(,file . ,contents-hash) modified-files)
|
||||||
|
(let* ((attr (file-attributes file))
|
||||||
|
(atime (file-attribute-access-time attr))
|
||||||
|
(mtime (file-attribute-modification-time attr)))
|
||||||
|
(condition-case nil
|
||||||
|
(org-roam--with-temp-buffer file
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into files
|
||||||
|
:values $v1]
|
||||||
|
(vector file contents-hash (list :atime atime :mtime mtime)))
|
||||||
|
(when org-roam-enable-headline-linking
|
||||||
|
(setq id-count (+ id-count (org-roam-db--insert-ids)))))
|
||||||
|
(file-error
|
||||||
|
(setq org-roam-files (remove file org-roam-files))
|
||||||
|
(org-roam-db--clear-file file)
|
||||||
|
(lwarn '(org-roam) :warning
|
||||||
|
"Skipping unreadable file while building cache: %s" file)))))
|
||||||
|
(pcase-dolist (`(,file . _) modified-files)
|
||||||
|
(org-roam-message "Processed %s/%s modified files..." modified-count (length modified-files))
|
||||||
|
(condition-case nil
|
||||||
|
(org-roam--with-temp-buffer file
|
||||||
|
(setq modified-count (1+ modified-count))
|
||||||
|
(setq link-count (+ link-count (org-roam-db--insert-links)))
|
||||||
|
(setq tag-count (+ tag-count (org-roam-db--insert-tags)))
|
||||||
|
(setq title-count (+ title-count (org-roam-db--insert-titles)))
|
||||||
|
(setq ref-count (+ ref-count (org-roam-db--insert-refs))))
|
||||||
|
(file-error
|
||||||
|
(setq org-roam-files (remove file org-roam-files))
|
||||||
|
(org-roam-db--clear-file file)
|
||||||
|
(lwarn '(org-roam) :warning
|
||||||
|
"Skipping unreadable file while building cache: %s" file))))
|
||||||
|
(org-roam-message "total: Δ%s, files-modified: Δ%s, ids: Δ%s, links: Δ%s, tags: Δ%s, titles: Δ%s, refs: Δ%s, deleted: Δ%s"
|
||||||
|
(length org-roam-files)
|
||||||
|
modified-count
|
||||||
id-count
|
id-count
|
||||||
link-count
|
link-count
|
||||||
tag-count
|
tag-count
|
||||||
@ -549,6 +583,16 @@ If FORCE, force a rebuild of the cache from scratch."
|
|||||||
ref-count
|
ref-count
|
||||||
deleted-count)))
|
deleted-count)))
|
||||||
|
|
||||||
|
(defun org-roam-db-update ()
|
||||||
|
"Update the database."
|
||||||
|
(pcase org-roam-db-update-method
|
||||||
|
('immediate
|
||||||
|
(org-roam-db-build-cache))
|
||||||
|
('idle-timer
|
||||||
|
(org-roam-db-mark-dirty))
|
||||||
|
(_
|
||||||
|
(user-error "Invalid `org-roam-db-update-method'"))))
|
||||||
|
|
||||||
(provide 'org-roam-db)
|
(provide 'org-roam-db)
|
||||||
|
|
||||||
;;; org-roam-db.el ends here
|
;;; org-roam-db.el ends here
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/jethrokuan/org-roam
|
;; URL: https://github.com/jethrokuan/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; Package-Requires: ((emacs "26.1"))
|
;; Package-Requires: ((emacs "26.1"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -65,6 +65,11 @@ This face is used on the region target by `org-roam-insertion'
|
|||||||
during an `org-roam-capture'."
|
during an `org-roam-capture'."
|
||||||
:group 'org-roam-faces)
|
:group 'org-roam-faces)
|
||||||
|
|
||||||
|
(defface org-roam-dailies-calendar-note
|
||||||
|
'((t :inherit (org-roam-link) :underline nil))
|
||||||
|
"Face for dates with a daily-note in the calendar"
|
||||||
|
:group 'org-roam-faces)
|
||||||
|
|
||||||
;;; _
|
;;; _
|
||||||
|
|
||||||
(provide 'org-roam-faces)
|
(provide 'org-roam-faces)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -32,7 +32,8 @@
|
|||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'xml) ;xml-escape-string
|
(require 'xml) ;xml-escape-string
|
||||||
(require 's) ;s-truncate, s-replace
|
(require 's) ;s-truncate, s-replace
|
||||||
(require 'org-roam-macs)
|
(eval-and-compile
|
||||||
|
(require 'org-roam-macs))
|
||||||
(require 'org-roam-db)
|
(require 'org-roam-db)
|
||||||
|
|
||||||
;;;; Declarations
|
;;;; Declarations
|
||||||
@ -169,15 +170,15 @@ into a digraph."
|
|||||||
(let* ((nodes (org-roam-db-query node-query))
|
(let* ((nodes (org-roam-db-query node-query))
|
||||||
(edges-query
|
(edges-query
|
||||||
`[:with selected :as [:select [file] :from ,node-query]
|
`[:with selected :as [:select [file] :from ,node-query]
|
||||||
:select :distinct [to from] :from links
|
:select :distinct [dest source] :from links
|
||||||
:where (and (in to selected) (in from selected))])
|
:where (and (in dest selected) (in source selected))])
|
||||||
(edges-cites-query
|
(edges-cites-query
|
||||||
`[:with selected :as [:select [file] :from ,node-query]
|
`[:with selected :as [:select [file] :from ,node-query]
|
||||||
:select :distinct [file from]
|
:select :distinct [file source]
|
||||||
:from links :inner :join refs :on (and (= links:to refs:ref)
|
:from links :inner :join refs :on (and (= links:dest refs:ref)
|
||||||
(= links:type "cite")
|
(= links:type "cite")
|
||||||
(= refs:type "cite"))
|
(= refs:type "cite"))
|
||||||
:where (and (in file selected) (in from selected))])
|
:where (and (in file selected) (in source selected))])
|
||||||
(edges (org-roam-db-query edges-query))
|
(edges (org-roam-db-query edges-query))
|
||||||
(edges-cites (org-roam-db-query edges-cites-query)))
|
(edges-cites (org-roam-db-query edges-cites-query)))
|
||||||
(insert "digraph \"org-roam\" {\n")
|
(insert "digraph \"org-roam\" {\n")
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -36,6 +36,10 @@
|
|||||||
|
|
||||||
(require 'ol)
|
(require 'ol)
|
||||||
(require 'org-roam-compat)
|
(require 'org-roam-compat)
|
||||||
|
(require 'org-roam-macs)
|
||||||
|
(require 'org-roam-db)
|
||||||
|
|
||||||
|
(require 'org-element)
|
||||||
|
|
||||||
(defvar org-roam-completion-ignore-case)
|
(defvar org-roam-completion-ignore-case)
|
||||||
(defvar org-roam-directory)
|
(defvar org-roam-directory)
|
||||||
@ -155,11 +159,11 @@ If there is no corresponding headline, return nil."
|
|||||||
(org-id-get-create))))))))
|
(org-id-get-create))))))))
|
||||||
|
|
||||||
;;; Path-related functions
|
;;; Path-related functions
|
||||||
(defun org-roam-link-get-path (path)
|
(defun org-roam-link-get-path (path &optional type)
|
||||||
"Return the PATH of the link to use.
|
"Return the PATH of the link to use.
|
||||||
Respect `org-link-file-path-type', see the variable documentation for details.
|
If TYPE is non-nil, create a link of TYPE. Otherwise, respect
|
||||||
If DIR is passed, use DIR as the default directory."
|
`org-link-file-path-type'."
|
||||||
(pcase org-roam-link-file-path-type
|
(pcase (or type org-roam-link-file-path-type)
|
||||||
('absolute
|
('absolute
|
||||||
(abbreviate-file-name (expand-file-name path)))
|
(abbreviate-file-name (expand-file-name path)))
|
||||||
('noabbrev
|
('noabbrev
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -34,9 +34,15 @@
|
|||||||
;;; Code:
|
;;; Code:
|
||||||
;;;; Library Requires
|
;;;; Library Requires
|
||||||
(require 'dash)
|
(require 'dash)
|
||||||
|
(require 's)
|
||||||
|
|
||||||
(defvar org-roam-verbose)
|
(defvar org-roam-verbose)
|
||||||
|
|
||||||
|
;; This is necessary to ensure all dependents on this module see
|
||||||
|
;; `org-mode-hook' and `org-inhibit-startup' as dynamic variables,
|
||||||
|
;; regardless of whether Org is loaded before their compilation.
|
||||||
|
(require 'org)
|
||||||
|
|
||||||
;;;; Utility Functions
|
;;;; Utility Functions
|
||||||
(defun org-roam--list-interleave (lst separator)
|
(defun org-roam--list-interleave (lst separator)
|
||||||
"Interleaves elements in LST with SEPARATOR."
|
"Interleaves elements in LST with SEPARATOR."
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; Package-Requires: ((emacs "26.1") (org "9.3"))
|
;; Package-Requires: ((emacs "26.1") (org "9.3"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -39,6 +39,11 @@
|
|||||||
(require 'org-roam)
|
(require 'org-roam)
|
||||||
(require 'ol) ;; for org-link-decode
|
(require 'ol) ;; for org-link-decode
|
||||||
|
|
||||||
|
(defcustom org-roam-protocol-store-links nil
|
||||||
|
"Whether to store links when capturing websites with `org-roam-protocol'."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'org-roam)
|
||||||
|
|
||||||
;;;; Functions
|
;;;; Functions
|
||||||
(defun org-roam-protocol-open-ref (info)
|
(defun org-roam-protocol-open-ref (info)
|
||||||
"Process an org-protocol://roam-ref?ref= style url with INFO.
|
"Process an org-protocol://roam-ref?ref= style url with INFO.
|
||||||
@ -46,7 +51,7 @@
|
|||||||
It opens or creates a note with the given ref.
|
It opens or creates a note with the given ref.
|
||||||
|
|
||||||
javascript:location.href = \\='org-protocol://roam-ref?template=r&ref=\\='+ \\
|
javascript:location.href = \\='org-protocol://roam-ref?template=r&ref=\\='+ \\
|
||||||
encodeURIComponent(location.href) + \\='&title=\\=' \\
|
encodeURIComponent(location.href) + \\='&title=\\=' + \\
|
||||||
encodeURIComponent(document.title) + \\='&body=\\=' + \\
|
encodeURIComponent(document.title) + \\='&body=\\=' + \\
|
||||||
encodeURIComponent(window.getSelection())"
|
encodeURIComponent(window.getSelection())"
|
||||||
(when-let* ((alist (org-roam--plist-to-alist info))
|
(when-let* ((alist (org-roam--plist-to-alist info))
|
||||||
@ -58,6 +63,20 @@ It opens or creates a note with the given ref.
|
|||||||
(error "No ref key provided"))
|
(error "No ref key provided"))
|
||||||
(when-let ((title (cdr (assoc 'title decoded-alist))))
|
(when-let ((title (cdr (assoc 'title decoded-alist))))
|
||||||
(push (cons 'slug (funcall org-roam-title-to-slug-function title)) decoded-alist))
|
(push (cons 'slug (funcall org-roam-title-to-slug-function title)) decoded-alist))
|
||||||
|
(let-alist decoded-alist
|
||||||
|
(let* ((ref (org-protocol-sanitize-uri .ref))
|
||||||
|
(type (and (string-match "^\\([a-z]+\\):" ref)
|
||||||
|
(match-string 1 ref)))
|
||||||
|
(title (or .title ""))
|
||||||
|
(body (or .body ""))
|
||||||
|
(orglink
|
||||||
|
(org-link-make-string ref (or (org-string-nw-p title) ref))))
|
||||||
|
(when org-roam-protocol-store-links
|
||||||
|
(push (list ref title) org-stored-links))
|
||||||
|
(org-link-store-props :type type
|
||||||
|
:link ref
|
||||||
|
:annotation orglink
|
||||||
|
:initial body)))
|
||||||
(let* ((org-roam-capture-templates org-roam-capture-ref-templates)
|
(let* ((org-roam-capture-templates org-roam-capture-ref-templates)
|
||||||
(org-roam-capture--context 'ref)
|
(org-roam-capture--context 'ref)
|
||||||
(org-roam-capture--info decoded-alist)
|
(org-roam-capture--info decoded-alist)
|
||||||
|
491
org-roam.el
491
org-roam.el
@ -5,7 +5,7 @@
|
|||||||
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
;; URL: https://github.com/org-roam/org-roam
|
;; URL: https://github.com/org-roam/org-roam
|
||||||
;; Keywords: org-mode, roam, convenience
|
;; Keywords: org-mode, roam, convenience
|
||||||
;; Version: 1.2.2
|
;; Version: 1.2.3
|
||||||
;; 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.2"))
|
;; 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.2"))
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
;; This file is NOT part of GNU Emacs.
|
||||||
@ -114,11 +114,6 @@ If nil, `find-file' is used."
|
|||||||
:type 'function
|
:type 'function
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
(defcustom org-roam-update-db-idle-seconds 2
|
|
||||||
"Number of idle seconds before triggering an Org-roam database update."
|
|
||||||
:type 'integer
|
|
||||||
:group 'org-roam)
|
|
||||||
|
|
||||||
(defcustom org-roam-include-type-in-ref-path-completions nil
|
(defcustom org-roam-include-type-in-ref-path-completions nil
|
||||||
"When t, include the type in ref-path completions.
|
"When t, include the type in ref-path completions.
|
||||||
Note that this only affects interactive calls.
|
Note that this only affects interactive calls.
|
||||||
@ -147,6 +142,11 @@ Formatter may be a function that takes title as its only argument."
|
|||||||
(function :tag "Custom function"))
|
(function :tag "Custom function"))
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
|
(defcustom org-roam-prefer-id-links t
|
||||||
|
"If non-nil, use ID for linking instead where available."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'org-roam)
|
||||||
|
|
||||||
(defcustom org-roam-list-files-commands
|
(defcustom org-roam-list-files-commands
|
||||||
(if (member system-type '(windows-nt ms-dos cygwin))
|
(if (member system-type '(windows-nt ms-dos cygwin))
|
||||||
nil
|
nil
|
||||||
@ -304,12 +304,6 @@ descriptive warnings when certain operations fail (e.g. parsing).")
|
|||||||
"]"))
|
"]"))
|
||||||
"Matches a typed link in double brackets.")
|
"Matches a typed link in double brackets.")
|
||||||
|
|
||||||
(defvar org-roam--file-update-timer nil
|
|
||||||
"Timer for updating the database on file changes.")
|
|
||||||
|
|
||||||
(defvar org-roam--file-update-queue nil
|
|
||||||
"List of files that need to be processed for a database update. Processed within `org-roam--file-update-timer'.")
|
|
||||||
|
|
||||||
;;;; Utilities
|
;;;; Utilities
|
||||||
(defun org-roam--plist-to-alist (plist)
|
(defun org-roam--plist-to-alist (plist)
|
||||||
"Return an alist of the property-value pairs in PLIST."
|
"Return an alist of the property-value pairs in PLIST."
|
||||||
@ -372,13 +366,14 @@ Like `file-name-extension', but does not strip version number."
|
|||||||
If FILE is not specified, use the current buffer's file-path."
|
If FILE is not specified, use the current buffer's file-path."
|
||||||
(when-let ((path (or file
|
(when-let ((path (or file
|
||||||
org-roam-file-name
|
org-roam-file-name
|
||||||
(buffer-file-name))))
|
(-> (buffer-base-buffer)
|
||||||
(save-match-data
|
(buffer-file-name)))))
|
||||||
(and
|
(save-match-data
|
||||||
(org-roam--org-file-p path)
|
(and
|
||||||
(not (and org-roam-file-exclude-regexp
|
(org-roam--org-file-p path)
|
||||||
(string-match-p org-roam-file-exclude-regexp path)))
|
(not (and org-roam-file-exclude-regexp
|
||||||
(f-descendant-of-p path (expand-file-name org-roam-directory))))))
|
(string-match-p org-roam-file-exclude-regexp path)))
|
||||||
|
(f-descendant-of-p path (expand-file-name org-roam-directory))))))
|
||||||
|
|
||||||
(defun org-roam--shell-command-files (cmd)
|
(defun org-roam--shell-command-files (cmd)
|
||||||
"Run CMD in the shell and return a list of files. If no files are found, an empty list is returned."
|
"Run CMD in the shell and return a list of files. If no files are found, an empty list is returned."
|
||||||
@ -510,22 +505,30 @@ Use external shell commands if defined in `org-roam-list-files-commands'."
|
|||||||
|
|
||||||
;;;; Org extraction functions
|
;;;; Org extraction functions
|
||||||
(defun org-roam--extract-global-props (props)
|
(defun org-roam--extract-global-props (props)
|
||||||
"Extract PROPS from the current org buffer.
|
"Extract PROPS from the current org buffer."
|
||||||
The search terminates when the first property is encountered."
|
(let ((collected
|
||||||
(if (functionp 'org-collect-keywords)
|
;; Collect the raw props first
|
||||||
(->> (org-collect-keywords props)
|
;; It'll be returned in the form of
|
||||||
;; convert (("TITLE" "my title")) to (("TITLE" . "my title"))
|
;; (("PROP" "value" ...) ("PROP2" "value" ...))
|
||||||
(mapcar (pcase-lambda (`(,k ,v)) (cons k v))))
|
(if (functionp 'org-collect-keywords)
|
||||||
(let ((buf (org-element-parse-buffer))
|
(org-collect-keywords props)
|
||||||
res)
|
(let ((buf (org-element-parse-buffer))
|
||||||
(dolist (prop props)
|
res)
|
||||||
(let ((p (org-element-map buf 'keyword
|
(dolist (prop props)
|
||||||
(lambda (kw)
|
(let ((p (org-element-map buf 'keyword
|
||||||
(when (string-equal (org-element-property :key kw) prop)
|
(lambda (kw)
|
||||||
(org-element-property :value kw)))
|
(when (string-equal (org-element-property :key kw) prop)
|
||||||
:first-match t)))
|
(org-element-property :value kw)))
|
||||||
(push (cons prop p) res)))
|
:first-match nil)))
|
||||||
res)))
|
(push (cons prop p) res)))
|
||||||
|
res))))
|
||||||
|
;; convert (("TITLE" "a" "b") ("Another" "c"))
|
||||||
|
;; to (("TITLE" . "a") ("TITLE" . "b") ("Another" . "c"))
|
||||||
|
(let (ret)
|
||||||
|
(pcase-dolist (`(,key . ,values) collected)
|
||||||
|
(dolist (value values)
|
||||||
|
(push (cons key value) ret)))
|
||||||
|
ret)))
|
||||||
|
|
||||||
(defun org-roam--get-outline-path ()
|
(defun org-roam--get-outline-path ()
|
||||||
"Return the outline path to the current entry.
|
"Return the outline path to the current entry.
|
||||||
@ -568,7 +571,7 @@ Assume buffer is widened and point is on a headline."
|
|||||||
"Extracts all link items within the current buffer.
|
"Extracts all link items within the current buffer.
|
||||||
Link items are of the form:
|
Link items are of the form:
|
||||||
|
|
||||||
[from to type properties]
|
[source dest type properties]
|
||||||
|
|
||||||
This is the format that emacsql expects when inserting into the database.
|
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
|
FILE-FROM is typically the buffer file path, but this may not exist, for example
|
||||||
@ -586,20 +589,20 @@ it as FILE-PATH."
|
|||||||
(let* ((type (org-roam--collate-types (org-element-property :type link)))
|
(let* ((type (org-roam--collate-types (org-element-property :type link)))
|
||||||
(path (org-element-property :path link))
|
(path (org-element-property :path link))
|
||||||
(element (org-element-at-point))
|
(element (org-element-at-point))
|
||||||
(begin (or (org-element-property :content-begin element)
|
(begin (or (org-element-property :contents-begin element)
|
||||||
(org-element-property :begin element)))
|
(org-element-property :begin element)))
|
||||||
|
(end (or (org-element-property :contents-end element)
|
||||||
|
(org-element-property :end element)))
|
||||||
(content (or (org-element-property :raw-value element)
|
(content (or (org-element-property :raw-value element)
|
||||||
(buffer-substring-no-properties
|
(when (and begin end)
|
||||||
begin
|
(string-trim (buffer-substring-no-properties begin end)))))
|
||||||
(or (org-element-property :content-end element)
|
|
||||||
(org-element-property :end element)))))
|
|
||||||
(content (string-trim content))
|
|
||||||
(properties (list :outline (org-roam--get-outline-path)
|
(properties (list :outline (org-roam--get-outline-path)
|
||||||
:content content
|
:content content
|
||||||
:point begin))
|
:point begin))
|
||||||
(names (pcase type
|
(names (pcase type
|
||||||
("id"
|
("id"
|
||||||
(list (car (org-roam-id-find path))))
|
(when-let ((file-path (org-roam-id-get-file path)))
|
||||||
|
(list file-path)))
|
||||||
("cite" (list path))
|
("cite" (list path))
|
||||||
("website" (list path))
|
("website" (list path))
|
||||||
("fuzzy" (list path))
|
("fuzzy" (list path))
|
||||||
@ -623,8 +626,9 @@ If FILE-PATH is nil, use the current file."
|
|||||||
(let (result)
|
(let (result)
|
||||||
;; We need to handle the special case of the file property drawer (at outline level 0)
|
;; We need to handle the special case of the file property drawer (at outline level 0)
|
||||||
(org-with-point-at (point-min)
|
(org-with-point-at (point-min)
|
||||||
(when-let ((id (org-entry-get nil "ID")))
|
(when-let ((before-first-heading (= 0 (org-outline-level)))
|
||||||
(push (vector id file-path (org-outline-level)) result)))
|
(id (org-entry-get nil "ID")))
|
||||||
|
(push (vector id file-path 0) result)))
|
||||||
(org-map-region
|
(org-map-region
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(when-let ((id (org-entry-get nil "ID")))
|
(when-let ((id (org-entry-get nil "ID")))
|
||||||
@ -671,18 +675,19 @@ Reads from the \"roam_alias\" property."
|
|||||||
(defun org-roam--extract-titles (&optional sources nested)
|
(defun org-roam--extract-titles (&optional sources nested)
|
||||||
"Extract the titles from current buffer using SOURCES.
|
"Extract the titles from current buffer using SOURCES.
|
||||||
If NESTED, return the first successful result from SOURCES."
|
If NESTED, return the first successful result from SOURCES."
|
||||||
(let (coll res)
|
(org-with-wide-buffer
|
||||||
(cl-dolist (source (or sources
|
(let (coll res)
|
||||||
org-roam-title-sources))
|
(cl-dolist (source (or sources
|
||||||
(setq res (if (symbolp source)
|
org-roam-title-sources))
|
||||||
(funcall (intern (concat "org-roam--extract-titles-" (symbol-name source))))
|
(setq res (if (symbolp source)
|
||||||
(org-roam--extract-titles source t)))
|
(funcall (intern (concat "org-roam--extract-titles-" (symbol-name source))))
|
||||||
(when res
|
(org-roam--extract-titles source t)))
|
||||||
(if (not nested)
|
(when res
|
||||||
(setq coll (nconc coll res))
|
(if (not nested)
|
||||||
(setq coll res)
|
(setq coll (nconc coll res))
|
||||||
(cl-return))))
|
(setq coll res)
|
||||||
coll))
|
(cl-return))))
|
||||||
|
coll)))
|
||||||
|
|
||||||
(defun org-roam--extract-tags-all-directories (file)
|
(defun org-roam--extract-tags-all-directories (file)
|
||||||
"Extract tags from using the directory path FILE.
|
"Extract tags from using the directory path FILE.
|
||||||
@ -759,20 +764,30 @@ backlinks."
|
|||||||
"website")
|
"website")
|
||||||
(t type)))
|
(t type)))
|
||||||
|
|
||||||
|
(defun org-roam--extract-refs ()
|
||||||
|
"Extract all refs (ROAM_KEY statements) from the current buffer.
|
||||||
|
|
||||||
|
Each ref is returned as a cons of its type and its key."
|
||||||
|
(let (refs)
|
||||||
|
(pcase-dolist
|
||||||
|
(`(,_ . ,roam-key)
|
||||||
|
(org-roam--extract-global-props '("ROAM_KEY")))
|
||||||
|
(let (type path)
|
||||||
|
(pcase roam-key
|
||||||
|
('nil nil)
|
||||||
|
((pred string-empty-p)
|
||||||
|
(user-error "Org property #+roam_key cannot be empty"))
|
||||||
|
(ref
|
||||||
|
(when (string-match org-link-plain-re ref)
|
||||||
|
(setq type (org-roam--collate-types (match-string 1 ref))
|
||||||
|
path (match-string 2 ref)))))
|
||||||
|
(when (and type path)
|
||||||
|
(push (cons type path) refs))))
|
||||||
|
refs))
|
||||||
|
|
||||||
(defun org-roam--extract-ref ()
|
(defun org-roam--extract-ref ()
|
||||||
"Extract the ref from current buffer and return the type and the key of the ref."
|
"Extract the ref from current buffer and return the type and the key of the ref."
|
||||||
(let (type path)
|
(car (org-roam--extract-refs)))
|
||||||
(pcase (cdr (assoc "ROAM_KEY"
|
|
||||||
(org-roam--extract-global-props '("ROAM_KEY"))))
|
|
||||||
('nil nil)
|
|
||||||
((pred string-empty-p)
|
|
||||||
(user-error "Org property #+roam_key cannot be empty"))
|
|
||||||
(ref
|
|
||||||
(when (string-match org-link-plain-re ref)
|
|
||||||
(setq type (org-roam--collate-types (match-string 1 ref))
|
|
||||||
path (match-string 2 ref)))))
|
|
||||||
(when (and type path)
|
|
||||||
(cons type path))))
|
|
||||||
|
|
||||||
;;;; Title/Path/Slug conversion
|
;;;; Title/Path/Slug conversion
|
||||||
(defun org-roam--path-to-slug (path)
|
(defun org-roam--path-to-slug (path)
|
||||||
@ -802,19 +817,14 @@ backlinks."
|
|||||||
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
|
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
|
||||||
(downcase slug))))
|
(downcase slug))))
|
||||||
|
|
||||||
(defun org-roam--format-link-title (title &optional type)
|
(defun org-roam-format-link (target &optional description type link-type)
|
||||||
"Return the link title, given the file TITLE.
|
|
||||||
If `org-roam-link-title-format title' is defined, use it with TYPE."
|
|
||||||
(if (functionp org-roam-link-title-format)
|
|
||||||
(funcall org-roam-link-title-format title type)
|
|
||||||
(format org-roam-link-title-format title)))
|
|
||||||
|
|
||||||
(defun org-roam-format-link (target &optional description type)
|
|
||||||
"Formats an org link for a given file TARGET, link DESCRIPTION and link TYPE.
|
"Formats an org link for a given file TARGET, link DESCRIPTION and link TYPE.
|
||||||
TYPE defaults to \"file\".
|
TYPE defaults to \"file\". LINK-TYPE is the type of file link to
|
||||||
Here, we also check if there is an ID for the file."
|
be generated. Here, we also check if there is an ID for the
|
||||||
|
file."
|
||||||
(setq type (or type "file"))
|
(setq type (or type "file"))
|
||||||
(when-let ((id (and (string-equal type "file")
|
(when-let ((id (and org-roam-prefer-id-links
|
||||||
|
(string-equal type "file")
|
||||||
(caar (org-roam-db-query [:select [id] :from ids
|
(caar (org-roam-db-query [:select [id] :from ids
|
||||||
:where (= file $s1)
|
:where (= file $s1)
|
||||||
:and (= level 0)
|
:and (= level 0)
|
||||||
@ -822,7 +832,11 @@ Here, we also check if there is an ID for the file."
|
|||||||
target)))))
|
target)))))
|
||||||
(setq type "id" target id))
|
(setq type "id" target id))
|
||||||
(when (string-equal type "file")
|
(when (string-equal type "file")
|
||||||
(setq target (org-roam-link-get-path target)))
|
(setq target (org-roam-link-get-path target link-type)))
|
||||||
|
(setq description
|
||||||
|
(if (functionp org-roam-link-title-format)
|
||||||
|
(funcall org-roam-link-title-format description type)
|
||||||
|
(format org-roam-link-title-format description)))
|
||||||
(org-link-make-string (concat type ":" target) description))
|
(org-link-make-string (concat type ":" target) description))
|
||||||
|
|
||||||
(defun org-roam--prepend-tag-string (str tags)
|
(defun org-roam--prepend-tag-string (str tags)
|
||||||
@ -870,6 +884,26 @@ whose title is 'Index'."
|
|||||||
(concat (expand-file-name org-roam-directory) path)
|
(concat (expand-file-name org-roam-directory) path)
|
||||||
index)))
|
index)))
|
||||||
|
|
||||||
|
;;;; dealing with file-wide properties
|
||||||
|
(defun org-roam--set-global-prop (name value)
|
||||||
|
"Set a file property called NAME to VALUE.
|
||||||
|
|
||||||
|
If the property is already set, it's value is replaced."
|
||||||
|
(save-excursion
|
||||||
|
(widen)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(if (re-search-forward (concat "^#\\+" name ": \\(.*\\)") (point-max) t)
|
||||||
|
(replace-match (concat "#+" name ": " value) 'fixedcase)
|
||||||
|
(while (and (not (eobp))
|
||||||
|
(looking-at "^[#:]"))
|
||||||
|
(if (save-excursion (end-of-line) (eobp))
|
||||||
|
(progn
|
||||||
|
(end-of-line)
|
||||||
|
(insert "\n"))
|
||||||
|
(forward-line)
|
||||||
|
(beginning-of-line)))
|
||||||
|
(insert "#+" name ": " value "\n"))))
|
||||||
|
|
||||||
;;;; org-roam-find-ref
|
;;;; org-roam-find-ref
|
||||||
(defun org-roam--get-ref-path-completions (&optional arg filter)
|
(defun org-roam--get-ref-path-completions (&optional arg filter)
|
||||||
"Return an alist of refs to absolute path of Org-roam files.
|
"Return an alist of refs to absolute path of Org-roam files.
|
||||||
@ -973,24 +1007,18 @@ Return nil if the file does not exist."
|
|||||||
(and (boundp org-roam-backlinks-mode)
|
(and (boundp org-roam-backlinks-mode)
|
||||||
org-roam-backlinks-mode))
|
org-roam-backlinks-mode))
|
||||||
|
|
||||||
(defun org-roam--retrieve-link-destination (&optional pom)
|
|
||||||
"Retrieve the destination of the link at POM.
|
|
||||||
The point-or-marker POM can either be a position in the current
|
|
||||||
buffer or a marker."
|
|
||||||
(let ((pom (or pom (point))))
|
|
||||||
(org-with-point-at pom
|
|
||||||
(let* ((context (org-element-context))
|
|
||||||
(type (org-element-property :type context))
|
|
||||||
(dest (org-element-property :path context)))
|
|
||||||
(pcase type
|
|
||||||
("id" (car (org-roam-id-find dest)))
|
|
||||||
(_ dest))))))
|
|
||||||
|
|
||||||
(defun org-roam--backlink-to-current-p ()
|
(defun org-roam--backlink-to-current-p ()
|
||||||
"Return t if backlink is to the current Org-roam file."
|
"Return t if the link at point is to the current Org-roam file."
|
||||||
(let ((current (buffer-file-name org-roam-buffer--current))
|
(save-match-data
|
||||||
(backlink-dest (org-roam--retrieve-link-destination)))
|
(let ((current-file (buffer-file-name org-roam-buffer--current))
|
||||||
(string= current backlink-dest)))
|
(backlink-dest (save-excursion
|
||||||
|
(let* ((context (org-element-context))
|
||||||
|
(type (org-element-property :type context))
|
||||||
|
(dest (org-element-property :path context)))
|
||||||
|
(pcase type
|
||||||
|
("id" (org-roam-id-get-file dest))
|
||||||
|
(_ dest))))))
|
||||||
|
(string= current-file backlink-dest))))
|
||||||
|
|
||||||
(defun org-roam-open-at-point ()
|
(defun org-roam-open-at-point ()
|
||||||
"Open an Org-roam link or visit the text previewed at point.
|
"Open an Org-roam link or visit the text previewed at point.
|
||||||
@ -1025,20 +1053,27 @@ citation key, for Org-ref cite links."
|
|||||||
(unless (listp targets)
|
(unless (listp targets)
|
||||||
(setq targets (list targets)))
|
(setq targets (list targets)))
|
||||||
(let ((conditions (--> targets
|
(let ((conditions (--> targets
|
||||||
(mapcar (lambda (i) (list '= 'to i)) it)
|
(mapcar (lambda (i) (list '= 'dest i)) it)
|
||||||
(org-roam--list-interleave it :or))))
|
(org-roam--list-interleave it :or))))
|
||||||
(org-roam-db-query `[:select [from to properties] :from links
|
(org-roam-db-query `[:select [source dest properties] :from links
|
||||||
:where ,@conditions
|
:where ,@conditions
|
||||||
:order-by (asc from)])))
|
:order-by (asc source)])))
|
||||||
|
|
||||||
(defun org-roam-id-get-file (id)
|
(defun org-roam-id-get-file (id &optional strict)
|
||||||
"Return the file if ID exists in the Org-roam database.
|
"Return the file if ID exists.
|
||||||
|
When STRICT is non-nil, only consider Org-roam's database.
|
||||||
Return nil otherwise."
|
Return nil otherwise."
|
||||||
(caar (org-roam-db-query [:select [file]
|
(or (caar (org-roam-db-query [:select [file]
|
||||||
:from ids
|
:from ids
|
||||||
:where (= id $s1)
|
:where (= id $s1)
|
||||||
:limit 1]
|
:limit 1]
|
||||||
id)))
|
id))
|
||||||
|
(and (not strict)
|
||||||
|
(progn
|
||||||
|
(unless org-id-locations (org-id-locations-load))
|
||||||
|
(or (and org-id-locations
|
||||||
|
(hash-table-p org-id-locations)
|
||||||
|
(gethash id org-id-locations)))))))
|
||||||
|
|
||||||
(defun org-roam-id-find (id &optional markerp strict keep-buffer-p)
|
(defun org-roam-id-find (id &optional markerp strict keep-buffer-p)
|
||||||
"Return the location of the entry with the id ID.
|
"Return the location of the entry with the id ID.
|
||||||
@ -1046,8 +1081,7 @@ When MARKERP is non-nil, return a marker pointing to the headline.
|
|||||||
Otherwise, return a cons formatted as \(file . pos).
|
Otherwise, return a cons formatted as \(file . pos).
|
||||||
When STRICT is non-nil, only consider Org-roam’s database.
|
When STRICT is non-nil, only consider Org-roam’s database.
|
||||||
When KEEP-BUFFER-P is non-nil, keep the buffers navigated by Org-roam open."
|
When KEEP-BUFFER-P is non-nil, keep the buffers navigated by Org-roam open."
|
||||||
(let ((file (or (org-roam-id-get-file id)
|
(let ((file (org-roam-id-get-file id strict)))
|
||||||
(unless strict (org-id-find-id-file id)))))
|
|
||||||
(when file
|
(when file
|
||||||
(let ((existing-buf (find-buffer-visiting file))
|
(let ((existing-buf (find-buffer-visiting file))
|
||||||
(res (org-id-find-id-in-file id file markerp)))
|
(res (org-id-find-id-in-file id file markerp)))
|
||||||
@ -1068,6 +1102,7 @@ When STRICT is non-nil, only consider Org-roam’s database."
|
|||||||
(when-let ((marker (if (markerp id-or-marker)
|
(when-let ((marker (if (markerp id-or-marker)
|
||||||
id-or-marker
|
id-or-marker
|
||||||
(org-roam-id-find id-or-marker t strict t))))
|
(org-roam-id-find id-or-marker t strict t))))
|
||||||
|
(org-mark-ring-push)
|
||||||
(org-goto-marker-or-bmk marker)
|
(org-goto-marker-or-bmk marker)
|
||||||
(set-marker marker nil)))
|
(set-marker marker nil)))
|
||||||
|
|
||||||
@ -1170,7 +1205,7 @@ This is active when `org-roam-completion-everywhere' is non-nil."
|
|||||||
;;;; Function Faces
|
;;;; Function Faces
|
||||||
;; These faces are used by `org-link-set-parameters', which take one argument,
|
;; These faces are used by `org-link-set-parameters', which take one argument,
|
||||||
;; which is the path.
|
;; which is the path.
|
||||||
(defcustom org-roam-link-use-custom-faces 'everywhere
|
(defcustom org-roam-link-use-custom-faces t
|
||||||
"Define where to apply custom faces to Org-roam links.
|
"Define where to apply custom faces to Org-roam links.
|
||||||
|
|
||||||
Valide values are:
|
Valide values are:
|
||||||
@ -1182,9 +1217,9 @@ everywhere Apply custom faces everywhere.
|
|||||||
|
|
||||||
Otherwise, do not apply custom faces to Org-roam links."
|
Otherwise, do not apply custom faces to Org-roam links."
|
||||||
:type '(choice
|
:type '(choice
|
||||||
(const :tag "Use custom faces inside Org-roam notes" t)
|
(const :tag "Use custom faces inside Org-roam notes" t)
|
||||||
(const :tag "Apply custom faces everywhere" everywhere)
|
(const :tag "Apply custom faces everywhere" everywhere)
|
||||||
(const :tag "Do not apply custom faces" nil))
|
(const :tag "Do not apply custom faces" nil))
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
(defun org-roam--file-link-face (path)
|
(defun org-roam--file-link-face (path)
|
||||||
@ -1222,35 +1257,18 @@ file."
|
|||||||
(org-roam--org-roam-file-p)))
|
(org-roam--org-roam-file-p)))
|
||||||
(custom (or (and in-note org-roam-link-use-custom-faces)
|
(custom (or (and in-note org-roam-link-use-custom-faces)
|
||||||
(eq org-roam-link-use-custom-faces 'everywhere))))
|
(eq org-roam-link-use-custom-faces 'everywhere))))
|
||||||
(cond ((and custom
|
(cond ((and (org-roam--in-buffer-p)
|
||||||
(not (org-roam-id-get-file id)))
|
|
||||||
'org-roam-link-invalid)
|
|
||||||
((and (org-roam--in-buffer-p)
|
|
||||||
(org-roam--backlink-to-current-p))
|
(org-roam--backlink-to-current-p))
|
||||||
'org-roam-link-current)
|
'org-roam-link-current)
|
||||||
((and custom
|
((and custom
|
||||||
(org-roam-id-get-file id))
|
(org-roam-id-get-file id t))
|
||||||
'org-roam-link)
|
'org-roam-link)
|
||||||
|
((and custom
|
||||||
|
(not (org-roam-id-get-file id)))
|
||||||
|
'org-roam-link-invalid)
|
||||||
(t
|
(t
|
||||||
'org-link)))))
|
'org-link)))))
|
||||||
|
|
||||||
(defun org-roam--queue-file-for-update (&optional file-path)
|
|
||||||
"Queue FILE-PATH for `org-roam' database update.
|
|
||||||
This is a lightweight function that is called during `after-save-hook'
|
|
||||||
and only schedules the current Org file to be `org-roam' updated
|
|
||||||
during the next idle slot."
|
|
||||||
(let ((fp (or file-path buffer-file-name)))
|
|
||||||
(when (org-roam--org-roam-file-p file-path)
|
|
||||||
(add-to-list 'org-roam--file-update-queue fp))))
|
|
||||||
|
|
||||||
(defun org-roam--process-update-queue ()
|
|
||||||
"Process files queued in `org-roam--file-update-queue'."
|
|
||||||
(when org-roam--file-update-queue
|
|
||||||
(mapc #'org-roam-db--update-file org-roam--file-update-queue)
|
|
||||||
(org-roam-message "database updated during idle: %s."
|
|
||||||
(mapconcat #'file-name-nondirectory org-roam--file-update-queue ", ") )
|
|
||||||
(setq org-roam--file-update-queue nil)))
|
|
||||||
|
|
||||||
;;;; Hooks and Advices
|
;;;; Hooks and Advices
|
||||||
(defcustom org-roam-file-setup-hook nil
|
(defcustom org-roam-file-setup-hook nil
|
||||||
"Hook that is run on setting up an Org-roam file."
|
"Hook that is run on setting up an Org-roam file."
|
||||||
@ -1265,7 +1283,7 @@ during the next idle slot."
|
|||||||
(org-roam--setup-title-auto-update)
|
(org-roam--setup-title-auto-update)
|
||||||
(add-hook 'post-command-hook #'org-roam-buffer--update-maybe nil t)
|
(add-hook 'post-command-hook #'org-roam-buffer--update-maybe nil t)
|
||||||
(add-hook 'before-save-hook #'org-roam-link--replace-link-on-save nil t)
|
(add-hook 'before-save-hook #'org-roam-link--replace-link-on-save nil t)
|
||||||
(add-hook 'after-save-hook #'org-roam--queue-file-for-update nil t)
|
(add-hook 'after-save-hook #'org-roam-db-update nil t)
|
||||||
(dolist (fn org-roam-completion-functions)
|
(dolist (fn org-roam-completion-functions)
|
||||||
(add-hook 'completion-at-point-functions fn nil t))
|
(add-hook 'completion-at-point-functions fn nil t))
|
||||||
(org-roam-buffer--update-maybe :redisplay t)))
|
(org-roam-buffer--update-maybe :redisplay t)))
|
||||||
@ -1276,44 +1294,51 @@ during the next idle slot."
|
|||||||
(org-roam--org-roam-file-p file))
|
(org-roam--org-roam-file-p file))
|
||||||
(org-roam-db--clear-file (expand-file-name file))))
|
(org-roam-db--clear-file (expand-file-name file))))
|
||||||
|
|
||||||
|
(defun org-roam--get-link-replacement (old-path new-path &optional old-desc new-desc)
|
||||||
|
"Create replacement text for link at point if OLD-PATH is a match.
|
||||||
|
Will update link to NEW-PATH. If OLD-DESC is set, and is not the
|
||||||
|
same as the link description, it is assumed that the user has
|
||||||
|
modified the description, and the description will not be
|
||||||
|
updated. Else, update with NEW-DESC."
|
||||||
|
(let (type path link-type label new-label)
|
||||||
|
(when-let ((link (org-element-lineage (org-element-context) '(link) t)))
|
||||||
|
(setq type (org-element-property :type link)
|
||||||
|
path (org-element-property :path link))
|
||||||
|
(when (and (string-equal (expand-file-name path) old-path)
|
||||||
|
(org-in-regexp org-link-bracket-re 1))
|
||||||
|
(setq link-type (when (file-name-absolute-p path) 'absolute)
|
||||||
|
label (if (match-end 2)
|
||||||
|
(match-string-no-properties 2)
|
||||||
|
(org-link-unescape (match-string-no-properties 1))))
|
||||||
|
(setq new-label (if (string-equal label old-desc) new-desc label))
|
||||||
|
(org-roam-format-link new-path new-label type link-type)))))
|
||||||
|
|
||||||
(defun org-roam--replace-link (old-path new-path &optional old-desc new-desc)
|
(defun org-roam--replace-link (old-path new-path &optional old-desc new-desc)
|
||||||
"Replace Org-roam file links with path OLD-PATH to path NEW-PATH.
|
"Replace Org-roam file links with path OLD-PATH to path NEW-PATH.
|
||||||
If OLD-DESC is passed, and is not the same as the link
|
If OLD-DESC is passed, and is not the same as the link
|
||||||
description, it is assumed that the user has modified the
|
description, it is assumed that the user has modified the
|
||||||
description, and the description will not be updated. Else,
|
description, and the description will not be updated. Else,
|
||||||
update with NEW-DESC."
|
update with NEW-DESC."
|
||||||
(save-excursion
|
(org-with-point-at 1
|
||||||
(goto-char (point-min))
|
(while (re-search-forward org-link-bracket-re nil t)
|
||||||
(while (re-search-forward org-link-any-re nil t)
|
(when-let ((link (save-match-data (org-roam--get-link-replacement old-path new-path old-desc new-desc))))
|
||||||
(when-let ((link (org-element-lineage (org-element-context) '(link) t)))
|
(replace-match link)))))
|
||||||
(let ((type (org-element-property :type link))
|
|
||||||
(path (org-element-property :path link)))
|
|
||||||
(when (and (string-equal (expand-file-name path) old-path)
|
|
||||||
(org-in-regexp org-link-bracket-re 1))
|
|
||||||
(let* ((label (if (match-end 2)
|
|
||||||
(match-string-no-properties 2)
|
|
||||||
(org-link-unescape (match-string-no-properties 1))))
|
|
||||||
(new-label (if (string-equal label old-desc)
|
|
||||||
new-desc
|
|
||||||
label)))
|
|
||||||
(replace-match (org-roam-format-link new-path new-label type)))))))))
|
|
||||||
|
|
||||||
(defun org-roam--fix-relative-links (old-path)
|
(defun org-roam--fix-relative-links (old-path)
|
||||||
"Fix file-relative links in current buffer.
|
"Fix file-relative links in current buffer.
|
||||||
File relative links are assumed to originate from OLD-PATH. The
|
File relative links are assumed to originate from OLD-PATH. The
|
||||||
replaced links are made relative to the current buffer."
|
replaced links are made relative to the current buffer."
|
||||||
(save-excursion
|
(org-with-point-at 1
|
||||||
(goto-char (point-min))
|
(let (link new-link type path)
|
||||||
(while (re-search-forward org-link-any-re nil t)
|
(while (re-search-forward org-link-bracket-re nil t)
|
||||||
(when-let ((link (org-element-lineage (org-element-context) '(link) t)))
|
(when (setq link (save-match-data (org-element-lineage (org-element-context) '(link) t)))
|
||||||
(let ((type (org-element-property :type link))
|
(setq type (org-element-property :type link))
|
||||||
(path (org-element-property :path link)))
|
(setq path (org-element-property :path link))
|
||||||
(when (and (f-relative-p path)
|
(when (and (string= type "file")
|
||||||
(org-in-regexp org-link-bracket-re 1))
|
(f-relative-p path))
|
||||||
(let* ((file-path (expand-file-name path (file-name-directory old-path)))
|
(setq new-link
|
||||||
(new-path (org-roam-link-get-path file-path)))
|
(concat type ":" (org-roam-link-get-path (expand-file-name path (file-name-directory old-path)))))
|
||||||
(replace-match (concat type ":" new-path)
|
(replace-match new-link nil t nil 1)))))))
|
||||||
nil t nil 1))))))))
|
|
||||||
|
|
||||||
(defcustom org-roam-rename-file-on-title-change t
|
(defcustom org-roam-rename-file-on-title-change t
|
||||||
"If non-nil, alter the filename on title change.
|
"If non-nil, alter the filename on title change.
|
||||||
@ -1356,9 +1381,9 @@ if applicable.
|
|||||||
|
|
||||||
To be added to `org-roam-title-change-hook'."
|
To be added to `org-roam-title-change-hook'."
|
||||||
(let* ((current-path (buffer-file-name))
|
(let* ((current-path (buffer-file-name))
|
||||||
(files-affected (org-roam-db-query [:select :distinct [from]
|
(files-affected (org-roam-db-query [:select :distinct [source]
|
||||||
:from links
|
:from links
|
||||||
:where (= to $s1)]
|
:where (= dest $s1)]
|
||||||
current-path)))
|
current-path)))
|
||||||
(dolist (file files-affected)
|
(dolist (file files-affected)
|
||||||
(with-current-buffer (or (find-buffer-visiting (car file))
|
(with-current-buffer (or (find-buffer-visiting (car file))
|
||||||
@ -1381,10 +1406,11 @@ To be added to `org-roam-title-change-hook'."
|
|||||||
(when (string-match-p old-slug file-name)
|
(when (string-match-p old-slug file-name)
|
||||||
(let* ((new-slug (funcall org-roam-title-to-slug-function new-title))
|
(let* ((new-slug (funcall org-roam-title-to-slug-function new-title))
|
||||||
(new-file-name (replace-regexp-in-string old-slug new-slug file-name)))
|
(new-file-name (replace-regexp-in-string old-slug new-slug file-name)))
|
||||||
(rename-file file-name new-file-name)
|
(unless (string-match-p file-name new-file-name)
|
||||||
(set-visited-file-name new-file-name t t)
|
(rename-file file-name new-file-name)
|
||||||
(add-to-list 'org-roam--file-update-queue new-file-name)
|
(set-visited-file-name new-file-name t t)
|
||||||
(org-roam-message "File moved to %S" (abbreviate-file-name new-file-name)))))))
|
(org-roam-db-update)
|
||||||
|
(org-roam-message "File moved to %S" (abbreviate-file-name new-file-name))))))))
|
||||||
|
|
||||||
(defun org-roam--rename-file-advice (old-file new-file-or-dir &rest _args)
|
(defun org-roam--rename-file-advice (old-file new-file-or-dir &rest _args)
|
||||||
"Rename backlinks of OLD-FILE to refer to NEW-FILE-OR-DIR.
|
"Rename backlinks of OLD-FILE to refer to NEW-FILE-OR-DIR.
|
||||||
@ -1398,42 +1424,40 @@ When NEW-FILE-OR-DIR is a directory, we use it to compute the new file path."
|
|||||||
(not (backup-file-name-p new-file))
|
(not (backup-file-name-p new-file))
|
||||||
(org-roam--org-roam-file-p old-file))
|
(org-roam--org-roam-file-p old-file))
|
||||||
(org-roam-db--ensure-built)
|
(org-roam-db--ensure-built)
|
||||||
(let* ((old-path (expand-file-name old-file))
|
(let* ((new-buffer (or (find-buffer-visiting new-file)
|
||||||
(new-path (expand-file-name new-file))
|
(find-file-noselect new-file)))
|
||||||
(new-buffer (or (find-buffer-visiting new-path)
|
(files-affected (org-roam-db-query [:select :distinct [source]
|
||||||
(find-file-noselect new-path)))
|
|
||||||
(files-affected (org-roam-db-query [:select :distinct [from]
|
|
||||||
:from links
|
:from links
|
||||||
:where (= to $s1)]
|
:where (= dest $s1)]
|
||||||
old-path)))
|
old-file)))
|
||||||
;; Remove database entries for old-file.org
|
;; Remove database entries for old-file.org
|
||||||
(org-roam-db--clear-file old-file)
|
(org-roam-db--clear-file old-file)
|
||||||
;; Replace links from old-file.org -> new-file.org in all Org-roam files with these links
|
;; Replace links from old-file.org -> new-file.org in all Org-roam files with these links
|
||||||
(mapc (lambda (file)
|
(mapc (lambda (file)
|
||||||
(setq file (if (string-equal (expand-file-name (car file)) old-path)
|
(setq file (if (string-equal (car file) old-file)
|
||||||
new-path
|
new-file
|
||||||
(car file)))
|
(car file)))
|
||||||
(with-current-buffer (or (find-buffer-visiting file)
|
(with-current-buffer (or (find-buffer-visiting file)
|
||||||
(find-file-noselect file))
|
(find-file-noselect file))
|
||||||
(org-roam--replace-link old-path new-path)
|
(org-roam--replace-link old-file new-file)
|
||||||
(save-buffer)
|
(save-buffer)
|
||||||
(org-roam-db--update-file)))
|
(org-roam-db--update-file)))
|
||||||
files-affected)
|
files-affected)
|
||||||
;; If the new path is in a different directory, relative links
|
;; If the new path is in a different directory, relative links
|
||||||
;; will break. Fix all file-relative links:
|
;; will break. Fix all file-relative links:
|
||||||
(unless (string= (file-name-directory old-path)
|
(unless (string= (file-name-directory old-file)
|
||||||
(file-name-directory new-path))
|
(file-name-directory new-file))
|
||||||
(with-current-buffer new-buffer
|
(with-current-buffer new-buffer
|
||||||
(org-roam--fix-relative-links old-path)
|
(org-roam--fix-relative-links old-file)
|
||||||
(save-buffer)))
|
(save-buffer)))
|
||||||
(when (org-roam--org-roam-file-p new-file)
|
(when (org-roam--org-roam-file-p new-file)
|
||||||
(org-roam-db--update-file new-path))))))
|
(org-roam-db--update-file new-file))))))
|
||||||
|
|
||||||
(defun org-roam--id-new-advice (&rest _args)
|
(defun org-roam--id-new-advice (&rest _args)
|
||||||
"Update the database if a new Org ID is created."
|
"Update the database if a new Org ID is created."
|
||||||
(when (and org-roam-enable-headline-linking
|
(when (and org-roam-enable-headline-linking
|
||||||
(org-roam--org-roam-file-p))
|
(org-roam--org-roam-file-p))
|
||||||
(add-to-list 'org-roam--file-update-queue (buffer-file-name))))
|
(org-roam-db-update)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(define-minor-mode org-roam-mode
|
(define-minor-mode org-roam-mode
|
||||||
@ -1468,8 +1492,9 @@ M-x info for more information at Org-roam > Installation > Post-Installation Tas
|
|||||||
(add-hook 'find-file-hook #'org-roam--find-file-hook-function)
|
(add-hook 'find-file-hook #'org-roam--find-file-hook-function)
|
||||||
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
||||||
(add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point)
|
(add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point)
|
||||||
(unless org-roam--file-update-timer
|
(if (and org-roam-db-file-update-timer
|
||||||
(setq org-roam--file-update-timer (run-with-idle-timer org-roam-update-db-idle-seconds t #'org-roam--process-update-queue)))
|
(eq org-roam-db-update-method 'idle-timer))
|
||||||
|
(setq org-roam-db-file-update-timer (run-with-idle-timer org-roam-db-update-idle-seconds t #'org-roam-db-update-cache-on-timer)))
|
||||||
(advice-add 'rename-file :after #'org-roam--rename-file-advice)
|
(advice-add 'rename-file :after #'org-roam--rename-file-advice)
|
||||||
(advice-add 'delete-file :before #'org-roam--delete-file-advice)
|
(advice-add 'delete-file :before #'org-roam--delete-file-advice)
|
||||||
(advice-add 'org-id-new :after #'org-roam--id-new-advice)
|
(advice-add 'org-id-new :after #'org-roam--id-new-advice)
|
||||||
@ -1482,8 +1507,8 @@ M-x info for more information at Org-roam > Installation > Post-Installation Tas
|
|||||||
(remove-hook 'find-file-hook #'org-roam--find-file-hook-function)
|
(remove-hook 'find-file-hook #'org-roam--find-file-hook-function)
|
||||||
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
||||||
(remove-hook 'org-open-at-point-functions #'org-roam-open-id-at-point)
|
(remove-hook 'org-open-at-point-functions #'org-roam-open-id-at-point)
|
||||||
(when org-roam--file-update-timer
|
(when org-roam-db-file-update-timer
|
||||||
(cancel-timer org-roam--file-update-timer))
|
(cancel-timer org-roam-db-file-update-timer))
|
||||||
(advice-remove 'rename-file #'org-roam--rename-file-advice)
|
(advice-remove 'rename-file #'org-roam--rename-file-advice)
|
||||||
(advice-remove 'delete-file #'org-roam--delete-file-advice)
|
(advice-remove 'delete-file #'org-roam--delete-file-advice)
|
||||||
(advice-remove 'org-id-new #'org-roam--id-new-advice)
|
(advice-remove 'org-id-new #'org-roam--id-new-advice)
|
||||||
@ -1496,7 +1521,7 @@ M-x info for more information at Org-roam > Installation > Post-Installation Tas
|
|||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(remove-hook 'post-command-hook #'org-roam-buffer--update-maybe t)
|
(remove-hook 'post-command-hook #'org-roam-buffer--update-maybe t)
|
||||||
(remove-hook 'before-save-hook #'org-roam-link--replace-link-on-save t)
|
(remove-hook 'before-save-hook #'org-roam-link--replace-link-on-save t)
|
||||||
(remove-hook 'after-save-hook #'org-roam--queue-file-for-update t))))))
|
(remove-hook 'after-save-hook #'org-roam-db-update t))))))
|
||||||
|
|
||||||
;;; Interactive Commands
|
;;; Interactive Commands
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
@ -1584,8 +1609,8 @@ included as a candidate."
|
|||||||
(defun org-roam-insert (&optional lowercase completions filter-fn description link-type)
|
(defun org-roam-insert (&optional lowercase completions filter-fn description link-type)
|
||||||
"Find an Org-roam file, and insert a relative org link to it at point.
|
"Find an Org-roam file, and insert a relative org link to it at point.
|
||||||
Return selected file if it exists.
|
Return selected file if it exists.
|
||||||
|
If LOWERCASE is non-nil, downcase the link description.
|
||||||
LINK-TYPE is the type of link to be created. It defaults to \"file\".
|
LINK-TYPE is the type of link to be created. It defaults to \"file\".
|
||||||
If LOWERCASE, downcase the title before insertion.
|
|
||||||
COMPLETIONS is a list of completions to be used instead of
|
COMPLETIONS is a list of completions to be used instead of
|
||||||
`org-roam--get-title-path-completions`.
|
`org-roam--get-title-path-completions`.
|
||||||
FILTER-FN is the name of a function to apply on the candidates
|
FILTER-FN is the name of a function to apply on the candidates
|
||||||
@ -1616,17 +1641,16 @@ If DESCRIPTION is provided, use this as the link label. See
|
|||||||
title-with-tags))
|
title-with-tags))
|
||||||
(target-file-path (plist-get res :path))
|
(target-file-path (plist-get res :path))
|
||||||
(description (or description region-text title))
|
(description (or description region-text title))
|
||||||
(link-description (org-roam--format-link-title (if lowercase
|
(description (if lowercase
|
||||||
(downcase description)
|
(downcase description)
|
||||||
description)
|
description)))
|
||||||
link-type)))
|
|
||||||
(cond ((and target-file-path
|
(cond ((and target-file-path
|
||||||
(file-exists-p target-file-path))
|
(file-exists-p target-file-path))
|
||||||
(when region-text
|
(when region-text
|
||||||
(delete-region beg end)
|
(delete-region beg end)
|
||||||
(set-marker beg nil)
|
(set-marker beg nil)
|
||||||
(set-marker end nil))
|
(set-marker end nil))
|
||||||
(insert (org-roam-format-link target-file-path link-description link-type)))
|
(insert (org-roam-format-link target-file-path description link-type)))
|
||||||
(t
|
(t
|
||||||
(let ((org-roam-capture--info `((title . ,title-with-tags)
|
(let ((org-roam-capture--info `((title . ,title-with-tags)
|
||||||
(slug . ,(funcall org-roam-title-to-slug-function title-with-tags))))
|
(slug . ,(funcall org-roam-title-to-slug-function title-with-tags))))
|
||||||
@ -1634,7 +1658,7 @@ If DESCRIPTION is provided, use this as the link label. See
|
|||||||
(setq org-roam-capture-additional-template-props (list :region (org-roam-shield-region beg end)
|
(setq org-roam-capture-additional-template-props (list :region (org-roam-shield-region beg end)
|
||||||
:insert-at (point-marker)
|
:insert-at (point-marker)
|
||||||
:link-type link-type
|
:link-type link-type
|
||||||
:link-description link-description
|
:link-description description
|
||||||
:finalize 'insert-link))
|
:finalize 'insert-link))
|
||||||
(org-roam-capture--capture))))
|
(org-roam-capture--capture))))
|
||||||
res))
|
res))
|
||||||
@ -1680,6 +1704,68 @@ command will offer you to create one."
|
|||||||
(when (y-or-n-p "Index file does not exist. Would you like to create it? ")
|
(when (y-or-n-p "Index file does not exist. Would you like to create it? ")
|
||||||
(org-roam-find-file "Index")))))
|
(org-roam-find-file "Index")))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun org-roam-alias-add ()
|
||||||
|
"Add an alias to Org-roam file.
|
||||||
|
|
||||||
|
Return added alias."
|
||||||
|
(interactive)
|
||||||
|
(unless org-roam-mode (org-roam-mode))
|
||||||
|
(let ((alias (read-string "Alias: " )))
|
||||||
|
(when (string-empty-p alias)
|
||||||
|
(user-error "Alias can't be empty"))
|
||||||
|
(org-roam--set-global-prop
|
||||||
|
"ROAM_ALIAS"
|
||||||
|
(combine-and-quote-strings
|
||||||
|
(seq-uniq (cons alias
|
||||||
|
(org-roam--extract-titles-alias)))))
|
||||||
|
(org-roam-db--update-file (buffer-file-name (buffer-base-buffer)))
|
||||||
|
alias))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun org-roam-alias-delete ()
|
||||||
|
"Delete an alias from Org-roam file."
|
||||||
|
(interactive)
|
||||||
|
(unless org-roam-mode (org-roam-mode))
|
||||||
|
(if-let ((aliases (org-roam--extract-titles-alias)))
|
||||||
|
(let ((alias (completing-read "Alias: " aliases nil 'require-match)))
|
||||||
|
(org-roam--set-global-prop
|
||||||
|
"ROAM_ALIAS"
|
||||||
|
(combine-and-quote-strings (delete alias aliases)))
|
||||||
|
(org-roam-db--update-file (buffer-file-name (buffer-base-buffer))))
|
||||||
|
(user-error "No aliases to delete")))
|
||||||
|
|
||||||
|
(defun org-roam-tag-add ()
|
||||||
|
"Add a tag to Org-roam file.
|
||||||
|
|
||||||
|
Return added tag."
|
||||||
|
(interactive)
|
||||||
|
(unless org-roam-mode (org-roam-mode))
|
||||||
|
(let* ((all-tags (org-roam-db--get-tags))
|
||||||
|
(tag (completing-read "Tag: " all-tags))
|
||||||
|
(file (buffer-file-name (buffer-base-buffer)))
|
||||||
|
(existing-tags (org-roam--extract-tags-prop file)))
|
||||||
|
(when (string-empty-p tag)
|
||||||
|
(user-error "Tag can't be empty"))
|
||||||
|
(org-roam--set-global-prop
|
||||||
|
"ROAM_TAGS"
|
||||||
|
(combine-and-quote-strings (seq-uniq (cons tag existing-tags))))
|
||||||
|
(org-roam-db--insert-tags 'update)
|
||||||
|
tag))
|
||||||
|
|
||||||
|
(defun org-roam-tag-delete ()
|
||||||
|
"Delete a tag from Org-roam file."
|
||||||
|
(interactive)
|
||||||
|
(unless org-roam-mode (org-roam-mode))
|
||||||
|
(if-let* ((file (buffer-file-name (buffer-base-buffer)))
|
||||||
|
(tags (org-roam--extract-tags-prop file)))
|
||||||
|
(let ((tag (completing-read "Tag: " tags nil 'require-match)))
|
||||||
|
(org-roam--set-global-prop
|
||||||
|
"ROAM_TAGS"
|
||||||
|
(combine-and-quote-strings (delete tag tags)))
|
||||||
|
(org-roam-db--insert-tags 'update))
|
||||||
|
(user-error "No tag to delete")))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-roam-switch-to-buffer ()
|
(defun org-roam-switch-to-buffer ()
|
||||||
"Switch to an existing Org-roam buffer."
|
"Switch to an existing Org-roam buffer."
|
||||||
@ -1719,12 +1805,17 @@ means that the results can be noisy, and may not truly indicate
|
|||||||
an unlinked reference.
|
an unlinked reference.
|
||||||
|
|
||||||
Users are encouraged to think hard about whether items should be
|
Users are encouraged to think hard about whether items should be
|
||||||
linked, lest the network graph get too crowded."
|
linked, lest the network graph get too crowded.
|
||||||
|
|
||||||
|
Requires a version of Ripgrep with PCRE2 support installed, with
|
||||||
|
the executable 'rg' in variable `exec-path'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless (org-roam--org-roam-file-p)
|
(unless (org-roam--org-roam-file-p)
|
||||||
(user-error "Not in org-roam file"))
|
(user-error "Not in org-roam file"))
|
||||||
(if (not (executable-find "rg"))
|
(if (not (executable-find "rg"))
|
||||||
(error "Cannot find the ripgrep executable \"rg\". Check that it is installed and available on `exec-path'")
|
(error "Cannot find the ripgrep executable \"rg\". Check that it is installed and available on `exec-path'")
|
||||||
|
(when (string-match "PCRE2 is not available" (shell-command-to-string "rg --pcre2-version"))
|
||||||
|
(error "\"rg\" must be compiled with PCRE2 support"))
|
||||||
(let* ((titles (org-roam--extract-titles))
|
(let* ((titles (org-roam--extract-titles))
|
||||||
(rg-command (concat "rg -o --vimgrep -P -i "
|
(rg-command (concat "rg -o --vimgrep -P -i "
|
||||||
(string-join (mapcar (lambda (glob) (concat "-g " glob))
|
(string-join (mapcar (lambda (glob) (concat "-g " glob))
|
||||||
@ -1771,7 +1862,9 @@ linked, lest the network graph get too crowded."
|
|||||||
(concat "sed -n "
|
(concat "sed -n "
|
||||||
row
|
row
|
||||||
"p "
|
"p "
|
||||||
file))))
|
"\""
|
||||||
|
file
|
||||||
|
"\""))))
|
||||||
(insert "\n")))))))
|
(insert "\n")))))))
|
||||||
(read-only-mode +1)
|
(read-only-mode +1)
|
||||||
(dolist (title titles)
|
(dolist (title titles)
|
||||||
|
1
tests/roam-files/cite_ref.org
Normal file
1
tests/roam-files/cite_ref.org
Normal file
@ -0,0 +1 @@
|
|||||||
|
#+roam_key: cite:mitsuha2007
|
2
tests/roam-files/multiple-refs.org
Normal file
2
tests/roam-files/multiple-refs.org
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#+roam_key: https://www.orgroam.com/
|
||||||
|
#+roam_key: cite:orgroam2020
|
@ -45,7 +45,7 @@
|
|||||||
(pcase (benchmark-run 1 (org-roam-db-build-cache t))
|
(pcase (benchmark-run 1 (org-roam-db-build-cache t))
|
||||||
(`(,time ,gcs ,time-in-gc)
|
(`(,time ,gcs ,time-in-gc)
|
||||||
(message "Elapsed time: %fs (%fs in %d GCs)" time time-in-gc gcs)
|
(message "Elapsed time: %fs (%fs in %d GCs)" time time-in-gc gcs)
|
||||||
(expect time :to-be-less-than 90))))
|
(expect time :to-be-less-than 110))))
|
||||||
(it "builds quickly without change"
|
(it "builds quickly without change"
|
||||||
(pcase (benchmark-run 1 (org-roam-db-build-cache))
|
(pcase (benchmark-run 1 (org-roam-db-build-cache))
|
||||||
(`(,time ,gcs ,time-in-gc)
|
(`(,time ,gcs ,time-in-gc)
|
||||||
|
@ -71,6 +71,40 @@
|
|||||||
(expect (org-roam--str-to-list "\"hello")
|
(expect (org-roam--str-to-list "\"hello")
|
||||||
:to-throw)))
|
:to-throw)))
|
||||||
|
|
||||||
|
(describe "Ref 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
|
||||||
|
;; Unlike tag extraction, it doesn't make sense to
|
||||||
|
;; pass a filename.
|
||||||
|
(funcall fn)))))
|
||||||
|
;; Enable "cite:" link parsing
|
||||||
|
(org-link-set-parameters "cite")
|
||||||
|
(it "extracts web keys"
|
||||||
|
(expect (test #'org-roam--extract-ref
|
||||||
|
"web_ref.org")
|
||||||
|
:to-equal
|
||||||
|
'("website" . "//google.com/")))
|
||||||
|
(it "extracts cite keys"
|
||||||
|
(expect (test #'org-roam--extract-ref
|
||||||
|
"cite_ref.org")
|
||||||
|
:to-equal
|
||||||
|
'("cite" . "mitsuha2007")))
|
||||||
|
(it "extracts all keys"
|
||||||
|
(expect (test #'org-roam--extract-refs
|
||||||
|
"multiple-refs.org")
|
||||||
|
:to-have-same-items-as
|
||||||
|
'(("cite" . "orgroam2020")
|
||||||
|
("website" . "//www.orgroam.com/"))))))
|
||||||
|
|
||||||
(describe "Title extraction"
|
(describe "Title extraction"
|
||||||
:var (org-roam-title-sources)
|
:var (org-roam-title-sources)
|
||||||
(before-all
|
(before-all
|
||||||
@ -300,21 +334,21 @@
|
|||||||
|
|
||||||
;; Links
|
;; Links
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||||
:where (= from $s1)]
|
:where (= source $s1)]
|
||||||
(test-org-roam--abs-path "foo.org"))) :to-be 1)
|
(test-org-roam--abs-path "foo.org"))) :to-be 1)
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||||
:where (= from $s1)]
|
:where (= source $s1)]
|
||||||
(test-org-roam--abs-path "nested/bar.org"))) :to-be 2)
|
(test-org-roam--abs-path "nested/bar.org"))) :to-be 2)
|
||||||
|
|
||||||
;; Links -- File-to
|
;; Links -- File-to
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||||
:where (= to $s1)]
|
:where (= dest $s1)]
|
||||||
(test-org-roam--abs-path "nested/foo.org"))) :to-be 1)
|
(test-org-roam--abs-path "nested/foo.org"))) :to-be 1)
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||||
:where (= to $s1)]
|
:where (= dest $s1)]
|
||||||
(test-org-roam--abs-path "nested/bar.org"))) :to-be 1)
|
(test-org-roam--abs-path "nested/bar.org"))) :to-be 1)
|
||||||
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
(expect (caar (org-roam-db-query [:select (funcall count) :from links
|
||||||
:where (= to $s1)]
|
:where (= dest $s1)]
|
||||||
(test-org-roam--abs-path "unlinked.org"))) :to-be 0)
|
(test-org-roam--abs-path "unlinked.org"))) :to-be 0)
|
||||||
;; TODO Test titles
|
;; TODO Test titles
|
||||||
(expect (org-roam-db-query [:select * :from titles])
|
(expect (org-roam-db-query [:select * :from titles])
|
||||||
|
Reference in New Issue
Block a user