Compare commits

..

10 Commits

Author SHA1 Message Date
Wetlize
9401fad1b2 (experimental): react to directory related events in the database
With filenotify events related to subdirectories, automatically
invalidate no longer valid entries and add the new ones as they appear.
2021-08-23 01:22:49 +03:00
Wetlize
1c3d3098c7 allow hot swapping of org-roam-db-autosync-update-method 2021-08-22 15:39:03 +03:00
Jethro Kuan
15dfb85bd1 ignore hidden directories 2021-08-20 15:25:36 +08:00
Jethro Kuan
0d0ae01684 use filenotify-recursive 2021-08-19 03:14:49 +08:00
Wetlize
6135731eed revert "move (require 'filenotify) under the "update method" function"
Revert c450dbd054.

We sniff for file-notify--library at the top level, so it's required
there. Otherwise it will error during the loading.
2021-08-17 21:00:04 +03:00
Wetlize
aac41a22e4 update org-roam-compat.el 2021-08-17 20:53:40 +03:00
Wetlize
c450dbd054 move (require 'filenotify) under the "update method" function 2021-08-17 20:53:38 +03:00
Wetlize
33d8792f19 fix and refactor things
- restructure the file a bit
- move setup logic for update method to its own function
- namespace autosync and filenotify related things
- rewrite org-roam-db-fn-callback (now org-roam-db-autosync--filenotify-update)
  to actually react to changes. Previously it wouldn't do anything.
2021-08-17 20:25:00 +03:00
Jethro Kuan
87b2359d6d fix lints 2021-08-17 19:11:47 +08:00
Jethro Kuan
210073c7d2 (feat)db: use file-notify to keep track trigger db updates 2021-08-17 18:55:22 +08:00
17 changed files with 435 additions and 558 deletions

View File

@@ -1,46 +1,9 @@
# Changelog
## TBD
## 1.2.4 (TBD)
### Added
### Removed
### Changed
- [#1795](https://github.com/org-roam/org-roam/pull/1795) buffer: optimized reflinks fetch
### Fixed
- [#1798](https://github.com/org-roam/org-roam/pull/1798) org-roam-node-at-point: do not skip invisible headings
## 2.1.0
### Added
- [#1693](https://github.com/org-roam/org-roam/pull/1693) added `filter-fn` and `templates` parameter to `org-roam-capture`, `org-roam-node-find`, and `org-roam-node-insert`
- [#1709](https://github.com/org-roam/org-roam/pull/1709) added ability to specify default value in org-roam capture templates
- [#1710](https://github.com/org-roam/org-roam/pull/1710) added `org-roam-extract-subtree`
- [#1720](https://github.com/org-roam/org-roam/pull/1720) added `org-roam-db-update-on-save`
- [#1758](https://github.com/org-roam/org-roam/pull/1758) added `org-roam-db-autosync-mode`, replacing `org-roam-setup` and `org-roam-teardown`
### Removed
- [#1716](https://github.com/org-roam/org-roam/pull/1716) helper function `org-roam-get-keyword` is now obsolete: prefer `org-collect-keywords`
### Changed
- [#1595](https://github.com/org-roam/org-roam/pull/1595), [#1724](https://github.com/org-roam/org-roam/pull/1724) Major refactoring and restructuring of the codebase
- [#1655](https://github.com/org-roam/org-roam/pull/1655) improved org-roam contents preview
- [#1741](https://github.com/org-roam/org-roam/pull/1741) expose `org-roam-capture-` keys in interactive commands
- [#1786](https://github.com/org-roam/org-roam/pull/1786) org-roam-version now outputs commit hash if found
- [#1788](https://github.com/org-roam/org-roam/pull/1788) the point is not moved if the node is already visited
### Fixed
- [#1608](https://github.com/org-roam/org-roam/pull/1608) migration: empty ROAM_REFS are now removed
- [#1609](https://github.com/org-roam/org-roam/pull/1609) migration: fixed file-link replacement
- [#1653](https://github.com/org-roam/org-roam/pull/1653) migration: fixed tags migration
- [#1694](https://github.com/org-roam/org-roam/pull/1694) core: nodes with no title are now skipped
- [#1637](https://github.com/org-roam/org-roam/pull/1637) core: fix org-ref multi-cite links not being split
- [#1651](https://github.com/org-roam/org-roam/pull/1651) core: fix org-roam-file-p crashing when there is no corresponding file
- [#1705](https://github.com/org-roam/org-roam/pull/1705) core: fix for add/remove of file-level tags
- [#1769](https://github.com/org-roam/org-roam/pull/1769) core: gracefully handle absence of `org-id-locations-file`
- [#1713](https://github.com/org-roam/org-roam/pull/1713) capture: check for file-existence before template insertion
- [#1725](https://github.com/org-roam/org-roam/pull/1725) db: always compute hash of encrypted file to prevent re-processing of encrypted files
## 2.0.0
### Added
- [#1396](https://github.com/org-roam/org-roam/pull/1396) add option to choose between prepending, appending, and omitting `roam_tags` in file completion
- [#1270](https://github.com/org-roam/org-roam/pull/1270) capture: create OLP if it does not exist. Removes need for OLP setup in `:head`.
- [#1353](https://github.com/org-roam/org-roam/pull/1353) support file-level property drawers
@@ -65,6 +28,7 @@
- [#1403](https://github.com/org-roam/org-roam/issues/1403) fixed inconsistency between how we write and read props like alias and tags
- [#1409](https://github.com/org-roam/org-roam/issues/1398) prevent inclusion of non-org-roam files in `org-roam-dailies--list-files`
- [#1542](https://github.com/org-roam/org-roam/issues/1542) fix files not excluded when `org-roam-list-files-commands` is nil
- [#1705](https://github.com/org-roam/org-roam/pull/1705) fix for add/remove of file-level tags
## 1.2.3 (13-11-2020)

146
README.md
View File

@@ -33,22 +33,13 @@ solution for anyone already using Org-mode for their personal wiki.
## Installation
Down below you will find basic installation instructions for how to quickly
install `org-roam` using various environments for various purposes. For more
detailed information, please read the [manual][docs].
### Using `package.el`
<details>
<summary>Toggle instuctions</summary>
You can install `org-roam` from [MELPA](https://melpa.org/) or [MELPA
Stable](https://stable.melpa.org/) using `package.el`:
You can install `org-roam` using `package.el`:
```
M-x package-install RET org-roam RET
```
Here's a very basic sample for configuration of `org-roam` using `use-package`:
Here's a sample configuration with `use-package`:
```emacs-lisp
(use-package org-roam
@@ -68,135 +59,12 @@ Here's a very basic sample for configuration of `org-roam` using `use-package`:
(require 'org-roam-protocol))
```
Note that the `file-truename` function is only necessary when you use symbolic
link to `org-roam-directory`. Org-roam won't automatically resolve symbolic link
to the directory.
</details>
The `file-truename` function is only necessary when you use symbolic links
inside `org-roam-directory`: Org-roam does not resolve symbolic links.
### Using `straight.el`
<details>
<summary>Toggle instuctions</summary>
Installation from MELPA or MELPA Stable using `straight.el`:
```emacs-lisp
(straight-use-package 'org-roam)
```
Or with `use-package`:
```emacs-lisp
(use-package org-roam
:straight t
...)
```
If you need to install the package directly from the source repository, instead
of from MELPA, the next sample shows how to do so:
```emacs-lisp
(use-package org-roam
:straight (:host github :repo "org-roam/org-roam"
:files (:defaults "extensions/*"))
...)
```
If you plan to use your own local fork for the development and contribution, the
next sample will get you there:
```emacs-lisp
(use-package org-roam
:straight (:local-repo "/path/to/org-roam-fork"
:files (:defaults "extensions/*")
:build (:not compile))
...)
```
</details>
### Using Doom Emacs
<details>
<summary>Toggle instuctions</summary>
Doom's `:lang org` module comes with support for `org-roam`, but it's not
enabled by default. To activate it pass `+roam2` flag to `org` module in your
`$DOOMDIR/init.el` (e.g. `(org +roam2)`), save the file and run `doom sync -u`
in your shell.
To provide better stability, Doom pins the package to a specific commit. If you
need to unpin it *(not recommended doing that, request Doom to bump the package
instead)* use the next in your `packages.el`:
```emacs-lisp
(unpin! org-roam)
```
If for some reasons you want to use a different recipe for `org-roam`, you can
use the next form in your `packages.el` to install the package from a recipe
repository (e.g. MELPA):
```emacs-lisp
(package! org-roam)
```
You can pass `:pin "commit hash"` to pin the package to a specific commit.
With the next sample you can install the package directly from the source
repository:
```emacs-lisp
(package! org-roam
:recipe (:host github :repo "org-roam/org-roam"
:files (:defaults "extensions/*")))
```
And if you plan to use your own local fork for the development or contribution,
the next sample will get you there:
```emacs-lisp
(package! org-roam
:recipe (:local-repo "/path/to/org-roam-fork"
:files (:defaults "extensions/*")
:build (:not compile)))
```
</details>
### Without a package manager
<details>
<summary>Toggle instructions</summary>
To install the package without using a package manager you have the next two
options:
1. Install the package by cloning it with `git` from the source repository.
2. Or install the package by downloading the latest [release
version](https://github.com/org-roam/org-roam/releases).
In both of the cases you will need to ensure that you have all the required
dependencies. These include:
- dash
- f
- s
- org (9.4 is the minimal required version!)
- emacsql
- emacsql-sqlite
- magit-section
- filenotify-recursive
After installing the package, you will need to properly setup `load-path` to the
package:
``` emacs-lisp
(add-to-list 'load-path "/path/to/org-roam/")
(add-to-list 'load-path "/path/to-org-roam/extensions/")
```
After which you should be able to resolve `(require 'org-roam)` call without any
problems.
Org-roam also comes with `.texi` files to integrate with Emacs' built-in Info
system. Read the manual to find more details for how to install them manually.
</details>
Org-roam requires sqlite to function. Org-roam optionally uses Graphviz for
graph-related functionality. It is recommended to install PCRE-enabled ripgrep
for better performance and extended functionality.
## Getting Started

View File

@@ -116,8 +116,8 @@
<div class="row">
<a
class="content footer-links"
href="https://github.com/org-roam/org-roam-ui"
>org-roam-ui</a
href="https://github.com/org-roam/org-roam-server"
>org-roam-server</a
>
</div>
</div>

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.1.0
#+subtitle: for version 2.0.0
#+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.1.0.
This manual is for Org-roam version 2.0.0.
#+BEGIN_QUOTE
Copyright (C) 2020-2021 Jethro Kuan <jethrokuan95@gmail.com>

View File

@@ -31,7 +31,7 @@ General Public License for more details.
@finalout
@titlepage
@title Org-roam User Manual
@subtitle for version 2.1.0
@subtitle for version 2.0.0
@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.1.0.
This manual is for Org-roam version 2.0.0.
@quotation
Copyright (C) 2020-2021 Jethro Kuan <jethrokuan95@@gmail.com>

View File

@@ -7,8 +7,8 @@
;; Leo Vivier <leo.vivier+dev@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org-roam "2.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org-roam "2.0"))
;; This file is NOT part of GNU Emacs.
@@ -36,18 +36,6 @@
;; One can use dailies for various purposes, e.g. journaling, fleeting notes,
;; scratch notes and whatever else you can came up with.
;;
;; To add new capture templates dedicated for dailies, specify ":kind daily" for
;; each of such template in `org-roam-capture-templates', e.g.
;;
;; (setq org-roam-capture-templates
;; '(("d" "daily" entry "* %?" :kind daily
;; :if-new (file+head "%<%Y-%m-%d>.org"
;; "#+title: %<%Y-%m-%d>\n"))))
;;
;; Note that in order for your daily files to properly integrate with the
;; calendar, each daily file should be named with a format understood by
;; `org-parse-time-string'.
;;
;;; Code:
(require 'f)
(require 'dash)
@@ -61,9 +49,8 @@
;;; Options
(defcustom org-roam-dailies-directory "daily/"
"Path to daily-notes. This path is relative to `org-roam-directory'.
Daily based capture templates will automatically start from this
path."
"Path to daily-notes.
This path is relative to `org-roam-directory'."
:group 'org-roam
:type 'string)
@@ -72,6 +59,74 @@ path."
:group 'org-roam
:type 'hook)
(defcustom org-roam-dailies-capture-templates
`(("d" "default" entry
"* %?"
:if-new (file+head "%<%Y-%m-%d>.org"
"#+title: %<%Y-%m-%d>\n")))
"Capture templates for daily-notes in Org-roam.
Note that for daily files to show up in the calendar, they have to be of format
\"org-time-string.org\".
See `org-roam-capture-templates' for the template documentation."
:group 'org-roam
:type '(repeat
(choice (list :tag "Multikey description"
(string :tag "Keys ")
(string :tag "Description"))
(list :tag "Template entry"
(string :tag "Keys ")
(string :tag "Description ")
(choice :tag "Capture Type " :value entry
(const :tag "Org entry" entry)
(const :tag "Plain list item" item)
(const :tag "Checkbox item" checkitem)
(const :tag "Plain text" plain)
(const :tag "Table line" table-line))
(choice :tag "Template "
(string)
(list :tag "File"
(const :format "" file)
(file :tag "Template file"))
(list :tag "Function"
(const :format "" function)
(function :tag "Template function")))
(plist :inline t
;; Give the most common options as checkboxes
:options (((const :format "%v " :if-new)
(choice :tag "Node location"
(list :tag "File"
(const :format "" file)
(string :tag " File"))
(list :tag "File & Head Content"
(const :format "" file+head)
(string :tag " File")
(string :tag " Head Content"))
(list :tag "File & Outline path"
(const :format "" file+olp)
(string :tag " File")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))
(list :tag "File & Head Content & Outline path"
(const :format "" file+head+olp)
(string :tag " File")
(string :tag " Head Content")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))))
((const :format "%v " :prepend) (const t))
((const :format "%v " :immediate-finish) (const t))
((const :format "%v " :jump-to-captured) (const t))
((const :format "%v " :empty-lines) (const 1))
((const :format "%v " :empty-lines-before) (const 1))
((const :format "%v " :empty-lines-after) (const 1))
((const :format "%v " :clock-in) (const t))
((const :format "%v " :clock-keep) (const t))
((const :format "%v " :clock-resume) (const t))
((const :format "%v " :time-prompt) (const t))
((const :format "%v " :tree-type) (const week))
((const :format "%v " :unnarrowed) (const t))
((const :format "%v " :table-line-pos) (string))
((const :format "%v " :kill-buffer) (const t))))))))
;;; Commands
;;;; Today
;;;###autoload
@@ -251,8 +306,8 @@ When GOTO is non-nil, go the note without creating an entry."
(let ((org-roam-directory (expand-file-name org-roam-dailies-directory org-roam-directory)))
(org-roam-capture- :goto (when goto '(4))
:node (org-roam-node-create)
:props (list :kind 'daily
:override-default-time time)))
:templates org-roam-dailies-capture-templates
:props (list :override-default-time time)))
(when goto (run-hooks 'org-roam-dailies-find-file-hook)))
(add-hook 'org-roam-capture-preface-hook #'org-roam-dailies--override-capture-time-h)
@@ -262,12 +317,6 @@ When GOTO is non-nil, go the note without creating an entry."
(when (org-roam-capture--get :override-default-time)
(org-capture-put :default-time (org-roam-capture--get :override-default-time)))))
(when (org-roam-capture--load-templates-p 'org-roam-dailies)
(push '("d" "daily" entry "* %?" :kind daily
:if-new (file+head "%<%Y-%m-%d>.org"
"#+title: %<%Y-%m-%d>\n"))
org-roam-capture-templates))
;;; Bindings
(defvar org-roam-dailies-map (make-sparse-keymap)
"Keymap for `org-roam-dailies'.")

View File

@@ -5,8 +5,8 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.0"))
;; This file is NOT part of GNU Emacs.
@@ -207,8 +207,7 @@ WITH RECURSIVE
connected_component(source) AS
(SELECT dest FROM links_of WHERE source = $s1 UNION
SELECT dest FROM links_of JOIN connected_component USING(source))
SELECT DISTINCT source, dest, type FROM links
WHERE source IN connected_component OR dest IN connected_component;"
SELECT source, dest, type FROM links WHERE source IN connected_component OR dest IN connected_component;"
"
WITH RECURSIVE
links_of(source, dest) AS
@@ -225,7 +224,7 @@ WITH RECURSIVE
AND json_array_length(cc.trace) < $s2)),
nodes(source) as (SELECT DISTINCT source
FROM connected_component GROUP BY source ORDER BY min(json_array_length(trace)))
SELECT DISTINCT source, dest, type FROM links WHERE source IN nodes OR dest IN nodes;")))
SELECT source, dest, type FROM links WHERE source IN nodes OR dest IN nodes;")))
(org-roam-db-query query id distance)))
(defun org-roam-graph--dot-option (option &optional wrap-key wrap-val)

View File

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

View File

@@ -4,8 +4,8 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.0"))
;; This file is NOT part of GNU Emacs.
@@ -32,21 +32,12 @@
;; 1. "roam-node": This protocol simply opens the node given by the node ID
;; 2. "roam-ref": This protocol creates or opens the node with the given REF
;;
;; To add new capture templates dedicated for the protocol, specify ":kind
;; protocol" for each of such template in `org-roam-capture-templates', e.g.
;;
;; (setq org-roam-capture-templates
;; '(("r" "ref" plain "%?" :kind protocol
;; :if-new (file+head "${slug}.org"
;; "#+title: ${title}")
;; :unnarrowed t)))
;;
;; You can find a detailed instruction on how to setup the protocol in the
;; manual for Org-roam.
;; You can find detailed instructions on how to setup the protocol in the
;; documentation for Org-roam.
;;
;;; Code:
(require 'org-protocol)
(require 'ol) ; to use `org-link-decode'
(require 'ol) ;; for org-link-decode
(require 'org-roam)
;;; Options
@@ -55,12 +46,73 @@
:type 'boolean
:group 'org-roam)
;;; Protocols
(mapc (lambda (spec) (cl-pushnew spec org-protocol-protocol-alist :test #'equal))
'(("org-roam-ref" :protocol "roam-ref" :function org-roam-protocol-open-ref)
("org-roam-node" :protocol "roam-node" :function org-roam-protocol-open-node)))
(defcustom org-roam-capture-ref-templates
'(("r" "ref" plain "%?"
:if-new (file+head "${slug}.org"
"#+title: ${title}")
:unnarrowed t))
"The Org-roam templates used during a capture from the roam-ref protocol.
See `org-roam-capture-templates' for the template documentation."
:group 'org-roam
:type '(repeat
(choice (list :tag "Multikey description"
(string :tag "Keys ")
(string :tag "Description"))
(list :tag "Template entry"
(string :tag "Keys ")
(string :tag "Description ")
(choice :tag "Capture Type " :value entry
(const :tag "Org entry" entry)
(const :tag "Plain list item" item)
(const :tag "Checkbox item" checkitem)
(const :tag "Plain text" plain)
(const :tag "Table line" table-line))
(choice :tag "Template "
(string)
(list :tag "File"
(const :format "" file)
(file :tag "Template file"))
(list :tag "Function"
(const :format "" function)
(function :tag "Template function")))
(plist :inline t
;; Give the most common options as checkboxes
:options (((const :format "%v " :if-new)
(choice :tag "Node location"
(list :tag "File"
(const :format "" file)
(string :tag " File"))
(list :tag "File & Head Content"
(const :format "" file+head)
(string :tag " File")
(string :tag " Head Content"))
(list :tag "File & Outline path"
(const :format "" file+olp)
(string :tag " File")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))
(list :tag "File & Head Content & Outline path"
(const :format "" file+head+olp)
(string :tag " File")
(string :tag " Head Content")
(list :tag "Outline path"
(repeat (string :tag "Headline"))))))
((const :format "%v " :prepend) (const t))
((const :format "%v " :immediate-finish) (const t))
((const :format "%v " :jump-to-captured) (const t))
((const :format "%v " :empty-lines) (const 1))
((const :format "%v " :empty-lines-before) (const 1))
((const :format "%v " :empty-lines-after) (const 1))
((const :format "%v " :clock-in) (const t))
((const :format "%v " :clock-keep) (const t))
((const :format "%v " :clock-resume) (const t))
((const :format "%v " :time-prompt) (const t))
((const :format "%v " :tree-type) (const week))
((const :format "%v " :unnarrowed) (const t))
((const :format "%v " :table-line-pos) (string))
((const :format "%v " :kill-buffer) (const t))))))))
;;;; roam-ref
;;; Handlers
(defun org-roam-protocol-open-ref (info)
"Process an org-protocol://roam-ref?ref= style url with INFO.
@@ -94,9 +146,29 @@ It opens or creates a note with the given ref.
:node (org-roam-node-create :title (plist-get info :title))
:info (list :ref (plist-get info :ref)
:body (plist-get info :body))
:props '(:kind protocol))
:templates org-roam-capture-ref-templates)
nil)
(defun org-roam-protocol-open-node (info)
"This handler simply opens the file with emacsclient.
INFO is a plist containing additional information passed by the protocol URL.
It should contain the FILE key, pointing to the path of the file to open.
Example protocol string:
org-protocol://roam-node?node=uuid"
(when-let ((node (plist-get info :node)))
(raise-frame)
(org-roam-node-visit (org-roam-populate (org-roam-node-create :id node))))
nil)
(push '("org-roam-ref" :protocol "roam-ref" :function org-roam-protocol-open-ref)
org-protocol-protocol-alist)
(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."
@@ -114,27 +186,6 @@ It opens or creates a note with the given ref.
(when-let ((ref (plist-get org-roam-capture--info :ref)))
(org-roam-ref-add ref)))
(when (org-roam-capture--load-templates-p 'org-roam-protocol)
(push '("r" "ref" plain "%?" :kind protocol
:if-new (file+head "${slug}.org"
"#+title: ${title}")
:unnarrowed t)
org-roam-capture-templates))
;;;; roam-node
(defun org-roam-protocol-open-node (info)
"This handler simply opens the file with emacsclient.
INFO is a plist containing additional information passed by the protocol URL.
It should contain the FILE key, pointing to the path of the file to open.
Example protocol string:
org-protocol://roam-node?node=uuid"
(when-let ((node (plist-get info :node)))
(raise-frame)
(org-roam-node-visit (org-roam-populate (org-roam-node-create :id node)) nil 'force))
nil)
(provide 'org-roam-protocol)

View File

@@ -5,8 +5,8 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1") (filenotify-recursive "0.0.1"))
;; This file is NOT part of GNU Emacs.
@@ -38,33 +38,6 @@
(defvar org-end-time-was-given)
;;; Options
(defcustom org-roam-capture-load-default-templates t
"Whether to include default Org-roam capture templates during the loading.
The value will also affect default templates provided by
Org-roam's extensions. It can be:
t
Include all the default capture templates provided by
Org-roam and its extensions.
nil
Don't include the default capture templates provided by
Org-roam and its extensions.
a list of symbols
Each symbol in the list corresponds to a `provide'd FEATURE,
for which the default capture templates will be automatically
included (if any). The list can start with a special value
`:not', in which case the logic will be inverted to
exclusion, e.g. (:not org-roam-dailies) won't include the
default templates provided by `org-roam-dailies', but will
include for other features."
:type '(choice
(const :tag "Yes" t)
(const :tag "No" nil)
(repeat :tag "List features" symbol))
:group 'org-roam)
(defcustom org-roam-capture-templates
'(("d" "default" plain "%?"
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
@@ -405,18 +378,9 @@ This variable is populated dynamically, and is only non-nil
during the Org-roam capture process.")
(defconst org-roam-capture--template-keywords (list :if-new :id :link-description :call-location
:region :kind :action)
:region)
"Keywords used in `org-roam-capture-templates' specific to Org-roam.")
(defun org-roam-capture--load-templates-p (feature)
"Return t if capture templates for FEATURE are allowed to be loaded.
See `org-roam-capture-load-default-templates' for more details."
(let ((user-value org-roam-capture-load-default-templates))
(pcase user-value
((pred consp) (org-roam--valid-option-p feature user-value))
((pred null) nil)
('t t))))
;;; Main entry point
;;;###autoload
(cl-defun org-roam-capture- (&key goto keys node info props templates)
@@ -426,18 +390,11 @@ INFO is a plist for filling up Org-roam's capture templates.
NODE is an `org-roam-node' construct containing information about the node.
PROPS is a plist containing additional Org-roam properties for each template.
TEMPLATES is a list of org-roam templates."
(let* ((props (thread-first props
(plist-put :call-location (point-marker))
(plist-put :action (or (plist-get props :action) (if goto 'goto 'capture)))
(plist-put :kind (or (plist-get props :kind) 'normal))))
(templates (org-roam-capture-get-templates
:action (plist-get props :action)
:kind (plist-get props :kind)
:templates (or templates org-roam-capture-templates)))
(let* ((props (plist-put props :call-location (point-marker)))
(org-capture-templates
(mapcar (lambda (template)
(org-roam-capture--convert-template template props))
templates))
(or templates org-roam-capture-templates)))
(org-roam-capture--node node)
(org-roam-capture--info info))
(when (and (not keys)
@@ -472,27 +429,6 @@ valid for the capture (i.e. initialization, and finalization of
the capture)."
(plist-get org-capture-plist :org-roam))
(cl-defun org-roam-capture-get-templates (&key (kind 'normal)
(action 'capture)
(templates org-roam-capture-templates))
"Return list of narrowed down capture TEMPLATES to a suitable KIND and ACTION."
(cl-loop for templ in templates
for templ-kind = (or (plist-get templ :kind) 'normal)
for templ-action = (or (plist-get templ :action) 'capture)
when (and (org-roam--valid-option-p kind templ-kind)
(org-roam--valid-option-p action templ-action))
if (org-roam-capture--dull-template-p templ) collect it
else collect templ))
(defun org-roam-capture--dull-template-p (template)
"Return prefix key declaration of TEMPLATE if it's a prefix key based one.
Unlike `org-capture', in Org-roam such templates can also
optionally specify dedicated `:kind' and `:action' values."
(cl-loop for property in (cddr template) by #'cddr
unless (memq property '(:kind :action))
return nil
finally return (cl-subseq template 0 2)))
(defun org-roam-capture--get (keyword)
"Get the value for KEYWORD from the `org-roam-capture-template'."
(plist-get (plist-get org-capture-plist :org-roam) keyword))

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.1.0
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1"))
;; This file is NOT part of GNU Emacs.
@@ -163,6 +163,9 @@ nodes." org-id-locations-file)
(define-obsolete-function-alias
'org-roam-teardown
'org-roam-db-autosync-disable "org-roam 2.0")
(define-obsolete-variable-alias
'org-roam-db-update-on-save
'org-roam-db-autosync-update-method "org-roam 2.0")
(define-obsolete-variable-alias
'org-roam-current-node
@@ -202,10 +205,6 @@ nodes." org-id-locations-file)
;;; Obsolete functions
(make-obsolete 'org-roam-get-keyword 'org-collect-keywords "org-roam 2.0")
;;; Obsolete variables
(make-obsolete-variable 'org-roam-dailies-capture-templates 'org-roam-capture-templates "org-roam 2.1")
(make-obsolete-variable 'org-roam-capture-ref-templates 'org-roam-capture-templates "org-roam 2.1")
(provide 'org-roam-compat)
;;; org-roam-compat.el ends here

View File

@@ -5,8 +5,8 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1") (filenotify-recursive "0.0.1"))
;; This file is NOT part of GNU Emacs.
@@ -31,6 +31,9 @@
;;
;;; Code:
(require 'org-roam)
(require 'filenotify)
(require 'filenotify-recursive)
(defvar org-outline-path-cache)
;;; Options
@@ -71,26 +74,38 @@ database."
:type 'function
:group 'org-roam)
(defcustom org-roam-db-update-on-save t
"If t, update the Org-roam database upon saving the file.
Disable this if your files are large and updating the database is
slow."
:type 'boolean
(defcustom org-roam-db-autosync-update-method
(if file-notify--library 'filenotify 'on-save)
"What method to use to keep Org-roam's database updated.
'filenotify
Update Org-roam upon detecting changes from the filesystem using
file watchers. Requires Emacs that's compiled with support for
file notifications.
'on-save
Update the database whenever Emacs buffer that visits an Org-roam
file is saved. Unlike `filenotify' this won't be able to react to
external changes in the filesystem.
nil
Do not automatically update the Org-roam database."
:type '(choice (const :tag "Filenotify" filenotify)
(const :tag "On save" onsave)
(const :tag "Do not autoupdate" nil))
:group 'org-roam)
;;; Variables
;;; Initialization
(defconst org-roam-db-version 16)
;; TODO Rename this
(defvar org-roam-db--connection (make-hash-table :test #'equal)
"Database connection to Org-roam database.")
(defconst org-roam--sqlite-available-p
(with-demoted-errors "Org-roam initialization: %S"
(emacsql-sqlite-ensure-binary)
t))
(defvar org-roam-db--connection (make-hash-table :test #'equal)
"Database connection to Org-roam database.")
;;; Core Functions
(defun org-roam-db--get-connection ()
"Return the database connection, if any."
(gethash (expand-file-name org-roam-directory)
@@ -474,6 +489,8 @@ If UPDATE-P is non-nil, first remove the file in the database."
If the file does not exist anymore, remove it from the cache.
If the file exists, update the cache with information."
(setq file-path (or file-path (buffer-file-name (buffer-base-buffer))))
(org-roam-db-clear-file file-path)
(when (file-exists-p file-path)
(let ((content-hash (org-roam-db--file-hash file-path))
(db-hash (caar (org-roam-db-query [:select hash :from files
:where (= file $s1)] file-path))))
@@ -481,7 +498,6 @@ If the file exists, update the cache with information."
(org-roam-with-file file-path nil
(save-excursion
(org-set-regexps-and-options 'tags-only)
(org-roam-db-clear-file)
(org-roam-db-insert-file)
(org-roam-db-insert-file-node)
(setq org-outline-path-cache nil)
@@ -492,7 +508,7 @@ If the file exists, update the cache with information."
#'org-roam-db-insert-refs))
(setq org-outline-path-cache nil)
(org-roam-db-map-links
(list #'org-roam-db-insert-link)))))))
(list #'org-roam-db-insert-link))))))))
;;;###autoload
(defun org-roam-db-sync (&optional force)
@@ -527,6 +543,19 @@ If FORCE, force a rebuild of the cache from scratch."
(dolist (file modified-files)
(org-roam-db-update-file file))))))
;;;###autoload
(defun org-roam-db-autosync-enable ()
"Activate `org-roam-db-autosync-mode'."
(org-roam-db-autosync-mode +1))
(defun org-roam-db-autosync-disable ()
"Deactivate `org-roam-db-autosync-mode'."
(org-roam-db-autosync-mode -1))
(defun org-roam-db-autosync-toggle ()
"Toggle `org-roam-db-autosync-mode' enabled/disabled."
(org-roam-db-autosync-mode 'toggle))
;;;###autoload
(define-minor-mode org-roam-db-autosync-mode
"Global minor mode to keep your Org-roam session automatically synchronized.
@@ -540,37 +569,101 @@ database, see `org-roam-db-sync' command."
:group 'org-roam
:global t
:init-value nil
(let ((enabled org-roam-db-autosync-mode))
(let ((enabled org-roam-db-autosync-mode)
(update-method org-roam-db-autosync-update-method))
(cond
(enabled
(add-hook 'find-file-hook #'org-roam-db-autosync--setup-file-h)
(org-roam-db-autosync--update-method :enable update-method)
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
(advice-add #'rename-file :after #'org-roam-db-autosync--rename-file-a)
(advice-add #'delete-file :before #'org-roam-db-autosync--delete-file-a)
(org-roam-db-sync))
(t
(remove-hook 'find-file-hook #'org-roam-db-autosync--setup-file-h)
(org-roam-db-autosync--update-method :disable update-method)
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
(advice-remove #'rename-file #'org-roam-db-autosync--rename-file-a)
(advice-remove #'delete-file #'org-roam-db-autosync--delete-file-a)
(org-roam-db--close-all)
;; Disable local hooks for all org-roam buffers
(dolist (buf (org-roam-buffer-list))
(with-current-buffer buf
(remove-hook 'after-save-hook #'org-roam-db-autosync--try-update-on-save-h t)))))))
;;;###autoload
(defun org-roam-db-autosync-enable ()
"Activate `org-roam-db-autosync-mode'."
(org-roam-db-autosync-mode +1))
(defvar org-roam-db-autosync--filenotify-descriptors (list)
"An alist mapping watched Org-roam directories to `filenotify-recursive' uuid.")
(defun org-roam-db-autosync-disable ()
"Deactivate `org-roam-db-autosync-mode'."
(org-roam-db-autosync-mode -1))
(defun org-roam-db-autosync--update-method (state method)
"Change the current `org-roam-db-autosync-update-method' to METHOD.
STATE should be either :enable or :disable, while METHOD should
be on of the values from `org-roam-db-autosync-update-method'."
(unless (memq method '(filenotify on-save nil))
(user-error "Unknown `org-roam-db-autosync-update-method': %s" method))
(cl-ecase state
(:enable
(unless (eq method org-roam-db-autosync-update-method)
;; Clean up the old method in case of hot swap.
(org-roam-db-autosync--update-method :disable org-roam-db-autosync-update-method))
(setq org-roam-db-autosync-update-method method)
(pcase method
('filenotify
(cl-pushnew
(cons org-roam-directory
(fnr-add-watch org-roam-directory
'(change)
#'org-roam-db-autosync--filenotify-update
"\\`\\.")) ; Ignore directories that start with "."
org-roam-db-autosync--filenotify-descriptors))
('on-save
(add-hook 'org-roam-find-file-hook #'org-roam-db-autosync--setup-update-on-save-h)
(advice-add #'rename-file :after #'org-roam-db-autosync--rename-file-a)
(advice-add #'delete-file :before #'org-roam-db-autosync--delete-file-a))
((pred nilp)
t)))
(:disable
(pcase org-roam-db-autosync-update-method
('filenotify
(cl-loop for entry in org-roam-db-autosync--filenotify-descriptors
for _dir = (car entry)
for uuid = (cdr entry)
do (fnr-rm-watch uuid))
(setq org-roam-db-autosync--filenotify-descriptors nil))
('on-save
(remove-hook 'org-roam-find-file-hook #'org-roam-db-autosync--setup-update-on-save-h)
(advice-remove #'rename-file #'org-roam-db-autosync--rename-file-a)
(advice-remove #'delete-file #'org-roam-db-autosync--delete-file-a))
((pred nilp)
t)))))
(defun org-roam-db-autosync-toggle ()
"Toggle `org-roam-db-autosync-mode' enabled/disabled."
(org-roam-db-autosync-mode 'toggle))
(defun org-roam-db-autosync--filenotify-update (event)
"Update Org-roam's database according to EVENT sent by `filenotify'."
(cl-destructuring-bind (_descriptor action &rest files) event
(cond
((cl-find-if #'org-roam-file-p files)
(mapc #'org-roam-db-update-file files))
((memq action '(created deleted renamed))
(apply (intern (format "org-roam-db-autosync--update-%s-dir" action)) files)))))
(defun org-roam-db-autosync--update-created-dir (dir)
"Add entries from Org-roam files under DIR to the database."
(when (file-directory-p dir)
(let ((files (let ((org-roam-directory dir))
(org-roam-list-files))))
(emacsql-with-transaction (org-roam-db)
(mapc #'org-roam-db-update-file files)))))
(defun org-roam-db-autosync--update-deleted-dir (dir)
"Invalidate entries related to Org-roam files under DIR from the database."
(let ((dir (thread-first dir
;; Ensure that separator is present in the name
(directory-file-name)
(concat (f-path-separator))
;; Follow the same format as the rest of the files in the database
(expand-file-name))))
(org-roam-db-query [:delete :from files :where (like file $s1)]
(concat dir "%"))))
(defun org-roam-db-autosync--update-renamed-dir (old-name new-name)
"Invalidate and then add files renamed from OLD-NAME directory to NEW-NAME."
(org-roam-db-autosync--update-deleted-dir old-name)
(org-roam-db-autosync--update-created-dir new-name))
(defun org-roam-db-autosync--delete-file-a (file &optional _trash)
"Maintain cache consistency when file deletes.
@@ -601,14 +694,9 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
"Setup the current buffer if it visits an Org-roam file."
(when (org-roam-file-p) (run-hooks 'org-roam-find-file-hook)))
(add-hook 'org-roam-find-file-hook #'org-roam-db-autosync--setup-update-on-save-h)
(defun org-roam-db-autosync--setup-update-on-save-h ()
"Setup the current buffer to update the DB after saving the current file."
(add-hook 'after-save-hook #'org-roam-db-autosync--try-update-on-save-h nil t))
(defun org-roam-db-autosync--try-update-on-save-h ()
"If appropriate, update the database for the current file after saving buffer."
(when org-roam-db-update-on-save (org-roam-db-update-file)))
(add-hook 'after-save-hook #'org-roam-db-update-file nil t))
;;; Diagnostics
(defun org-roam-db-diagnose-node ()

View File

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

View File

@@ -5,8 +5,8 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1") (filenotify-recursive "0.0.1"))
;; This file is NOT part of GNU Emacs.
@@ -379,8 +379,7 @@ the same time:
The preview content comes from FILE, and the link as at POINT.")
(defun org-roam-preview-visit (file point &optional other-window)
"Visit FILE at POINT and return the visited buffer.
With OTHER-WINDOW non-nil do so in another window.
"Visit FILE at POINT. With OTHER-WINDOW non-nil do so in another window.
In interactive calls OTHER-WINDOW is set with
`universal-argument'."
(interactive (list (org-roam-buffer-file-at-point 'assert)
@@ -390,12 +389,11 @@ In interactive calls OTHER-WINDOW is set with
(display-buffer-fn (if other-window
#'switch-to-buffer-other-window
#'pop-to-buffer-same-window)))
(funcall display-buffer-fn buf)
(with-current-buffer buf
(widen)
(goto-char point))
(when (org-invisible-p) (org-show-context))
buf))
(funcall display-buffer-fn buf)
(when (org-invisible-p) (org-show-context))))
(defun org-roam-preview-get-contents (file point)
"Get preview content for FILE at POINT."
@@ -542,20 +540,22 @@ Sorts by title."
(defun org-roam-reflinks-get (node)
"Return the reflinks for NODE."
(let ((refs (org-roam-db-query [:select :distinct [refs:ref links:source links:pos links:properties]
:from refs
:left-join links
:where (= refs:node-id $s1)
:and (= links:dest refs:ref)]
(let ((refs (org-roam-db-query [:select [ref] :from refs
:where (= node-id $s1)]
(org-roam-node-id node)))
links)
(pcase-dolist (`(,ref ,source-id ,pos ,properties) refs)
(pcase-dolist (`(,ref) refs)
(pcase-dolist (`(,source-id ,pos ,properties) (org-roam-db-query
[:select [source pos properties]
:from links
:where (= dest $s1)]
ref))
(push (org-roam-populate
(org-roam-reflink-create
:source-node (org-roam-node-create :id source-id)
:ref ref
:point pos
:properties properties)) links))
:properties properties)) links)))
links))
(defun org-roam-reflinks-sort (a b)
@@ -593,7 +593,7 @@ Sorts by title."
"A `magit-section' used by `org-roam-mode' to contain grep output.")
(defun org-roam-grep-visit (file &optional other-window row col)
"Visit FILE at row ROW (if any) and column COL (if any). Return the buffer.
"Visits FILE. If ROW, move to the row, and if COL move to the COL.
With OTHER-WINDOW non-nil (in interactive calls set with
`universal-argument') display the buffer in another window
instead."
@@ -605,7 +605,6 @@ instead."
(display-buffer-fn (if other-window
#'switch-to-buffer-other-window
#'pop-to-buffer-same-window)))
(funcall display-buffer-fn buf)
(with-current-buffer buf
(widen)
(goto-char (point-min))
@@ -613,8 +612,8 @@ instead."
(forward-line (1- row)))
(when col
(forward-char (1- col))))
(when (org-invisible-p) (org-show-context))
buf))
(funcall display-buffer-fn buf)
(when (org-invisible-p) (org-show-context))))
;;;; Unlinked references
(defvar org-roam-unlinked-references-result-re

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.1.0
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (magit-section "2.90.1"))
;; This file is NOT part of GNU Emacs.
@@ -76,21 +76,6 @@ It takes a single argument NODE, which is an `org-roam-node' construct."
(const :tag "file-atime" file-atime))
:group 'org-roam)
(defcustom org-roam-node-template-prefixes
'(("tags" . "#")
("todo" . "t:"))
"Prefixes for each of the node's properties.
This is used in conjunction with
`org-roam-node-display-template': in minibuffer completions the
node properties will be prefixed with strings in this variable,
acting as a query language of sorts.
For example, if a node has tags (\"foo\" \"bar\") and the alist
has the entry (\"tags\" . \"#\"), these will appear as
\"#foo #bar\"."
:group 'org-roam
:type '(alist))
(defcustom org-roam-ref-annotation-function #'org-roam-ref-read--annotation
"This function used to attach annotations for `org-roam-ref-read'.
It takes a single argument REF, which is a propertized string.")
@@ -180,7 +165,7 @@ populated."
(magit-section-up)
(org-roam-node-at-point)))
(t (org-with-wide-buffer
(org-back-to-heading-or-point-min t)
(org-back-to-heading-or-point-min)
(while (and (not (org-roam-db-node-p))
(not (bobp)))
(org-roam-up-heading-or-point-min))
@@ -369,31 +354,23 @@ 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."
(defun org-roam-node-find-noselect (node)
"Navigate to the point for NODE, and return the buffer."
(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))))
(goto-char (org-roam-node-point node)))
buf))
(defun org-roam-node-visit (node &optional other-window force)
(defun org-roam-node-visit (node &optional other-window)
"From the current buffer, visit NODE. Return the visited buffer.
Display the buffer in the selected window. With a prefix
argument OTHER-WINDOW display the buffer in another window
instead.
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))
instead."
(interactive (list (org-roam-node-at-point t) current-prefix-arg))
(let ((buf (org-roam-node-find-noselect node))
(display-buffer-fn (if other-window
#'switch-to-buffer-other-window
#'pop-to-buffer-same-window)))
@@ -478,51 +455,50 @@ The displayed title is formatted according to `org-roam-node-display-template'."
(let ((candidate-main (org-roam-node-read--format-entry node (1- (frame-width)))))
(cons (propertize candidate-main 'node node) node)))
(defun org-roam-node-read--tags-to-str (tags)
"Convert list of TAGS into a string."
(mapconcat (lambda (s) (concat "#" s)) tags " "))
(defun org-roam-node-read--format-entry (node width)
"Formats NODE for display in the results list.
WIDTH is the width of the results list.
Uses `org-roam-node-display-template' to format the entry."
(pcase-let ((`(,tmpl . ,tmpl-width)
(org-roam-node-read--process-display-format org-roam-node-display-template)))
(let ((fmt (org-roam-node-read--process-display-format org-roam-node-display-template)))
(org-roam-format-template
tmpl
(car fmt)
(lambda (field _default-val)
(pcase-let* ((`(,field-name ,field-width) (split-string field ":"))
(let* ((field (split-string field ":"))
(field-name (car field))
(field-width (cadr field))
(getter (intern (concat "org-roam-node-" field-name)))
(field-value (funcall getter node)))
(field-value (or (funcall getter node) "")))
(when (and (equal field-name "tags")
field-value)
(setq field-value (org-roam-node-read--tags-to-str field-value)))
(when (and (equal field-name "file")
field-value)
(setq field-value (file-relative-name field-value org-roam-directory)))
(when (and (equal field-name "olp")
field-value)
(setq field-value (string-join field-value " > ")))
(when (and field-value (not (listp field-value)))
(setq field-value (list field-value)))
(setq field-value (mapconcat
(lambda (v)
(concat (or (cdr (assoc field-name org-roam-node-template-prefixes))
"")
v))
field-value " "))
(setq field-width (cond
((not field-width)
field-width)
((string-equal field-width "*")
(- width tmpl-width))
((>= (string-to-number field-width) 0)
(string-to-number field-width))))
(if (not field-width)
field-value
(setq field-width (string-to-number field-width))
(let ((display-string (truncate-string-to-width
field-value
(if (> field-width 0)
field-width
(- width (cdr fmt)))
0 ?\s)))
;; Setting the display (which would be padded out to the field length) for an
;; empty string results in an empty string and misalignment for candidates that
;; don't have some field. This uses the actual display string, made of spaces
;; when the field-value is "" so that we actually take up space.
(let ((display-string (if field-width
(truncate-string-to-width field-value field-width 0 ?\s)
field-value)))
(if (equal field-value "")
display-string
(if (not (equal field-value ""))
;; Remove properties from the full candidate string, otherwise the display
;; formatting with pre-prioritized field-values gets messed up.
(propertize (substring-no-properties field-value) 'display display-string))))))))
(propertize (substring-no-properties field-value) 'display display-string)
display-string))))))))
(defun org-roam-node-read--process-display-format (format)
"Pre-calculate minimal widths needed by the FORMAT string."
@@ -621,7 +597,7 @@ Assumes that the cursor was put where the link is."
(cond
((org-roam-node-file node)
(org-mark-ring-push)
(org-roam-node-visit node nil 'force)
(org-roam-node-visit node)
t)
(t nil))))))
@@ -635,7 +611,7 @@ Assumes that the cursor was put where the link is."
(when org-roam-link-auto-replace
(org-roam-link-replace-at-point))
(org-mark-ring-push)
(org-roam-node-visit node nil 'force))
(org-roam-node-visit node))
(org-roam-capture-
:node (org-roam-node-create :title title-or-alias)
:props '(:finalize find-file))))
@@ -827,7 +803,7 @@ If region is active, then use it instead of the node at point."
"Convert current subtree at point to a node, and extract it into a new file."
(interactive)
(save-excursion
(org-back-to-heading-or-point-min t)
(org-back-to-heading-or-point-min)
(when (bobp) (user-error "Already a top-level node"))
(org-id-get-create)
(save-buffer)
@@ -865,7 +841,7 @@ If region is active, then use it instead of the node at point."
Recursively traverses up the headline tree to find the
first encapsulating ID."
(org-with-wide-buffer
(org-back-to-heading-or-point-min t)
(org-back-to-heading-or-point-min)
(while (and (not (org-roam-db-node-p))
(not (bobp)))
(org-roam-up-heading-or-point-min))

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.1.0
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4"))
;; This file is NOT part of GNU Emacs.
@@ -32,8 +32,6 @@
;;
;;; Code:
(require 'org-roam)
;;; String utilities
;; TODO Refactor this.
(defun org-roam-replace-string (old new s)
@@ -105,29 +103,6 @@ If FILE, set `default-directory' to FILE's directory and insert its contents."
(setq-local default-directory (file-name-directory ,file)))
,@body)))))
;;; Processing options
(defun org-roam--valid-option-p (option choice)
"Return t if OPTION satisfies CHOICE, else nil.
OPTION is a symbol, while CHOICE is either, a symbol or a list of
symbols that can optionally start with `:not' keyword.
If CHOICE is a list that indicates negation, then the function
will return t if OPTION isn't in the list. Otherwise it will
return t is OPTION is present in the CHOICE.
When CHOICE is a symbol, it will behave like `eq', except of
special 'any value, in which case it will always return t,
independently OPTION's value.
CHOICE as a list can too contain 'any, in which case any OPTION
value will be considered as part of the CHOICE, with respect to
negation."
(let* ((choices (-list choice))
(intersection (-intersection (list option 'any) choices))
(negation (eq :not (car choices))))
(or (and intersection (not negation))
(and (not intersection) negation))))
;;; Formatting
(defun org-roam-format-template (template replacer)
"Format TEMPLATE with the function REPLACER.
@@ -313,20 +288,8 @@ If VAL is not specified, user is prompted to select a value."
"Return `org-roam' version.
Interactively, or when MESSAGE is non-nil, show in the echo area."
(interactive)
(let* ((toplib (or load-file-name buffer-file-name))
gitdir topdir version)
(unless (and toplib (equal (file-name-nondirectory toplib) "org-roam-utils.el"))
(setq toplib (locate-library "org-roam-utils.el")))
(setq toplib (and toplib (org-roam--straight-chase-links toplib)))
(when toplib
(setq topdir (file-name-directory toplib)
gitdir (expand-file-name ".git" topdir)))
(when (file-exists-p gitdir)
(setq version
(let ((default-directory topdir))
(shell-command-to-string "git describe --tags --dirty --always"))))
(unless version
(setq version (with-temp-buffer
(let* ((version
(with-temp-buffer
(insert-file-contents-literally (locate-library "org-roam.el"))
(goto-char (point-min))
(save-match-data
@@ -337,21 +300,6 @@ Interactively, or when MESSAGE is non-nil, show in the echo area."
(message "%s" version)
version)))
(defun org-roam--straight-chase-links (filename)
"Chase links in FILENAME until a name that is not a link.
This is the same as `file-chase-links', except that it also
handles fake symlinks that are created by the package manager
straight.el on Windows.
See <https://github.com/raxod502/straight.el/issues/520>."
(when (and (bound-and-true-p straight-symlink-emulation-mode)
(fboundp 'straight-chase-emulated-symlink))
(when-let ((target (straight-chase-emulated-symlink filename)))
(unless (eq target 'broken)
(setq filename target))))
(file-chase-links filename))
;;;###autoload
(defun org-roam-diagnostics ()
"Collect and print info for `org-roam' issues."

View File

@@ -5,8 +5,8 @@
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/org-roam/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 2.1.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1"))
;; Version: 2.0.0
;; Package-Requires: ((emacs "26.1") (dash "2.13") (f "0.17.2") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "2.90.1") (filenotify-recursive "0.0.1"))
;; This file is NOT part of GNU Emacs.
@@ -94,6 +94,7 @@
(eval-when-compile
(require 'subr-x))
(require 'org-roam-utils)
(require 'org-roam-compat)
;;; Options
@@ -309,7 +310,6 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
(provide 'org-roam)
(cl-eval-when (load eval)
(require 'org-roam-utils)
(require 'org-roam-db)
(require 'org-roam-node)
(require 'org-roam-capture)