Compare commits

...

27 Commits

Author SHA1 Message Date
Jethro Kuan
3782e88d50 (release): v2.2.1 (#2126) 2022-03-14 23:37:29 -07:00
lafirest
b4f14eebae (feat)capture: add org-roam-post-node-insert-hook (#2125)
* (feat): add org-roam-post-node-insert-hook

Co-authored-by: Jethro Kuan <jethrokuan95@gmail.com>
2022-03-14 23:24:55 -07:00
Jethro Kuan
cce6a05630 (fix)buffer: update defcustom for org-roam-mode-section-functions (#2124) 2022-03-13 09:04:55 -07:00
Jethro Kuan
cc3689f30f (feat)buffer: pass args to org-mode-section-functions (#2123)
* (feat)buffer: pass args to org-mode-section-functions

* update docs
2022-03-12 21:24:11 -08:00
Jeremy Friesen
b179a5a1a6 (feat)buffer: add unique option for org-roam-backlinks-section (#2121)
Prior to this commit, when we would render backlinks in the
`org-buffer`, we would render each reference.  This meant that if a
source file referenced the node 5 times, there would be 5 backlink
references in the `org-buffer` (one for each position of the reference).

With this change, we add a parameter that specifies that backlink
sources should be unique.  In the above example, that would mean instead
of 5 backlinks we'd see 1.  And, as a concession, we'd use the lowest
position (e.g. the first reference in the source).

Closes #2119
2022-03-12 13:12:03 -08:00
Jethro Kuan
9172001c11 (chore)readme: update link (#2120) 2022-03-11 21:49:24 -08:00
Ron Parker
c51cadfe25 (fix)core: fix broken shell-based file listing methods (#2118)
Change #2025 broke the `org-roam--shell-command-files` filter that
affects all of the `org-roam-list-files-command` methods except
`elisp`.  This causes `org-roam--list-files` to iterate through the
variants executing their commands via `org-roam--shell-command-files`
but to not see any output, until it finally lands upon `elisp` and
gets some results.

The issue is that "#'s-present?" was replaced by

  (or (null s) (string= "" s))

effectively negating the test and converting it to "#'s-blank?".

This addresses that by negating the current test.
2022-03-10 16:07:39 -08:00
Jethro Kuan
f6950a9820 (fix)capture: fill-template preserve whitespace content (#2117)
* (fix)capture: fill-template preserve whitespace content

Preserve the whitespace content given in the capture template, by
caching it and then appending it to the output template. For
Org-capture's purposes, we need to separately ensure that a newline is
present. Adds tests to the various helper functions to illustrate changes.

Addresses #2115
2022-03-10 09:46:53 -08:00
Jethro Kuan
feb9179c9f (docs): add docs for org-protocol (#2116) 2022-03-09 22:11:05 -08:00
PRESFIL
f50d6e7376 (fix): caching symlinked files (#2112)
* Revert "(fix): `org-roam-descendant-of-p` bug on Windows (#2089)"

This reverts commit 97a342fd3f.

Reason:

It seems that the `file-in-directory-p` function proposed in #2089 is provided only for
*physical directories*, does not work as we would like with *symlinked directories*.
It dereferences all the symlinks in its path, and previously seemed related paths
cease to be such.

Because of this, such notes are ignored and not indexed, although they
were indexed earlier.
2022-03-03 22:47:24 -08:00
Jethro Kuan
65ea325071 (fix): place cursor after inserted link for new nodes (#2109)
Special care is taken not to move the point if the original point is no
longer the same (i.e. the user moves the cursor after calling the
capture, but before finalizing it). Fixes #2108.
2022-02-27 12:50:45 -08:00
Jethro Kuan
62d311de22 (chore): org-map-entries -> org-map-region (#2107)
org-map-entries is affected by agenda, while org-map-region is not
2022-02-26 18:07:45 -08:00
lennonhill
c8a360afdd (fix)capture: don't update org-id-locations if file is unknown (#2103) 2022-02-24 09:11:20 -08:00
Jethro Kuan
cebe77135a (fix)capture: always ask before deleting capture (#2100) 2022-02-20 16:51:41 -08:00
Jethro Kuan
25d828c32e (chore): fix lints on master (#2099) 2022-02-20 13:14:58 -08:00
Jethro Kuan
fd97c80a26 (chore): pin eldev install to 10.3 (#2098) 2022-02-20 10:40:54 -08:00
bing
97a342fd3f (fix): org-roam-descendant-of-p bug on Windows (#2089)
On Windows, `file-truename` and `directory-file-name` downcase driver
label: "C:/" => "c:/", while `expand-file-name` keep the case
unchanged. If `org-roam-directory` use upper case driver label, `org-roam-descendant-of-p` will alway return `nil`. Fix by only using `file-truename` in the function.
2022-02-20 10:05:12 -08:00
Ingo Lohmar
d20480bb8d (fix)node: properly expand extraction file path (#2097)
Previously, the file-path of the new node in `org-roam-extract-subtree'
was incorrect in many circumstances.  Expanding w.r.t. the initial
prompt directory (ie, `org-roam-directory') fixes that
2022-02-19 19:12:53 -08:00
Noboru Ota
b163c900b8 (fix)capture: correctly update org-id-locations-file after capture (#2086) 2022-02-08 09:12:42 -08:00
Jethro Kuan
0432b00485 (fix)buffer: buffer-toggle: don't destroy window if org-roam-node-toggle reuses window (#2082)
* (fix)buffer: buffer-toggle: don't destroy buffer if reused

Closes #2077

* add changelog
2022-02-06 14:20:24 -08:00
Jeremy Friesen
ccfa97ec3a (feat): ensuring that :ref info capture in all cases (#2079)
Let's assume we're evaluating the following region:

```elisp
(org-roam-capture-
     :node (org-roam-node-create :title "Org Roam Homepage")
     :info '(:ref "https://orgroam.com")
     :props '(:immediate-finish nil))
```

Prior to this commit, if you did not require "org-roam-protocol" then
`org-roam-capture-` would ignore the `:info '(:ref
"https://orgroam.com")` parameter.  Once you required
"org-roam-protocol" then the callback hooks that process `:info`'s
`:ref` will fire regardless of whether it comes from org-roam-protocol.

After this commit, you no longer need to require "org-roam-protocol" to
ensure that you capture an `:info`'s `:ref`.

Why is this useful?  When I'm reading through my elfeed RSS feed, I want
to capture an article.  I could use the org-roam-protocol to do this,
but that seems a bit unnecessary given that I'm already in Emacs.

Closes org-roam/org-roam#2078
2022-02-06 11:17:16 -08:00
Jürgen Hötzel
86e102d990 (fix)dailies: prevent multiple "dailies/" subdir expansions (#2080) (#2080)
When dynamic binding `org-roam-directory` to the "dailies/"
subdirectory also bind `org-roam-dailies-directory` to "./" to prevent
invalid expansions in user-defined hook functions.

Fixes #2070
2022-02-06 11:16:33 -08:00
Jethro Kuan
eed1df90f5 (feat)id: add org-roam-id module (#2072) 2022-01-30 22:54:28 -08:00
Jethro Kuan
905564a7eb (docs)db: document "selecting deleted buffer" error (#2071) 2022-01-30 11:11:09 -08:00
Michael Eliachevitch
9f7a4a0b02 (feat): allow specifying template keys in remaining org-roam-dailies capture/goto commands (#2065)
This is an extension of PR #2028 [1] by @astery, where the `keys`
argument was added to `org-roam-dailies--capture` `org-roam-dailies-capture-today`.

I extended this argument to also be available in other built-in dailies
functions, as I didn't see any reason why not and it results in my opinion in
more consistent behaviour.

The rationale is the same as in #2028: Allow users to add keybindings (or in my
case hydras) to calls of org-roam-dailies functions with specific template keys,
thus circumventing the selection screen.

So far it seems to work for me. I have only one pet-peeve about
the interface, if the user starts adding keys to all their goto-functions, they
might add

      (org-roam-dailies-goto-date nil "<key>")

Then the key-string will be interpreted as the value for `prefer-future` and
since it's non-nil, there won't be an error.

[1] https://github.com/org-roam/org-roam/pull/2028
2022-01-29 14:07:19 -08:00
Jethro Kuan
aafe4114c2 (fix)node: make filter-fn for org-roam-node-random optional (#2063)
Also, make interactive argument actually apply for other-window
2022-01-25 21:54:06 -08:00
Álmos-Ágoston Zediu
3e2716edf3 (fix)node: added DOUBLE ACUTE ACCENT for unicode normalization (#2060) 2022-01-21 15:50:52 -08:00
22 changed files with 603 additions and 232 deletions

View File

@@ -4,6 +4,9 @@
(elisp-lint-ignored-validators . ("byte-compile" "package-lint"))
(elisp-lint-indent-specs . ((describe . 1)
(it . 1)
(thread-first . 0)
(cl-flet . 1)
(cl-flet* . 1)
(org-element-map . defun)
(org-roam-dolist-with-progress . 2)
(org-roam-with-temp-buffer . 1)

View File

@@ -46,7 +46,7 @@ jobs:
- uses: actions/checkout@v2
- name: Install Eldev
run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
run: curl -fsSL https://raw.github.com/org-roam/org-roam/master/github-eldev | sh
- name: Install dependencies
run: make prepare

View File

@@ -1,9 +1,9 @@
# Changelog
## TBD
## 2.2.1
### Breaking
- [#2054](https://github.com/org-roam/org-roam/pull/2054) node: simplify default `org-roam-node-display-template`.
This was done so completions work fine by default on all completion systems. To restore the tabular vertical completion interface, set this in your configuration:
```emacs-lisp
(setq org-roam-node-display-template
(concat "${title:*} "
@@ -14,12 +14,24 @@
- [#2042](https://github.com/org-roam/org-roam/pull/2042) db: add `org-roam-db-extra-links-elements` and `org-roam-db-extra-links-exclude-keys` for fine-grained control over additional link parsing
- [#2049](https://github.com/org-roam/org-roam/pull/2049) capture: allow ID to be used as part of `org-roam-capture-templates`
- [#2050](https://github.com/org-roam/org-roam/pull/2050) core: add `FILTER-FN` to `org-roam-node-random`
- [#2065](https://github.com/org-roam/org-roam/pull/2065) dailies: add `keys` argument to the remaining dailies functions `org-roam-dailies-goto-yesterday`/`-today`/`-tomorrow`/`-date` and `org-roam-dailies-capture-yesterday`/`-tomorrow`/`-date` to give the abilty to get into a capture buffer bypassing the selection screen in all dailies commands. Extension of #2055
- [#2079](https://github.com/org-roam/org-roam/pull/2079) capture: ensure that `:ref` info captured in all cases.
- [#2121](https://github.com/org-roam/org-roam/pull/2121) buffer: add unique option to `org-roam-backlinks-section`
### Removed
### Fixed
- [#2086](https://github.com/org-roam/org-roam/pull/2086) capture: correctly update org-id-locations on capture
- [#2082](https://github.com/org-roam/org-roam/pull/2082) buffer: don't destroy window if `org-roam-node-toggle` reuses window
- [#2080](https://github.com/org-roam/org-roam/pull/2080) dailies: prevent multiple "dailies/" subdir expansions
- [#2055](https://github.com/org-roam/org-roam/pull/2055) dailies: removed stray f require, which was causing require and compilation errors
- [#2117](https://github.com/org-roam/org-roam/pull/2117) capture: preserve trailing whitespace content in capture templates
### Changed
- [#2060](https://github.com/org-roam/org-roam/pull/2060) node: added double acute accent normalization for Unicode characters in titles
- [#2040](https://github.com/org-roam/org-roam/pull/2040) completions: fix completions display-width for Helm users
- [#2025](https://github.com/org-roam/org-roam/pull/2025) chore: removed the dependencies on f.el and s.el
- [#2109](https://github.com/org-roam/org-roam/pull/2109) capture: `org-roam-node-insert` places cursor after inserted link where appropriate
- [#2123](https://github.com/org-roam/org-roam/pull/2123), [#2124](https://github.com/org-roam/org-roam/pull/2124) buffer: `org-roam-mode-section-functions` renamed to `org-roam-mode-sections`, supports passing args into the section-rendering function
## 2.2.0
### Added

View File

@@ -228,7 +228,7 @@ it has not already been addressed on [GitHub][issues] or on
- [Jethro Kuan](https://braindump.jethro.dev/)
([Source](https://github.com/jethrokuan/braindump/tree/master/org))
- [Alexey Shmalko](https://braindump.rasen.dev/)
- [Alexey Shmalko](https://www.alexeyshmalko.com/)
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
## Contributing

View File

@@ -8,13 +8,13 @@
#+texinfo_dir_category: Emacs
#+texinfo_dir_title: Org-roam: (org-roam).
#+texinfo_dir_desc: Roam Research for Emacs.
#+subtitle: for version 2.2.0
#+subtitle: for version 2.2.1
#+options: H:4 num:3 toc:nil creator:t ':t
#+property: header-args :eval never
#+texinfo: @noindent
This manual is for Org-roam version 2.2.0.
This manual is for Org-roam version 2.2.1.
#+BEGIN_QUOTE
Copyright (C) 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>
@@ -468,6 +468,9 @@ can set ~org-roam-node-display-template~ as such:
* Customizing Node Caching
** How to cache
:PROPERTIES:
:ID: 280bfca8-83f3-4371-bc3a-25478d25129c
:END:
Org-roam uses a sqlite database to perform caching, but there are multiple Emacs
libraries that can be used. The default used by Org-roam is ~emacs-sqlite~.
@@ -633,10 +636,10 @@ There are currently 3 provided widget types:
- Unlinked references :: View nodes that contain text that match the nodes
title/alias but are not linked
To configure what sections are displayed in the buffer, set ~org-roam-mode-section-functions~.
To configure what sections are displayed in the buffer, set ~org-roam-mode-sections.
#+begin_src emacs-lisp
(setq org-roam-mode-section-functions
(setq org-roam-mode-sections
(list #'org-roam-backlinks-section
#'org-roam-reflinks-section
;; #'org-roam-unlinked-references-section
@@ -645,6 +648,16 @@ To configure what sections are displayed in the buffer, set ~org-roam-mode-secti
Note that computing unlinked references may be slow, and has not been added in by default.
For each section function, you can pass args along to modify its behaviour. For
example, if you want to render unique sources for backlinks (and also keep
rendering reference links), set ~org-roam-mode-sections~ as follows:
#+begin_src emacs-lisp
(setq org-roam-mode-sections
'((org-roam-backlinks-section :unique t)
org-roam-reflinks-section))
#+end_src
** Configuring the Org-roam buffer display
Org-roam does not control how the pop-up buffer is displayed: this is left to
@@ -899,7 +912,16 @@ file:
#+END_SRC
We also need to set up ~org-protocol~: the instructions for setting up
~org-protocol~ are reproduced below.
~org-protocol~ are reproduced here.
On a high-level, external calls are passed to Emacs via ~emacsclient~.
~org-protocol~ intercepts these and runs custom actions based on the protocols
registered. Hence, to use ~org-protocol~, once must:
1. launch the ~emacsclient~ process
2. Register ~org-protocol://~ as a valid scheme-handler
The instructions for the latter for each operating system is detailed below.
*** Linux
For Linux users, create a desktop application in
@@ -1618,6 +1640,20 @@ to the publishing directory. Example code follows:
(kill-buffer (file-name-nondirectory svg))
(setq my-publish-time 0)))))
#+end_src
** I'm seeing this "Selecting deleted buffer" error. What do I do?
The "selecting deleted buffer" error usually occurs when you don't have a
working ~emacsql-sqlite~ executable. Org-roam relies on this executable to
function properly, and doesn't catch this error. This issue is most commonly
seen on Windows setups. You can browse through the various GitHub issues posted
about this [[https://github.com/org-roam/org-roam/issues?q=is%3Aissue+selecting+deleted][here]].
To fix this, you can try the following:
1. If on Windows, try replacing your system binary with [[https://github.com/nobiot/emacsql-sqlite.exe][this one]] that has been proven
to work
2. Use the ~emacsql-sqlite3~ option rather than compiling your own emacsql
binary (see [[id:280bfca8-83f3-4371-bc3a-25478d25129c][How to cache]]).
* Developer's Guide to Org-roam
** Org-roam's Design Principle

View File

@@ -31,7 +31,7 @@ General Public License for more details.
@finalout
@titlepage
@title Org-roam User Manual
@subtitle for version 2.2.0
@subtitle for version 2.2.1
@author Jethro Kuan
@page
@vskip 0pt plus 1filll
@@ -44,7 +44,7 @@ General Public License for more details.
@noindent
This manual is for Org-roam version 2.2.0.
This manual is for Org-roam version 2.2.1.
@quotation
Copyright (C) 2020-2021 Jethro Kuan <jethrokuan95@@gmail.com>
@@ -195,6 +195,7 @@ FAQ
* How do I migrate from Roam Research?::
* How to migrate from Org-roam v1?::
* How do I publish my notes with an Internet-friendly graph?::
* I'm seeing this ``Selecting deleted buffer'' error. What do I do?: I'm seeing this ``Selecting deleted buffer'' error What do I do?.
How do I publish my notes with an Internet-friendly graph?
@@ -975,10 +976,10 @@ There are currently 3 provided widget types:
title/alias but are not linked
@end itemize
To configure what sections are displayed in the buffer, set @code{org-roam-mode-section-functions}.
To configure what sections are displayed in the buffer, set ~org-roam-mode-sections.
@lisp
(setq org-roam-mode-section-functions
(setq org-roam-mode-sections
(list #'org-roam-backlinks-section
#'org-roam-reflinks-section
;; #'org-roam-unlinked-references-section
@@ -987,6 +988,16 @@ To configure what sections are displayed in the buffer, set @code{org-roam-mode-
Note that computing unlinked references may be slow, and has not been added in by default.
For each section function, you can pass args along to modify its behaviour. For
example, if you want to render unique sources for backlinks (and also keep
rendering reference links), set @code{org-roam-mode-sections} as follows:
@lisp
(setq org-roam-mode-sections
'((org-roam-backlinks-section :unique t)
org-roam-reflinks-section))
@end lisp
@node Configuring the Org-roam buffer display
@section Configuring the Org-roam buffer display
@@ -1308,7 +1319,21 @@ file:
@end lisp
We also need to set up @code{org-protocol}: the instructions for setting up
@code{org-protocol} are reproduced below.
@code{org-protocol} are reproduced here.
On a high-level, external calls are passed to Emacs via @code{emacsclient}.
@code{org-protocol} intercepts these and runs custom actions based on the protocols
registered. Hence, to use @code{org-protocol}, once must:
@itemize
@item
launch the @code{emacsclient} process
@item
Register @code{org-protocol://} as a valid scheme-handler
@end itemize
The instructions for the latter for each operating system is detailed below.
@menu
* Linux::
@@ -2023,6 +2048,7 @@ Org-mode, and sync your cards to Anki via @uref{https://github.com/FooSoft/anki-
* How do I migrate from Roam Research?::
* How to migrate from Org-roam v1?::
* How do I publish my notes with an Internet-friendly graph?::
* I'm seeing this ``Selecting deleted buffer'' error. What do I do?: I'm seeing this ``Selecting deleted buffer'' error What do I do?.
@end menu
@node How do I have more than one Org-roam directory?
@@ -2233,6 +2259,27 @@ to the publishing directory. Example code follows:
(setq my-publish-time 0)))))
@end lisp
@node I'm seeing this ``Selecting deleted buffer'' error What do I do?
@section I'm seeing this ``Selecting deleted buffer'' error. What do I do?
The ``selecting deleted buffer'' error usually occurs when you don't have a
working @code{emacsql-sqlite} executable. Org-roam relies on this executable to
function properly, and doesn't catch this error. This issue is most commonly
seen on Windows setups. You can browse through the various GitHub issues posted
about this @uref{https://github.com/org-roam/org-roam/issues?q=is%3Aissue+selecting+deleted, here}.
To fix this, you can try the following:
@itemize
@item
If on Windows, try replacing your system binary with @uref{https://github.com/nobiot/emacsql-sqlite.exe, this one} that has been proven
to work
@item
Use the @code{emacsql-sqlite3} option rather than compiling your own emacsql
binary (see @ref{How to cache}).
@end itemize
@node Developer's Guide to Org-roam
@chapter Developer's Guide to Org-roam

View File

@@ -7,7 +7,7 @@
;; Leo Vivier <leo.vivier+dev@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
@@ -139,72 +139,93 @@ In this case, interactive selection will be bypassed."
(org-roam-dailies--capture (current-time) goto keys))
;;;###autoload
(defun org-roam-dailies-goto-today ()
"Find the daily-note for today, creating it if necessary."
(defun org-roam-dailies-goto-today (&optional keys)
"Find the daily-note for today, creating it if necessary.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive)
(org-roam-dailies-capture-today t))
(org-roam-dailies-capture-today t keys))
;;;; Tomorrow
;;;###autoload
(defun org-roam-dailies-capture-tomorrow (n &optional goto)
(defun org-roam-dailies-capture-tomorrow (n &optional goto keys)
"Create an entry in the daily-note for tomorrow.
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."
creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies--capture (time-add (* n 86400) (current-time)) goto))
(org-roam-dailies--capture (time-add (* n 86400) (current-time)) goto keys))
;;;###autoload
(defun org-roam-dailies-goto-tomorrow (n)
(defun org-roam-dailies-goto-tomorrow (n &optional keys)
"Find the daily-note for tomorrow, creating it if necessary.
With numeric argument N, use the daily-note N days in the
future."
future.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies-capture-tomorrow n t))
(org-roam-dailies-capture-tomorrow n t keys))
;;;; Yesterday
;;;###autoload
(defun org-roam-dailies-capture-yesterday (n &optional goto)
(defun org-roam-dailies-capture-yesterday (n &optional goto keys)
"Create an entry in the daily-note for yesteday.
With numeric argument N, use the daily-note N days in the past.
When GOTO is non-nil, go the note without creating an entry."
When GOTO is non-nil, go the note without creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies-capture-tomorrow (- n) goto))
(org-roam-dailies-capture-tomorrow (- n) goto keys))
;;;###autoload
(defun org-roam-dailies-goto-yesterday (n)
(defun org-roam-dailies-goto-yesterday (n &optional keys)
"Find the daily-note for yesterday, creating it if necessary.
With numeric argument N, use the daily-note N days in the
future."
future.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "p")
(org-roam-dailies-capture-tomorrow (- n) t))
(org-roam-dailies-capture-tomorrow (- n) t keys))
;;;; Date
;;;###autoload
(defun org-roam-dailies-capture-date (&optional goto prefer-future)
(defun org-roam-dailies-capture-date (&optional goto prefer-future keys)
"Create an entry in the daily-note for a date using the calendar.
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."
creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive "P")
(let ((time (let ((org-read-date-prefer-future prefer-future))
(org-read-date nil t nil (if goto
"Find daily-note: "
"Capture to daily-note: ")))))
(org-roam-dailies--capture time goto)))
(org-roam-dailies--capture time goto keys)))
;;;###autoload
(defun org-roam-dailies-goto-date (&optional prefer-future)
(defun org-roam-dailies-goto-date (&optional prefer-future keys)
"Find the daily-note for a date using the calendar, creating it if necessary.
Prefer past dates, unless PREFER-FUTURE is non-nil."
Prefer past dates, unless PREFER-FUTURE is non-nil.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(interactive)
(org-roam-dailies-capture-date t prefer-future))
(org-roam-dailies-capture-date t prefer-future keys))
;;;; Navigation
(defun org-roam-dailies-goto-next-note (&optional n)
@@ -308,7 +329,8 @@ When GOTO is non-nil, go the note without creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(let ((org-roam-directory (expand-file-name org-roam-dailies-directory org-roam-directory)))
(let ((org-roam-directory (expand-file-name org-roam-dailies-directory org-roam-directory))
(org-roam-dailies-directory "./"))
(org-roam-capture- :goto (when goto '(4))
:keys keys
:node (org-roam-node-create)

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.

View File

@@ -4,7 +4,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
;; This file is NOT part of GNU Emacs.
@@ -169,25 +169,6 @@ org-protocol://roam-node?node=uuid"
(push '("org-roam-node" :protocol "roam-node" :function org-roam-protocol-open-node)
org-protocol-protocol-alist)
;;; Capture implementation
(add-hook 'org-roam-capture-preface-hook #'org-roam-protocol--try-capture-to-ref-h)
(defun org-roam-protocol--try-capture-to-ref-h ()
"Try to capture to an existing node that match the ref."
(when-let ((node (and (plist-get org-roam-capture--info :ref)
(org-roam-node-from-ref
(plist-get org-roam-capture--info :ref)))))
(set-buffer (org-capture-target-buffer (org-roam-node-file node)))
(goto-char (org-roam-node-point node))
(widen)
(org-roam-node-id node)))
(add-hook 'org-roam-capture-new-node-hook #'org-roam-protocol--insert-captured-ref-h)
(defun org-roam-protocol--insert-captured-ref-h ()
"Insert the ref if any."
(when-let ((ref (plist-get org-roam-capture--info :ref)))
(org-roam-ref-add ref)))
(provide 'org-roam-protocol)
;;; org-roam-protocol.el ends here

11
github-eldev Executable file
View File

@@ -0,0 +1,11 @@
#! /bin/sh
set -e
ELDEV_BIN_DIR=~/.local/bin
# `$GITHUB_PATH' is a magic file which contents is translated to environment variable `$PATH'.
echo "$ELDEV_BIN_DIR" >> $GITHUB_PATH
mkdir -p $ELDEV_BIN_DIR
curl -fsSL https://raw.githubusercontent.com/doublep/eldev/f111d19cda305e5e8fcb70a5675b87173041cb68/bin/eldev > $ELDEV_BIN_DIR/eldev
chmod a+x $ELDEV_BIN_DIR/eldev

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.
@@ -505,7 +505,7 @@ Return the ID of the location."
(set-buffer (org-capture-target-buffer path))
(when new-file-p
(org-roam-capture--put :new-file path)
(insert (org-roam-capture--fill-template head t)))
(insert (org-roam-capture--fill-template head 'ensure-newline)))
(widen)
(setq p (goto-char (point-min))))
(`(file+head+olp ,path ,head ,olp)
@@ -515,7 +515,7 @@ Return the ID of the location."
(widen)
(when new-file-p
(org-roam-capture--put :new-file path)
(insert (org-roam-capture--fill-template head t)))
(insert (org-roam-capture--fill-template head 'ensure-newline)))
(setq p (point-min))
(let ((m (org-roam-capture-find-or-create-olp olp)))
(goto-char m)))
@@ -591,8 +591,9 @@ Return the ID of the location."
PATH is a string that can optionally contain templated text in
it."
(or (org-roam-node-file org-roam-capture--node)
(thread-first path
(org-roam-capture--fill-template t)
(thread-first
path
(org-roam-capture--fill-template)
(string-trim)
(expand-file-name org-roam-directory))))
@@ -617,7 +618,7 @@ you can catch it with `condition-case'."
(org-with-wide-buffer
(goto-char start)
(dolist (heading olp)
(setq heading (org-roam-capture--fill-template heading t))
(setq heading (org-roam-capture--fill-template heading))
(let ((re (format org-complex-heading-regexp-format
(regexp-quote heading)))
(cnt 0))
@@ -679,6 +680,24 @@ the current value of `point'."
(goto-char (org-entry-end-position))))))))
(point))
;;; Capture implementation
(add-hook 'org-roam-capture-preface-hook #'org-roam-capture--try-capture-to-ref-h)
(defun org-roam-capture--try-capture-to-ref-h ()
"Try to capture to an existing node that match the ref."
(when-let ((node (and (plist-get org-roam-capture--info :ref)
(org-roam-node-from-ref
(plist-get org-roam-capture--info :ref)))))
(set-buffer (org-capture-target-buffer (org-roam-node-file node)))
(goto-char (org-roam-node-point node))
(widen)
(org-roam-node-id node)))
(add-hook 'org-roam-capture-new-node-hook #'org-roam-capture--insert-captured-ref-h)
(defun org-roam-capture--insert-captured-ref-h ()
"Insert the ref if any."
(when-let ((ref (plist-get org-roam-capture--info :ref)))
(org-roam-ref-add ref)))
;;;; Finalizers
(add-hook 'org-capture-prepare-finalize-hook #'org-roam-capture--install-finalize-h)
(defun org-roam-capture--install-finalize-h ()
@@ -691,11 +710,14 @@ the current value of `point'."
(when-let ((region (org-roam-capture--get :region)))
(org-roam-unshield-region (car region) (cdr region)))
(if org-note-abort
(when-let ((new-file (org-roam-capture--get :new-file)))
(org-roam-message "Deleting file for aborted capture %s" new-file)
(when-let ((new-file (org-roam-capture--get :new-file))
(_ (yes-or-no-p "Delete file for aborted capture?")))
(when (find-buffer-visiting new-file)
(kill-buffer (find-buffer-visiting new-file)))
(delete-file new-file))
(when-let* ((buffer (plist-get org-capture-plist :buffer))
(file (buffer-file-name buffer)))
(org-id-add-location (org-roam-capture--get :id) file))
(when-let* ((finalize (org-roam-capture--get :finalize))
(org-roam-finalize-fn (intern (concat "org-roam-capture--finalize-"
(symbol-name finalize)))))
@@ -722,48 +744,53 @@ This function is to be called in the Org-capture finalization process."
(delete-region (car region) (cdr region))
(set-marker (car region) nil)
(set-marker (cdr region) nil))
(org-with-point-at mkr
(insert (org-link-make-string (concat "id:" (org-roam-capture--get :id))
(org-roam-capture--get :link-description)))))))
(let* ((id (org-roam-capture--get :id))
(description (org-roam-capture--get :link-description))
(link (org-link-make-string (concat "id:" id)
description)))
(if (eq (point) (marker-position mkr))
(insert link)
(org-with-point-at mkr
(insert link)))
(run-hook-with-args 'org-roam-post-node-insert-hook
id
description)))))
;;;; Processing of the capture templates
(defun org-roam-capture--fill-template (template &optional org-capture-p newline)
(defun org-roam-capture--fill-template (template &optional ensure-newline)
"Expand TEMPLATE and return it.
It expands ${var} occurrences in TEMPLATE. When ORG-CAPTURE-P,
also run Org-capture's template expansion.
If NEWLINE, ensure that the template returned ends with a newline."
(setq template (org-roam-format-template
template
(lambda (key default-val)
(let ((fn (intern key))
(node-fn (intern (concat "org-roam-node-" key)))
(ksym (intern (concat ":" key))))
(cond
((fboundp fn)
(funcall fn org-roam-capture--node))
((fboundp node-fn)
(funcall node-fn org-roam-capture--node))
((plist-get org-roam-capture--info ksym)
(plist-get org-roam-capture--info ksym))
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
(plist-put org-roam-capture--info ksym r)
r)))))))
;; WARNING:
;; `org-capture-fill-template' fills the template, but post-processes whitespace such that the resultant
;; template does not start with any whitespace, and only ends with a single newline
;;
;; In most cases where we rely on `org-capture-fill-template' to populate non-org-capture-related templates,
;; (e.g. in OLPs), we strip the final newline, obtaining a template that seems to be string-trimmed.
;;
;; This means that if the original passed template has newlines, and ORG-CAPTURE-P is true, then the extra
;; whitespace specified in the template will be ignored.
(when org-capture-p
It expands ${var} occurrences in TEMPLATE, and then runs
org-capture's template expansion.
When ENSURE-NEWLINE, always ensure there's a newline behind."
(let ((template-whitespace-content (org-roam-whitespace-content template)))
(setq template
(replace-regexp-in-string "\n$" "" (org-capture-fill-template template))))
(when (and newline
(not (string-suffix-p "\n" template)))
(setq template (concat template "\n")))
template)
(org-roam-format-template
template
(lambda (key default-val)
(let ((fn (intern key))
(node-fn (intern (concat "org-roam-node-" key)))
(ksym (intern (concat ":" key))))
(cond
((fboundp fn)
(funcall fn org-roam-capture--node))
((fboundp node-fn)
(funcall node-fn org-roam-capture--node))
((plist-get org-roam-capture--info ksym)
(plist-get org-roam-capture--info ksym))
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
(plist-put org-roam-capture--info ksym r)
r)))))))
;; WARNING:
;; `org-capture-fill-template' fills the template, but post-processes whitespace such that the resultant
;; template does not start with any whitespace, and only ends with a single newline
;;
;; Instead, we restore the whitespace in the original template.
(setq template (replace-regexp-in-string "\n$" "" (org-capture-fill-template template)))
(when (and ensure-newline
(string-equal template-whitespace-content ""))
(setq template-whitespace-content "\n"))
(setq template (concat template template-whitespace-content))
template))
(defun org-roam-capture--convert-template (template &optional props)
"Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax.

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1"))
;; This file is NOT part of GNU Emacs.
@@ -229,6 +229,10 @@ nodes." org-id-locations-file)
'org-roam-remove-property
'org-roam-property-remove "org-roam 2.1")
(define-obsolete-variable-alias
'org-roam-mode-section-functions
'org-roam-mode-sections "org-roam 2.2.0")
;;; Obsolete functions
(make-obsolete 'org-roam-get-keyword 'org-collect-keywords "org-roam 2.0")

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.

117
org-roam-id.el Normal file
View File

@@ -0,0 +1,117 @@
;;; org-roam-id.el --- ID-related utilities for Org-roam -*- lexical-binding: t; -*-
;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; This module provides ID-related facilities using the Org-roam database.
;;
;;; Code:
(require 'org-id)
(defun org-roam-id-at-point ()
"Return the ID at point, if any.
Recursively traverses up the headline tree to find the
first encapsulating ID."
(org-with-wide-buffer
(org-back-to-heading-or-point-min t)
(while (and (not (org-roam-db-node-p))
(not (bobp)))
(org-roam-up-heading-or-point-min))
(when (org-roam-db-node-p)
(org-id-get))))
(defun org-roam-id-find (id &optional markerp)
"Return the location of the entry with the id ID using the Org-roam db.
The return value is a cons cell (file-name . position), or nil
if there is no entry with that ID.
With optional argument MARKERP, return the position as a new marker."
(cond
((symbolp id) (setq id (symbol-name id)))
((numberp id) (setq id (number-to-string id))))
(let ((node (org-roam-populate (org-roam-node-create :id id))))
(when-let ((file (org-roam-node-file node)))
(if markerp
(unwind-protect
(let ((buffer (or (find-buffer-visiting file)
(find-file-noselect file))))
(with-current-buffer buffer
(move-marker (make-marker) (org-roam-node-point node) buffer))))
(cons (org-roam-node-file node)
(org-roam-node-point node))))))
(defun org-roam-id-open (id _)
"Go to the entry with id ID.
Like `org-id-open', but additionally uses the Org-roam database."
(org-mark-ring-push)
(let ((m (or (org-roam-id-find id 'marker)
(org-id-find id 'marker)))
cmd)
(unless m
(error "Cannot find entry with ID \"%s\"" id))
;; Use a buffer-switching command in analogy to finding files
(setq cmd
(or
(cdr
(assq
(cdr (assq 'file org-link-frame-setup))
'((find-file . switch-to-buffer)
(find-file-other-window . switch-to-buffer-other-window)
(find-file-other-frame . switch-to-buffer-other-frame))))
'switch-to-buffer-other-window))
(if (not (equal (current-buffer) (marker-buffer m)))
(funcall cmd (marker-buffer m)))
(goto-char m)
(move-marker m nil)
(org-show-context)))
(org-link-set-parameters "id" :follow #'org-roam-id-open)
;;;###autoload
(defun org-roam-update-org-id-locations (&rest directories)
"Scan Org-roam files to update `org-id' related state.
This is like `org-id-update-id-locations', but will automatically
use the currently bound `org-directory' and `org-roam-directory'
along with DIRECTORIES (if any), where the lookup for files in
these directories will be always recursive.
Note: Org-roam doesn't have hard dependency on
`org-id-locations-file' to lookup IDs for nodes that are stored
in the database, but it still tries to properly integrates with
`org-id'. This allows the user to cross-reference IDs outside of
the current `org-roam-directory', and also link with \"id:\"
links to headings/files within the current `org-roam-directory'
that are excluded from identification in Org-roam as
`org-roam-node's, e.g. with \"ROAM_EXCLUDE\" property."
(interactive)
(cl-loop for dir in (cons org-roam-directory directories)
for org-roam-directory = dir
nconc (org-roam-list-files) into files
finally (org-id-update-id-locations files org-roam-verbose)))
(provide 'org-roam-id)
;;; org-roam-id.el ends here

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.
@@ -39,14 +39,28 @@
(defvar org-ref-buffer-hacked)
;;; Options
(defcustom org-roam-mode-section-functions (list #'org-roam-backlinks-section
#'org-roam-reflinks-section)
"Functions that insert sections in the `org-roam-mode' based buffers.
Each function is called with one argument, which is an
`org-roam-node' for which the buffer will be constructed for.
Normally this node is `org-roam-buffer-current-node'."
(defcustom org-roam-mode-sections (list #'org-roam-backlinks-section
#'org-roam-reflinks-section)
"A list of sections for the `org-roam-mode' based buffers.
Each section is a function that is passed the an `org-roam-node'
for which the section will be constructed for as the first
argument. Normally this node is `org-roam-buffer-current-node'.
The function may also accept other optional arguments. Each item
in the list is either:
1. A function, which is called only with the `org-roam-node' as the argument
2. A list, containing the function and the optional arguments.
For example, one can add
(org-roam-backlinks-section :unique t)
to the list to pass :unique t to the section-rendering function."
:group 'org-roam
:type 'hook)
:type `(repeat (choice (symbol :tag "Function")
(list :tag "Function with arguments"
(symbol :tag "Function")
(repeat :tag "Arguments" :inline t (sexp :tag "Arg"))))))
(defcustom org-roam-buffer-postrender-functions (list)
"Functions to run after the Org-roam buffer is rendered.
@@ -168,7 +182,7 @@ This mode is used by special Org-roam buffers, such as persistent
`org-roam-buffer' and dedicated Org-roam buffers
\(`org-roam-buffer-display-dedicated'), which render the
information in a section-like manner (see
`org-roam-mode-section-functions'), with which the user can
`org-roam-mode-sections'), with which the user can
interact with."
:group 'org-roam
(face-remap-add-relative 'header-line 'org-roam-header-line))
@@ -228,7 +242,14 @@ buffer."
(org-roam-node-title org-roam-buffer-current-node))
(magit-insert-section (org-roam)
(magit-insert-heading)
(run-hook-with-args 'org-roam-mode-section-functions org-roam-buffer-current-node))
(dolist (section org-roam-mode-sections)
(pcase section
((pred functionp)
(funcall section org-roam-buffer-current-node))
(`(,fn . ,args)
(apply fn (cons org-roam-buffer-current-node args)))
(_
(user-error "Invalid `org-roam-mode-sections' specification")))))
(run-hooks 'org-roam-buffer-postrender-functions)
(goto-char 0)))
@@ -289,7 +310,7 @@ To toggle its display use `org-roam-buffer-toggle' command.")
(pcase (org-roam-buffer--visibility)
('visible
(progn
(delete-window (get-buffer-window org-roam-buffer))
(quit-window nil (get-buffer-window org-roam-buffer))
(remove-hook 'post-command-hook #'org-roam-buffer--redisplay-h)))
((or 'exists 'none)
(progn
@@ -459,14 +480,23 @@ headline, up to the next headline."
(org-roam-populate (org-roam-backlink-target-node backlink)))
backlink)
(defun org-roam-backlinks-get (node)
"Return the backlinks for NODE."
(let ((backlinks (org-roam-db-query
[:select [source dest pos properties]
:from links
:where (= dest $s1)
:and (= type "id")]
(org-roam-node-id node))))
(cl-defun org-roam-backlinks-get (node &key unique)
"Return the backlinks for NODE.
When UNIQUE is nil, show all positions where references are found.
When UNIQUE is t, limit to unique sources."
(let* ((sql (if unique
[:select :distinct [source dest pos properties]
:from links
:where (= dest $s1)
:and (= type "id")
:group :by source
:having (funcall min pos)]
[:select [source dest pos properties]
:from links
:where (= dest $s1)
:and (= type "id")]))
(backlinks (org-roam-db-query sql (org-roam-node-id node))))
(cl-loop for backlink in backlinks
collect (pcase-let ((`(,source-id ,dest-id ,pos ,properties) backlink))
(org-roam-populate
@@ -482,9 +512,12 @@ Sorts by title."
(string< (org-roam-node-title (org-roam-backlink-source-node a))
(org-roam-node-title (org-roam-backlink-source-node b))))
(defun org-roam-backlinks-section (node)
"The backlinks section for NODE."
(when-let ((backlinks (seq-sort #'org-roam-backlinks-sort (org-roam-backlinks-get node))))
(cl-defun org-roam-backlinks-section (node &key (unique nil))
"The backlinks section for NODE.
When UNIQUE is nil, show all positions where references are found.
When UNIQUE is t, limit to unique sources."
(when-let ((backlinks (seq-sort #'org-roam-backlinks-sort (org-roam-backlinks-get node :unique unique))))
(magit-insert-section (org-roam-backlinks)
(magit-insert-heading "Backlinks:")
(dolist (backlink backlinks)

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.
@@ -131,7 +131,8 @@ It takes a single argument REF, which is a propertized string."
:type 'boolean)
(defcustom org-roam-extract-new-file-path "%<%Y%m%d%H%M%S>-${slug}.org"
"The file path to use when a node is extracted to its own file."
"The file path template to use when a node is extracted to its own file.
This path is relative to `org-roam-directory'."
:group 'org-roam
:type 'string)
@@ -174,6 +175,7 @@ It takes a single argument REF, which is a propertized string."
776 ; U+0308 COMBINING DIAERESIS
777 ; U+0309 COMBINING HOOK ABOVE
778 ; U+030A COMBINING RING ABOVE
779 ; U+030B COMBINING DOUBLE ACUTE ACCENT
780 ; U+030C COMBINING CARON
795 ; U+031B COMBINING HORN
803 ; U+0323 COMBINING DOT BELOW
@@ -185,14 +187,12 @@ It takes a single argument REF, which is a propertized string."
816 ; U+0330 COMBINING TILDE BELOW
817 ; U+0331 COMBINING MACRON BELOW
)))
(cl-flet* ((nonspacing-mark-p (char)
(memq char slug-trim-chars))
(strip-nonspacing-marks (s)
(string-glyph-compose
(apply #'string (seq-remove #'nonspacing-mark-p
(string-glyph-decompose s)))))
(cl-replace (title pair)
(replace-regexp-in-string (car pair) (cdr pair) title)))
(cl-flet* ((nonspacing-mark-p (char) (memq char slug-trim-chars))
(strip-nonspacing-marks (s) (string-glyph-compose
(apply #'string
(seq-remove #'nonspacing-mark-p
(string-glyph-decompose s)))))
(cl-replace (title pair) (replace-regexp-in-string (car pair) (cdr pair) title)))
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
("__*" . "_") ;; remove sequential underscores
("^_" . "") ;; remove starting underscore
@@ -425,19 +425,41 @@ GROUP BY id")))
all-titles)))))
;;;; Finders
(defun org-roam-node-find-noselect (node &optional force)
"Navigate to the point for NODE, and return the buffer.
If NODE is already visited, this won't automatically move the
point to the beginning of the NODE, unless FORCE is non-nil."
(unless (org-roam-node-file node)
(user-error "Node does not have corresponding file"))
(let ((buf (find-file-noselect (org-roam-node-file node))))
(with-current-buffer buf
(when (or force
(not (equal (org-roam-node-id node)
(org-roam-id-at-point))))
(goto-char (org-roam-node-point node))))
buf))
(defun org-roam-node-marker (node)
"Get the marker for NODE."
(unwind-protect
(let* ((file (org-roam-node-file node))
(buffer (or (find-buffer-visiting file)
(find-file-noselect file))))
(with-current-buffer buffer
(move-marker (make-marker) (org-roam-node-point node) buffer)))))
(defun org-roam-node-open (node &optional cmd force)
"Go to the node NODE.
CMD is the command used to display the buffer. If not provided,
`org-link-frame-setup' is respected. Assumes that the node is
fully populated, with file and point. If NODE is already visited,
this won't automatically move the point to the beginning of the
NODE, unless FORCE is non-nil."
(interactive (list (org-roam-node-at-point) current-prefix-arg))
(org-mark-ring-push)
(let ((m (org-roam-node-marker node))
(cmd (or cmd
(cdr
(assq
(cdr (assq 'file org-link-frame-setup))
'((find-file . switch-to-buffer)
(find-file-other-window . switch-to-buffer-other-window)
(find-file-other-frame . switch-to-buffer-other-frame))))
'switch-to-buffer-other-window)))
(if (not (equal (current-buffer) (marker-buffer m)))
(funcall cmd (marker-buffer m)))
(when (or force
(not (equal (org-roam-node-id node)
(org-roam-id-at-point))))
(goto-char m))
(move-marker m nil))
(org-show-context))
(defun org-roam-node-visit (node &optional other-window force)
"From the current buffer, visit NODE. Return the visited buffer.
@@ -449,13 +471,10 @@ If NODE is already visited, this won't automatically move the
point to the beginning of the NODE, unless FORCE is non-nil. In
interactive calls FORCE always set to t."
(interactive (list (org-roam-node-at-point t) current-prefix-arg t))
(let ((buf (org-roam-node-find-noselect node force))
(display-buffer-fn (if other-window
(org-roam-node-open node (if other-window
#'switch-to-buffer-other-window
#'pop-to-buffer-same-window)))
(funcall display-buffer-fn buf)
(when (org-invisible-p) (org-show-context))
buf))
#'pop-to-buffer-same-window)
force))
;;;###autoload
(cl-defun org-roam-node-find (&optional other-window initial-input filter-fn &key templates)
@@ -476,7 +495,7 @@ The TEMPLATES, if provided, override the list of capture templates (see
:props '(:finalize find-file)))))
;;;###autoload
(defun org-roam-node-random (filter-fn &optional other-window)
(defun org-roam-node-random (&optional other-window filter-fn)
"Find and open a random Org-roam node.
With prefix argument OTHER-WINDOW, visit the node in another
window instead.
@@ -669,9 +688,13 @@ The INFO, if provided, is passed to the underlying `org-roam-capture-'."
(delete-region beg end)
(set-marker beg nil)
(set-marker end nil))
(insert (org-link-make-string
(concat "id:" (org-roam-node-id node))
description)))
(let ((id (org-roam-node-id node)))
(insert (org-link-make-string
(concat "id:" id)
description))
(run-hook-with-args 'org-roam-post-node-insert-hook
id
description)))
(org-roam-capture-
:node node
:info info
@@ -679,31 +702,10 @@ The INFO, if provided, is passed to the underlying `org-roam-capture-'."
:props (append
(when (and beg end)
(list :region (cons beg end)))
(list :insert-at (point-marker)
:link-description description
(list :link-description description
:finalize 'insert-link))))))
(deactivate-mark)))
(add-hook 'org-roam-find-file-hook #'org-roam-open-id-with-org-roam-db-h)
(defun org-roam-open-id-with-org-roam-db-h ()
"Try to open \"id:\" links at point by querying them to the database."
(add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point nil t))
(defun org-roam-open-id-at-point ()
"Navigate to \"id:\" link at point using the Org-roam database."
(when (org-in-regexp org-link-any-re)
(let ((link (match-string 2))
id)
(when (string-prefix-p "id:" link)
(setq id (substring-no-properties link 3))
(let ((node (org-roam-populate (org-roam-node-create :id id))))
(cond
((org-roam-node-file node)
(org-mark-ring-push)
(org-roam-node-visit node nil 'force)
t)
(t nil)))))))
;;;;; [roam:] link
(org-link-set-parameters "roam" :follow #'org-roam-link-follow-link)
(defun org-roam-link-follow-link (title-or-alias)
@@ -817,7 +819,8 @@ Any tags declared on #+FILETAGS: are transferred to tags on the new top heading.
Any top level properties drawers are incorporated into the new heading."
(interactive)
(org-with-point-at 1
(org-map-entries 'org-do-demote)
(org-map-region #'org-do-demote
(point-min) (point-max))
(insert "* "
(org-roam--get-keyword "title")
"\n")
@@ -832,9 +835,11 @@ Converts a file containing a headline node at the top to a file
node."
(interactive)
(org-with-point-at 1
(org-map-entries (lambda ()
(when (> (org-outline-level) 1)
(org-do-promote))))
(org-map-region
(lambda ()
(when (> (org-outline-level) 1)
(org-do-promote)))
(point-min) (point-max))
(let ((title (nth 4 (org-heading-components)))
(tags (nth 5 (org-heading-components))))
(beginning-of-line)
@@ -926,8 +931,11 @@ If region is active, then use it instead of the node at point."
(t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
(plist-put template-info ksym r)
r)))))))
(file-path (read-file-name "Extract node to: "
(file-name-as-directory org-roam-directory) template nil template)))
(file-path
(expand-file-name
(read-file-name "Extract node to: "
(file-name-as-directory org-roam-directory) template nil template)
org-roam-directory)))
(when (file-exists-p file-path)
(user-error "%s exists. Aborting" file-path))
(org-cut-subtree)
@@ -937,42 +945,6 @@ If region is active, then use it instead of the node at point."
(org-roam-promote-entire-buffer)
(save-buffer)))))
;;; IDs
;;;; Getters
(defun org-roam-id-at-point ()
"Return the ID at point, if any.
Recursively traverses up the headline tree to find the
first encapsulating ID."
(org-with-wide-buffer
(org-back-to-heading-or-point-min t)
(while (and (not (org-roam-db-node-p))
(not (bobp)))
(org-roam-up-heading-or-point-min))
(when (org-roam-db-node-p)
(org-id-get))))
;;;###autoload
(defun org-roam-update-org-id-locations (&rest directories)
"Scan Org-roam files to update `org-id' related state.
This is like `org-id-update-id-locations', but will automatically
use the currently bound `org-directory' and `org-roam-directory'
along with DIRECTORIES (if any), where the lookup for files in
these directories will be always recursive.
Note: Org-roam doesn't have hard dependency on
`org-id-locations-file' to lookup IDs for nodes that are stored
in the database, but it still tries to properly integrates with
`org-id'. This allows the user to cross-reference IDs outside of
the current `org-roam-directory', and also link with \"id:\"
links to headings/files within the current `org-roam-directory'
that are excluded from identification in Org-roam as
`org-roam-node's, e.g. with \"ROAM_EXCLUDE\" property."
(interactive)
(cl-loop for dir in (cons org-roam-directory directories)
for org-roam-directory = dir
nconc (org-roam-list-files) into files
finally (org-id-update-id-locations files org-roam-verbose)))
;;; Refs
;;;; Completing-read interface
(defun org-roam-ref-read (&optional initial-input filter-fn)

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4"))
;; This file is NOT part of GNU Emacs.
@@ -69,6 +69,15 @@ Like `string-equal', but case-insensitive."
(or (string-equal s1 s2)
(string-equal (downcase s1) (downcase s2)))))
(defun org-roam-whitespace-content (s)
"Return the whitespace content at the end of S."
(with-temp-buffer
(let ((c 0))
(insert s)
(skip-chars-backward " \t\n")
(buffer-substring-no-properties
(point) (point-max)))))
(defun org-roam-strip-comments (s)
"Strip Org comments from string S."
(with-temp-buffer
@@ -112,8 +121,8 @@ SPEC is a list, as per `dolist'."
(defun org-roam-descendant-of-p (a b)
"Return t if A is descendant of B."
(unless (equal (file-truename a) (file-truename b))
(string-prefix-p (expand-file-name b)
(expand-file-name a))))
(string-prefix-p (replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name b) t t)
(replace-regexp-in-string "^\\([A-Za-z]\\):" 'downcase (expand-file-name a) t t))))
(defmacro org-roam-with-file (file keep-buf-p &rest body)
"Execute BODY within FILE.

View File

@@ -5,7 +5,7 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.2.0
;; Version: 2.2.1
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0"))
;; This file is NOT part of GNU Emacs.
@@ -122,6 +122,12 @@ All Org files, at any level of nesting, are considered part of the Org-roam."
:group 'org-roam
:type 'hook)
(defcustom org-roam-post-node-insert-hook nil
"Hook run when an Org-roam node is inserted as an Org link.
Each function takes two arguments: the id of the node, and the link description."
:group 'org-roam
:type 'hook)
(defcustom org-roam-file-extensions '("org")
"List of file extensions to be included by Org-Roam.
While a file extension different from \".org\" may be used, the
@@ -260,7 +266,7 @@ If no files are found, an empty list is returned."
(ansi-color-filter-apply it)
(split-string it "\n")
(seq-filter (lambda (s)
(or (null s) (string= "" s))) it)))
(not (or (null s) (string= "" s)))) it)))
(defun org-roam--list-files-search-globs (exts)
"Given EXTS, return a list of search globs.
@@ -313,6 +319,7 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
(require 'org-roam-utils)
(require 'org-roam-db)
(require 'org-roam-node)
(require 'org-roam-id)
(require 'org-roam-capture)
(require 'org-roam-mode)
(require 'org-roam-migrate))

View File

@@ -0,0 +1,51 @@
;;; test-org-roam-capture.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'buttercup)
(require 'org-roam)
(describe "org-roam-capture--fill-template"
(it "fills template without newline"
(expect
(org-roam-capture--fill-template "foo")
:to-equal "foo"))
(it "fills template ensuring newline"
(expect
(org-roam-capture--fill-template "foo" 'ensure-newline)
:to-equal "foo\n"))
(it "fills template with newline"
(expect
(org-roam-capture--fill-template "foo\n")
:to-equal "foo\n"))
(it "fills template with two newlines"
(expect
(org-roam-capture--fill-template "foo\n\n")
:to-equal "foo\n\n")
(expect
(org-roam-capture--fill-template "foo\n\t\n")
:to-equal "foo\n\t\n")))
(provide 'test-org-roam-capture)

View File

@@ -0,0 +1,39 @@
;;; test-org-roam-utils.el --- Tests for Org-roam -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Jethro Kuan
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; Package-Requires: ((buttercup))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'buttercup)
(require 'org-roam)
(describe "org-roam-whitespace-content"
(it "extracts whitespace correctly"
(expect
(org-roam-whitespace-content "foo")
:to-equal "")
(expect
(org-roam-whitespace-content "foo\n")
:to-equal "\n")
(expect
(org-roam-whitespace-content "foo\n\t\n")
:to-equal "\n\t\n")))
(provide 'test-org-roam-utils)