mirror of
https://github.com/org-roam/org-roam
synced 2025-08-01 12:17:21 -05:00
Compare commits
12 Commits
v2.0.0
...
migration/
Author | SHA1 | Date | |
---|---|---|---|
f5b8144c31 | |||
e997c017de | |||
63450e9eaf | |||
da02453ab1 | |||
bbf1d97eb0 | |||
7d9fcf5288 | |||
d0be7f3b2a | |||
363dca1765 | |||
4c5a041556 | |||
5e42d854c1 | |||
681873759d | |||
2168490d5a |
@ -86,6 +86,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/)
|
||||
- [Sidharth Arya](https://sidhartharya.github.io/braindump/index.html)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
107
doc/org-roam.org
107
doc/org-roam.org
@ -134,7 +134,7 @@ A slip-box requires a method for quickly capturing ideas. These are called
|
||||
*fleeting notes*: they are simple reminders of information or ideas that will
|
||||
need to be processed later on, or trashed. This is typically accomplished using
|
||||
~org-capture~ (see info:org#Capture), or using Org-roam's daily notes
|
||||
functionality (see [[*Daily-notes][Daily-notes]]). This provides a central inbox for collecting
|
||||
functionality (see [[id:4eae8552-95e1-4e4a-b7b7-2c53433730ea][Org-roam Dailies]]). This provides a central inbox for collecting
|
||||
thoughts, to be processed later into permanent notes.
|
||||
|
||||
*Permanent notes*
|
||||
@ -198,8 +198,6 @@ using:
|
||||
M-x package-install RET org-roam RET
|
||||
#+END_EXAMPLE
|
||||
|
||||
Now see [[*Post-Installation Tasks][Post-Installation Tasks]].
|
||||
|
||||
** Installing from Apt
|
||||
|
||||
Users of Debian 11 or later or Ubuntu 20.10 or later can simply install Org-roam
|
||||
@ -248,7 +246,7 @@ dependencies that it requires. These include:
|
||||
- s
|
||||
- org
|
||||
- emacsql
|
||||
- emacsql-sqlite3
|
||||
- emacsql-sqlite
|
||||
|
||||
You can install this manually as well, or get the latest version from MELPA. You
|
||||
may wish to use [[https://github.com/jwiegley/use-package][use-package]], [[https://github.com/raxod502/straight.el][straight.el]] to help manage this.
|
||||
@ -291,23 +289,43 @@ file:
|
||||
install-info /path/to/my/info/files/org-roam.info /path/to/my/info/files/dir
|
||||
#+end_src
|
||||
|
||||
** Post-Installation Tasks
|
||||
** Installation Troubleshooting
|
||||
*** C Compiler
|
||||
Org-roam relies on an Emacs package called ~emacsql~ and ~emacsql-sqlite~ to
|
||||
work with the ~sqlite~ database. Both of them should be installed automatically
|
||||
in your Emacs environment as a prerequisite for Org-roam when you install it.
|
||||
|
||||
Org-roam requires ~sqlite3~ to be locatable by Emacs (i.e. on ~exec-path~).
|
||||
Please ensure that ~sqlite3~ is installed appropriately on your operating
|
||||
system. You can verify that this is the case by executing [fn:2]:
|
||||
~emacsql-sqlite~ requires a C compiler (e.g. ~gcc~ or ~clang~) to be present in
|
||||
your computer. How to install a C compiler depends on the OS that you use.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(executable-find "sqlite3")
|
||||
#+END_SRC
|
||||
- For Windows:
|
||||
|
||||
If you have ~sqlite3~ installed, and ~executable-find~ still reports ~nil~, then
|
||||
the path to the executable is not a member of the Emacs variable ~exec-path~.
|
||||
Rectify this by manually adding the path within your Emacs configuration:
|
||||
There are various ways to install one, depending on how you have installed
|
||||
Emacs. If you use Emacs within a Cygwin or MinGW environment, then you should
|
||||
install a compiler using their respective package manager.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'exec-path "path/to/sqlite3")
|
||||
#+END_SRC
|
||||
If you have installed your Emacs from the [[https://www.gnu.org/software/emacs/][GNU Emacs website]], then the easiest way
|
||||
is to use [[https://www.msys2.org/][MSYS2]] as at the time of this writing:
|
||||
|
||||
1. Use the installer in the official website and install MSYS2
|
||||
2. Run MSYS2
|
||||
3. In the command-line tool, type the following and answer "Y" to proceed:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
pacman -S gcc
|
||||
#+END_SRC
|
||||
|
||||
Note that you do not need to manually set the PATH for MSYS2; the
|
||||
installer automatically takes care of it for you.
|
||||
|
||||
4. Open Emacs and call ~M-x org-roam-setup~
|
||||
|
||||
This will automatically start compiling ~emacsql-sqlite~; you should see a
|
||||
message in minibuffer. It may take a while until compilation completes. Once
|
||||
complete, you should see a new file ~emacsql-sqlite.exe~ created in a subfolder
|
||||
named ~sqlite~ under ~emacsql-sqlite~ installation folder. It's typically in
|
||||
your Emacs configuration folder like this:
|
||||
~/.config/emacs/elpa/emacsql-sqlite-20190727.1710/sqlite~
|
||||
|
||||
* Getting Started
|
||||
** The Org-roam Node
|
||||
@ -376,7 +394,7 @@ Org-roam is available on startup, place this in your Emacs configuration:
|
||||
(org-roam-setup)
|
||||
#+end_src
|
||||
|
||||
To build the cache manually, run ~M-x org-roam-db-build-cache~. Cache builds may
|
||||
To build the cache manually, run ~M-x org-roam-db-sync~. Cache builds may
|
||||
take a while the first time, but subsequent builds are often instantaneous
|
||||
because they only reprocess modified files.
|
||||
|
||||
@ -478,7 +496,7 @@ section-specific commands such as ~org-roam-node-visit~.
|
||||
There are currently 3 provided widget types:
|
||||
|
||||
- Backlinks :: View (preview of) nodes that link to this node
|
||||
- Reference Links :: Nodes that reference this node (see [[id:57c1f991-be38-4fab-b27d-60227047f3b7][Refs]])
|
||||
- Reference Links :: Nodes that reference this node (see [[*Refs][Refs]])
|
||||
- Unlinked references :: View nodes that contain text that match the nodes
|
||||
title/alias but are not linked
|
||||
|
||||
@ -501,11 +519,11 @@ the user. The author's recommended configuration is as follows:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(add-to-list 'display-buffer-alist
|
||||
'(("\\*org-roam\\*"
|
||||
(display-buffer-in-direction)
|
||||
(direction . right)
|
||||
(window-width . 0.33)
|
||||
(window-height . fit-window-to-buffer))))
|
||||
'("\\*org-roam\\*"
|
||||
(display-buffer-in-direction)
|
||||
(direction . right)
|
||||
(window-width . 0.33)
|
||||
(window-height . fit-window-to-buffer)))
|
||||
#+end_src
|
||||
|
||||
Crucially, the window is a regular window (not a side-window), and this allows
|
||||
@ -515,6 +533,20 @@ for predictable navigation:
|
||||
Org-roam buffer.
|
||||
- ~C-u RET~ navigates to thing-at-point in the other window.
|
||||
|
||||
For users that prefer using a side-window for the org-roam buffer, the following
|
||||
example configuration should provide a good starting point:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(add-to-list 'display-buffer-alist
|
||||
'("\\*org-roam\\*"
|
||||
(display-buffer-in-side-window)
|
||||
(side . right)
|
||||
(slot . 0)
|
||||
(window-width . 0.33)
|
||||
(window-parameters . ((no-other-window . t)
|
||||
(no-delete-other-windows . t)))))
|
||||
#+end_src
|
||||
|
||||
** TODO Styling the Org-roam buffer
|
||||
* Node Properties
|
||||
** Standard Org properties
|
||||
@ -587,7 +619,7 @@ With the above example, if another node links to https://www.google.com/, it
|
||||
will show up as a “reference backlink”.
|
||||
|
||||
These keys also come in useful for when taking website notes, using the
|
||||
~roam-ref~ protocol (see [[*Roam Protocol][Roam Protocol]]).
|
||||
~roam-ref~ protocol (see [[*Org-roam Protocol][Roam Protocol]]).
|
||||
|
||||
You may assign multiple refs to a single node, for example when you want
|
||||
multiple papers in a series to share the same note, or an article has a citation
|
||||
@ -664,6 +696,10 @@ extension in your Org-roam capture templates. For example:
|
||||
:unnarrowed t)))
|
||||
#+end_src
|
||||
|
||||
Note that the Org-roam database stores metadata information in plain-text
|
||||
(headline text, for example), so if this information is private to you then you
|
||||
should also ensure the database is encrypted.
|
||||
|
||||
* Org-roam Protocol
|
||||
|
||||
Org-roam provides extensions for capturing content from external applications
|
||||
@ -838,7 +874,7 @@ where ~template~ is the template key for a template in
|
||||
~org-roam-capture-ref-templates~ (see [[*The Templating System][The Templating System]]). These templates
|
||||
should contain a ~#+roam_key: ${ref}~ in it.
|
||||
|
||||
* The Org-roam Templating System
|
||||
* The Templating System
|
||||
|
||||
Org-roam extends the ~org-capture~ system, providing a smoother note-taking
|
||||
experience. However, these extensions mean Org-roam capture templates are
|
||||
@ -902,7 +938,7 @@ strings. ~${foo}~'s substitution is performed as follows:
|
||||
|
||||
Org-roam provides basic graphing capabilities to explore interconnections
|
||||
between notes, in ~org-roam-graph~. This is done by performing SQL queries and
|
||||
generating images using [[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*Roam Protocol][Roam
|
||||
generating images using [[https://graphviz.org/][Graphviz]]. The graph can also be navigated: see [[*Org-roam Protocol][Roam
|
||||
Protocol]].
|
||||
|
||||
The entry point to graph creation is ~org-roam-graph~.
|
||||
@ -971,9 +1007,12 @@ for customizable options.
|
||||
Example: ~'(("dir" . "back"))~
|
||||
|
||||
* Org-roam Dailies
|
||||
:PROPERTIES:
|
||||
:ID: 4eae8552-95e1-4e4a-b7b7-2c53433730ea
|
||||
:END:
|
||||
|
||||
Org-roam provides journaling capabilities akin to
|
||||
[[#org-journal][Org-journal]] with ~org-roam-dailies~.
|
||||
Org-journal with ~org-roam-dailies~.
|
||||
|
||||
** Configuration
|
||||
|
||||
@ -1011,7 +1050,7 @@ See [[*The Templating System][The Templating System]] for creating new templates
|
||||
|
||||
When ~goto~ is non-nil, go to the note without creating an entry.
|
||||
|
||||
- Function: ~org-roam-dailies-find-today~
|
||||
- Function: ~org-roam-dailies-goto-today~
|
||||
|
||||
Find the daily note for today, creating it if necessary.
|
||||
|
||||
@ -1023,7 +1062,7 @@ There are variants of those commands for ~-yesterday~ and ~-tomorrow~:
|
||||
|
||||
With numeric argument ~n~, use the daily note ~n~ days in the past.
|
||||
|
||||
- Function: ~org-roam-dailies-find-yesterday~
|
||||
- Function: ~org-roam-dailies-goto-yesterday~
|
||||
|
||||
With numeric argument N, use the daily-note N days in the future.
|
||||
|
||||
@ -1038,7 +1077,7 @@ There are also commands which allow you to use Emacs’s ~calendar~ to find the
|
||||
With a 'C-u' prefix or when ~goto~ is non-nil, go the note without
|
||||
creating an entry.
|
||||
|
||||
- Function: ~org-roam-dailies-find-date~
|
||||
- Function: ~org-roam-dailies-goto-date~
|
||||
|
||||
Find the daily note for a date using the calendar, creating it if necessary.
|
||||
|
||||
@ -1048,11 +1087,11 @@ There are also commands which allow you to use Emacs’s ~calendar~ to find the
|
||||
|
||||
Find and open ~org-roam-dailies-directory~.
|
||||
|
||||
- Function: ~org-roam-dailies-find-previous-note~
|
||||
- Function: ~org-roam-dailies-goto-previous-note~
|
||||
|
||||
When in an daily-note, find the previous one.
|
||||
|
||||
- Function: ~org-roam-dailies-find-next-note~
|
||||
- Function: ~org-roam-dailies-goto-next-note~
|
||||
|
||||
When in an daily-note, find the next one.
|
||||
* Performance Optimization
|
||||
@ -1128,7 +1167,7 @@ The Deft interface can slow down quickly when the number of files get huge.
|
||||
|
||||
[[https://github.com/bastibe/org-journal][Org-journal]] provides journaling capabilities to Org-mode. A lot of its
|
||||
functionalities have been incorporated into Org-roam under the name
|
||||
[[*Daily-notes][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose
|
||||
[[*Org-roam Dailies][~org-roam-dailies~]]. It remains a good tool if you want to isolate your verbose
|
||||
journal entries from the ideas you would write on a scratchpad.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
|
2327
doc/org-roam.texi
2327
doc/org-roam.texi
File diff suppressed because it is too large
Load Diff
@ -33,7 +33,90 @@
|
||||
;;; Code:
|
||||
;;;; Library Requires
|
||||
|
||||
;;; Backports
|
||||
;; REVIEW Remove when 26.x support is dropped. This is exact the same as
|
||||
;; `directory-files-recursively' from Emacs 26, but with FOLLOW-SYMLINKS
|
||||
;; parameter from Emacs 27.
|
||||
(defun org-roam--directory-files-recursively (dir regexp
|
||||
&optional include-directories predicate
|
||||
follow-symlinks)
|
||||
"Return list of all files under directory DIR whose names match REGEXP.
|
||||
This function works recursively. Files are returned in \"depth
|
||||
first\" order, and files from each directory are sorted in
|
||||
alphabetical order. Each file name appears in the returned list
|
||||
in its absolute form.
|
||||
|
||||
By default, the returned list excludes directories, but if
|
||||
optional argument INCLUDE-DIRECTORIES is non-nil, they are
|
||||
included.
|
||||
|
||||
PREDICATE can be either nil (which means that all subdirectories
|
||||
of DIR are descended into), t (which means that subdirectories that
|
||||
can't be read are ignored), or a function (which is called with
|
||||
the name of each subdirectory, and should return non-nil if the
|
||||
subdirectory is to be descended into).
|
||||
|
||||
If FOLLOW-SYMLINKS is non-nil, symbolic links that point to
|
||||
directories are followed. Note that this can lead to infinite
|
||||
recursion."
|
||||
(let* ((result nil)
|
||||
(files nil)
|
||||
(dir (directory-file-name dir))
|
||||
;; When DIR is "/", remote file names like "/method:" could
|
||||
;; also be offered. We shall suppress them.
|
||||
(tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir)))))
|
||||
(dolist (file (sort (file-name-all-completions "" dir)
|
||||
'string<))
|
||||
(unless (member file '("./" "../"))
|
||||
(if (directory-name-p file)
|
||||
(let* ((leaf (substring file 0 (1- (length file))))
|
||||
(full-file (concat dir "/" leaf)))
|
||||
;; Don't follow symlinks to other directories.
|
||||
(when (and (or (not (file-symlink-p full-file))
|
||||
(and (file-symlink-p full-file)
|
||||
follow-symlinks))
|
||||
;; Allow filtering subdirectories.
|
||||
(or (eq predicate nil)
|
||||
(eq predicate t)
|
||||
(funcall predicate full-file)))
|
||||
(let ((sub-files
|
||||
(if (eq predicate t)
|
||||
(condition-case nil
|
||||
(org-roam--directory-files-recursively
|
||||
full-file regexp include-directories
|
||||
predicate follow-symlinks)
|
||||
(file-error nil))
|
||||
(org-roam--directory-files-recursively
|
||||
full-file regexp include-directories
|
||||
predicate follow-symlinks))))
|
||||
(setq result (nconc result sub-files))))
|
||||
(when (and include-directories
|
||||
(string-match regexp leaf))
|
||||
(setq result (nconc result (list full-file)))))
|
||||
(when (string-match regexp file)
|
||||
(push (concat dir "/" file) files)))))
|
||||
(nconc result (nreverse files))))
|
||||
|
||||
;;; Obsolete aliases (remove after next major release)
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-today
|
||||
'org-roam-dailies-goto-today "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-yesterday
|
||||
'org-roam-dailies-goto-yesterday "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-tomorrow
|
||||
'org-roam-dailies-goto-tomorrow "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-next-note
|
||||
'org-roam-dailies-goto-next-note "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-previous-note
|
||||
'org-roam-dailies-goto-previous-note "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-date
|
||||
'org-roam-dailies-goto-date "org-roam 2.0")
|
||||
|
||||
;;; Obsolete functions
|
||||
|
||||
(provide 'org-roam-compat)
|
||||
|
@ -327,25 +327,6 @@ negative, find note N days in the future."
|
||||
(define-key org-roam-dailies-map (kbd "v") #'org-roam-dailies-capture-date)
|
||||
(define-key org-roam-dailies-map (kbd ".") #'org-roam-dailies-find-directory)
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-today
|
||||
'org-roam-dailies-goto-today "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-yesterday
|
||||
'org-roam-dailies-goto-yesterday "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-tomorrow
|
||||
'org-roam-dailies-goto-tomorrow "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-next-note
|
||||
'org-roam-dailies-goto-next-note "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-previous-note
|
||||
'org-roam-dailies-goto-previous-note "org-roam 2.0")
|
||||
(define-obsolete-function-alias
|
||||
'org-roam-dailies-find-date
|
||||
'org-roam-dailies-goto-date "org-roam 2.0")
|
||||
|
||||
(provide 'org-roam-dailies)
|
||||
|
||||
;;; org-roam-dailies.el ends here
|
||||
|
@ -78,23 +78,31 @@ To your init file.
|
||||
(when (yes-or-no-p "Org-roam will now convert all your notes from v1 to v2.
|
||||
This will take a while. Are you sure you want to do this?")
|
||||
;; Back up notes
|
||||
(let ((backup-dir (expand-file-name "org-roam.bak"
|
||||
(file-name-directory (directory-file-name org-roam-directory)))))
|
||||
(let* ((parent-dir (f-parent org-roam-directory))
|
||||
(backup-dir (expand-file-name "org-roam.bak" parent-dir))
|
||||
(debug-dir (expand-file-name "org-roam.debug" parent-dir)))
|
||||
(message "Backing up files to %s" backup-dir)
|
||||
(copy-directory org-roam-directory backup-dir))
|
||||
(condition-case err
|
||||
(progn
|
||||
;; Convert v1 to v2
|
||||
(dolist (f (org-roam--list-all-files))
|
||||
(org-roam-with-file f nil
|
||||
(org-roam-migrate-v1-to-v2)))
|
||||
;; Rebuild cache
|
||||
(org-roam-db-sync 'force)
|
||||
|
||||
;; Convert v1 to v2
|
||||
(dolist (f (org-roam--list-all-files))
|
||||
(org-roam-with-file f nil
|
||||
(org-roam-migrate-v1-to-v2)))
|
||||
;; Rebuild cache
|
||||
(org-roam-db-sync 'force)
|
||||
|
||||
;;Replace all file links with ID links
|
||||
(dolist (f (org-roam--list-all-files))
|
||||
(org-roam-with-file f nil
|
||||
(org-roam-migrate-replace-file-links-with-id)
|
||||
(save-buffer)))))
|
||||
;;Replace all file links with ID links
|
||||
(dolist (f (org-roam--list-all-files))
|
||||
(org-roam-with-file f nil
|
||||
(org-roam-migrate-replace-file-links-with-id)
|
||||
(save-buffer))))
|
||||
(t
|
||||
(rename-file org-roam-directory debug-dir)
|
||||
(rename-file backup-dir org-roam-directory)
|
||||
(lwarn 'org-roam :warning (format "The migration wizard failed with error:\n%s\n%s"
|
||||
(error-message-string err)
|
||||
"Your files have been restored, consider filing an issue.\n"))))))
|
||||
|
||||
(defun org-roam-migrate-v1-to-v2 ()
|
||||
"Convert the current buffer to v2 format."
|
||||
@ -115,13 +123,13 @@ This will take a while. Are you sure you want to do this?")
|
||||
;; Replace roam_alias into properties drawer roam_aliases
|
||||
(when-let* ((aliases (mapcan #'split-string-and-unquote
|
||||
(cdar (org-collect-keywords '("roam_alias"))))))
|
||||
(let ((case-fold-search t))
|
||||
(org-with-point-at 1
|
||||
(dolist (alias aliases)
|
||||
(org-roam-alias-add alias))
|
||||
(while (re-search-forward "^#\\+roam_alias:" (point-max) t)
|
||||
(beginning-of-line)
|
||||
(kill-line 1)))))
|
||||
(dolist (alias aliases)
|
||||
(org-roam-alias-add alias)))
|
||||
(let ((case-fold-search t))
|
||||
(org-with-point-at 1
|
||||
(while (re-search-forward "^#\\+roam_alias:" (point-max) t)
|
||||
(beginning-of-line)
|
||||
(kill-line 1))))
|
||||
|
||||
;; Replace #+roam_tags into #+filetags
|
||||
(org-with-point-at 1
|
||||
@ -186,7 +194,7 @@ If the property is already set, replace its value."
|
||||
:where (= file $s1)
|
||||
:and (= level 0)] path))))
|
||||
(set-match-data mdata)
|
||||
(replace-match (org-link-make-string (concat "id:" node-id) desc))))))))
|
||||
(replace-match (org-link-make-string (concat "id:" node-id)) nil t)))))))
|
||||
|
||||
(provide 'org-roam-migrate)
|
||||
;;; org-roam-migrate.el ends here
|
||||
|
191
org-roam.el
191
org-roam.el
@ -216,67 +216,6 @@ E.g. (\".org\") => (\"*.org\" \"*.org.gpg\")"
|
||||
(command (s-join " " `(,executable "-L" ,dir "-type f \\(" ,names "\\)"))))
|
||||
(org-roam--shell-command-files command)))
|
||||
|
||||
;; Emacs 26 does not have FOLLOW-SYMLINKS in `directory-files-recursively'
|
||||
(defun org-roam--directory-files-recursively (dir regexp
|
||||
&optional include-directories predicate
|
||||
follow-symlinks)
|
||||
"Return list of all files under directory DIR whose names match REGEXP.
|
||||
This function works recursively. Files are returned in \"depth
|
||||
first\" order, and files from each directory are sorted in
|
||||
alphabetical order. Each file name appears in the returned list
|
||||
in its absolute form.
|
||||
|
||||
By default, the returned list excludes directories, but if
|
||||
optional argument INCLUDE-DIRECTORIES is non-nil, they are
|
||||
included.
|
||||
|
||||
PREDICATE can be either nil (which means that all subdirectories
|
||||
of DIR are descended into), t (which means that subdirectories that
|
||||
can't be read are ignored), or a function (which is called with
|
||||
the name of each subdirectory, and should return non-nil if the
|
||||
subdirectory is to be descended into).
|
||||
|
||||
If FOLLOW-SYMLINKS is non-nil, symbolic links that point to
|
||||
directories are followed. Note that this can lead to infinite
|
||||
recursion."
|
||||
(let* ((result nil)
|
||||
(files nil)
|
||||
(dir (directory-file-name dir))
|
||||
;; When DIR is "/", remote file names like "/method:" could
|
||||
;; also be offered. We shall suppress them.
|
||||
(tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir)))))
|
||||
(dolist (file (sort (file-name-all-completions "" dir)
|
||||
'string<))
|
||||
(unless (member file '("./" "../"))
|
||||
(if (directory-name-p file)
|
||||
(let* ((leaf (substring file 0 (1- (length file))))
|
||||
(full-file (concat dir "/" leaf)))
|
||||
;; Don't follow symlinks to other directories.
|
||||
(when (and (or (not (file-symlink-p full-file))
|
||||
(and (file-symlink-p full-file)
|
||||
follow-symlinks))
|
||||
;; Allow filtering subdirectories.
|
||||
(or (eq predicate nil)
|
||||
(eq predicate t)
|
||||
(funcall predicate full-file)))
|
||||
(let ((sub-files
|
||||
(if (eq predicate t)
|
||||
(condition-case nil
|
||||
(org-roam--directory-files-recursively
|
||||
full-file regexp include-directories
|
||||
predicate follow-symlinks)
|
||||
(file-error nil))
|
||||
(org-roam--directory-files-recursively
|
||||
full-file regexp include-directories
|
||||
predicate follow-symlinks))))
|
||||
(setq result (nconc result sub-files))))
|
||||
(when (and include-directories
|
||||
(string-match regexp leaf))
|
||||
(setq result (nconc result (list full-file)))))
|
||||
(when (string-match regexp file)
|
||||
(push (concat dir "/" file) files)))))
|
||||
(nconc result (nreverse files))))
|
||||
|
||||
(defun org-roam--list-files-elisp (dir)
|
||||
"Return all Org-roam files located recursively within DIR, using elisp."
|
||||
(let ((regex (concat "\\.\\(?:"(mapconcat
|
||||
@ -352,7 +291,9 @@ If BUFFER is not specified, use the current buffer."
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-setup ()
|
||||
"Setup Org-roam."
|
||||
"Setup Org-roam and initialize its database.
|
||||
This will install the needed hooks and advices to keep everything
|
||||
in sync with the connected databases."
|
||||
(interactive)
|
||||
(add-hook 'find-file-hook #'org-roam--file-setup)
|
||||
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
||||
@ -361,7 +302,10 @@ If BUFFER is not specified, use the current buffer."
|
||||
(org-roam-db-sync))
|
||||
|
||||
(defun org-roam-teardown ()
|
||||
"Teardown Org-roam."
|
||||
"Teardown Org-roam to completely disable it.
|
||||
This will remove all the hooks and advices installed by
|
||||
`org-roam-setup' and close all the database connections made by
|
||||
Org-roam."
|
||||
(interactive)
|
||||
(remove-hook 'find-file-hook #'org-roam--file-setup)
|
||||
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
|
||||
@ -407,6 +351,7 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
|
||||
;;;; Nodes
|
||||
(cl-defstruct (org-roam-node (:constructor org-roam-node-create)
|
||||
(:copier nil))
|
||||
"A heading or top level file with an assigned ID property."
|
||||
file file-hash file-atime file-mtime
|
||||
id level point todo priority scheduled deadline title properties olp
|
||||
tags aliases refs)
|
||||
@ -446,7 +391,7 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
|
||||
(replace-regexp-in-string (car pair) (cdr pair) title)))
|
||||
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
|
||||
("__*" . "_") ;; remove sequential underscores
|
||||
("^_" . "") ;; remove starting underscore
|
||||
("^_" . "") ;; remove starting underscore
|
||||
("_$" . ""))) ;; remove ending underscore
|
||||
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
|
||||
(downcase slug)))))
|
||||
@ -456,24 +401,28 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added."
|
||||
(set-keymap-parent map org-roam-mode-map)
|
||||
(define-key map [remap org-roam-visit-thing] 'org-roam-node-visit)
|
||||
map)
|
||||
"Keymap for Org-roam node sections.")
|
||||
"Keymap for `org-roam-node-section's.")
|
||||
|
||||
(defclass org-roam-node-section (magit-section)
|
||||
((keymap :initform 'org-roam-node-map)
|
||||
(node :initform nil)))
|
||||
(node :initform nil))
|
||||
"A `magit-section' used by `org-roam-mode' to contain heading for NODE.")
|
||||
|
||||
(defvar org-roam-preview-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(set-keymap-parent map org-roam-mode-map)
|
||||
(define-key map [remap org-roam-visit-thing] 'org-roam-preview-visit)
|
||||
map)
|
||||
"Keymap for Org-roam preview.")
|
||||
"Keymap for `org-roam-preview-section's.")
|
||||
|
||||
(defclass org-roam-preview-section (magit-section)
|
||||
((keymap :initform 'org-roam-preview-map)
|
||||
(file :initform nil)
|
||||
(begin :initform nil)
|
||||
(end :initform nil)))
|
||||
(end :initform nil))
|
||||
"A `magit-section' used by `org-roam-mode' to contain preview content.
|
||||
The preview content comes from FILE, between the next locations:
|
||||
BEGIN and END.")
|
||||
|
||||
(cl-defmethod org-roam-populate ((node org-roam-node))
|
||||
"Populate NODE from database.
|
||||
@ -521,11 +470,27 @@ nodes."
|
||||
"${title:*} ${tags:10}"
|
||||
"Configures display formatting for Org-roam node.
|
||||
Patterns of form \"${field-name:length}\" are interpolated based
|
||||
on the current node. \"field-name\" is replaced with the
|
||||
corresponding value of the field of the current node. \"length\"
|
||||
specifies how many characters are used to display the value of
|
||||
the field. A \"length\" of \"*\" specifies that as many
|
||||
characters as possible should be used."
|
||||
on the current node.
|
||||
|
||||
Each \"field-name\" is replaced with the return value of each
|
||||
corresponding accessor function for `org-roam-node', e.g.
|
||||
\"${title}\" will be interpolated by the result of
|
||||
`org-roam-node-title'. You can also define custom accessors using
|
||||
`cl-defmethod'. For example, you can define:
|
||||
|
||||
(cl-defmethod org-roam-node-my-title ((node org-roam-node))
|
||||
(concat \"My \" (org-roam-node-title node)))
|
||||
|
||||
and then reference it here or in the capture templates as
|
||||
\"${my-title}\".
|
||||
|
||||
\"length\" is an optional specifier and declares how many
|
||||
characters can be used to display the value of the corresponding
|
||||
field. If it's not specified, the field will be inserted as is,
|
||||
i.e. it won't be aligned nor trimmed. If it's an integer, the
|
||||
field will be aligned accordingly and all the exceeding
|
||||
characters will be trimmed out. If it's \"*\", the field will use
|
||||
as many characters as possible and will be aligned accordingly."
|
||||
:group 'org-roam
|
||||
:type 'string)
|
||||
|
||||
@ -609,7 +574,7 @@ populated."
|
||||
buf))
|
||||
|
||||
(defun org-roam-node-visit (node &optional other-window)
|
||||
"From the buffer, visit NODE.
|
||||
"From the current buffer, visit NODE.
|
||||
|
||||
Display the buffer in the selected window. With a prefix
|
||||
argument OTHER-WINDOW display the buffer in another window
|
||||
@ -649,7 +614,7 @@ Throw an error if multiple choices exist."
|
||||
(user-error "Multiple nodes exist with title or alias \"%s\"" s)))))
|
||||
|
||||
(defun org-roam-node-list ()
|
||||
"Return a list of all nodes."
|
||||
"Return all nodes stored in the database as a list of `org-roam-node's."
|
||||
(let ((rows (org-roam-db-query
|
||||
"SELECT
|
||||
id,
|
||||
@ -833,10 +798,25 @@ window instead."
|
||||
#'pop-to-buffer-same-window) buf)))
|
||||
|
||||
(cl-defun org-roam-node-insert-section (&key source-node point properties)
|
||||
"Insert section for NODE.
|
||||
SOURCE-NODE is the source node.
|
||||
POINT is the point in buffer for the link.
|
||||
PROPERTIES contains properties about the link."
|
||||
"Insert section for a link from SOURCE-NODE to some other node.
|
||||
|
||||
SOURCE-NODE is an `org-roam-node' that links or references some
|
||||
other node. Normally the other node is `org-roam-current-node'
|
||||
that set in `org-roam-buffer'.
|
||||
|
||||
POINT is the position in SOURCE-NODE's file where the link is
|
||||
located.
|
||||
|
||||
PROPERTIES (a plist) contains additional information about the
|
||||
link.
|
||||
|
||||
This section is made out of the next 2 `magit-section's:
|
||||
1. `org-roam-node-section' for a heading that describes
|
||||
SOURCE-NODE.
|
||||
|
||||
2. `org-roam-preview-section' for a preview content that comes
|
||||
from SOURCE-NODE's file for the link (that references the
|
||||
other node) at POINT."
|
||||
(magit-insert-section section (org-roam-node-section)
|
||||
(let ((outline (if-let ((outline (plist-get properties :outline)))
|
||||
(mapconcat #'org-link-display-format outline " > ")
|
||||
@ -873,9 +853,7 @@ If OTHER-WINDOW, visit the NODE in another window."
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-node-insert (&optional filter-fn)
|
||||
"Find an Org-roam file, and insert a relative org link to it at point.
|
||||
Return selected file if it exists.
|
||||
If LOWERCASE is non-nil, downcase the link description.
|
||||
"Find an Org-roam node and insert (where the point is) an \"id:\" link to it.
|
||||
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
|
||||
and when nil is returned the node will be filtered out."
|
||||
(interactive)
|
||||
@ -912,7 +890,7 @@ and when nil is returned the node will be filtered out."
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-node-random (&optional other-window)
|
||||
"Find a random Org-roam node.
|
||||
"Find and open a random Org-roam node.
|
||||
With prefix argument OTHER-WINDOW, visit the node in another
|
||||
window instead."
|
||||
(interactive current-prefix-arg)
|
||||
@ -923,22 +901,24 @@ window instead."
|
||||
other-window)))
|
||||
|
||||
;;;; Properties
|
||||
(defun org-roam-add-property (s prop)
|
||||
"Add S to property PROP."
|
||||
(defun org-roam-add-property (val prop)
|
||||
"Add VAL value to PROP property for the node at point.
|
||||
Both, VAL and PROP are strings."
|
||||
(let* ((p (org-entry-get (point) prop))
|
||||
(lst (when p (split-string-and-unquote p)))
|
||||
(lst (if (memq s lst) lst (cons s lst)))
|
||||
(lst (if (memq val lst) lst (cons val lst)))
|
||||
(lst (seq-uniq lst)))
|
||||
(org-set-property prop (combine-and-quote-strings lst))
|
||||
s))
|
||||
val))
|
||||
|
||||
(defun org-roam-remove-property (prop &optional s)
|
||||
"Remove S from property PROP.
|
||||
(defun org-roam-remove-property (prop &optional val)
|
||||
"Remove VAL value from PROP property for the node at point.
|
||||
Both VAL and PROP are strings.
|
||||
|
||||
If S is not specified, user is prompted to select a value."
|
||||
If VAL is not specified, user is prompted to select a value."
|
||||
(let* ((p (org-entry-get (point) prop))
|
||||
(lst (when p (split-string-and-unquote p)))
|
||||
(prop-to-remove (or s (completing-read "Remove: " lst)))
|
||||
(prop-to-remove (or val (completing-read "Remove: " lst)))
|
||||
(lst (delete prop-to-remove lst)))
|
||||
(if lst
|
||||
(org-set-property prop (combine-and-quote-strings lst))
|
||||
@ -1093,9 +1073,7 @@ REF is assumed to be a propertized string."
|
||||
|
||||
;;;###autoload
|
||||
(defun org-roam-ref-find (&optional initial-input filter-fn)
|
||||
"Find and open and Org-roam file from REF if it exists.
|
||||
REF should be the value of '#+roam_key:' without any
|
||||
type-information (e.g. 'cite:').
|
||||
"Find and open an Org-roam node that's dedicated to a specific ref.
|
||||
INITIAL-INPUT is the initial input to the prompt.
|
||||
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
|
||||
and when nil is returned the node will be filtered out."
|
||||
@ -1106,7 +1084,7 @@ and when nil is returned the node will be filtered out."
|
||||
|
||||
;;;; roam: link
|
||||
(defcustom org-roam-link-auto-replace t
|
||||
"When non-nil, replace Org-roam's roam links with file or id links whenever possible."
|
||||
"If non-nil, replace \"roam:\" links to existing nodes with \"id:\" links."
|
||||
:group 'org-roam
|
||||
:type 'boolean)
|
||||
|
||||
@ -1114,7 +1092,7 @@ and when nil is returned the node will be filtered out."
|
||||
(org-link-set-parameters "roam" :follow #'org-roam-link-follow-link)
|
||||
|
||||
(defun org-roam-link-replace-at-point (&optional link)
|
||||
"Replace the roam: LINK at point with an id link."
|
||||
"Replace \"roam:\" LINK at point with an \"id:\" link."
|
||||
(save-excursion
|
||||
(save-match-data
|
||||
(let* ((link (or link (org-element-context)))
|
||||
@ -1143,23 +1121,21 @@ and when nil is returned the node will be filtered out."
|
||||
|
||||
(add-hook 'org-roam-find-file-hook #'org-roam--replace-roam-links-on-save-h)
|
||||
|
||||
(defun org-roam-link-follow-link (path)
|
||||
"Org-roam's roam: link navigation with description PATH.
|
||||
This function is called by Org when following links of the type
|
||||
`roam'. While the path is passed, assume that the cursor is on
|
||||
the link."
|
||||
(if-let ((node (org-roam-node-from-title-or-alias path)))
|
||||
(defun org-roam-link-follow-link (title-or-alias)
|
||||
"Navigate \"roam:\" link to find and open the node with TITLE-OR-ALIAS.
|
||||
Assumes that the cursor was put where the link is."
|
||||
(if-let ((node (org-roam-node-from-title-or-alias title-or-alias)))
|
||||
(progn
|
||||
(when org-roam-link-auto-replace
|
||||
(org-roam-link-replace-at-point))
|
||||
(org-id-goto (org-roam-node-id node)))
|
||||
(org-roam-capture-
|
||||
:node (org-roam-node-create :title path)
|
||||
:node (org-roam-node-create :title title-or-alias)
|
||||
:props '(:finalize find-file))))
|
||||
|
||||
(defun org-roam-open-id-at-point ()
|
||||
"Navigates to the ID at point.
|
||||
To be added to `org-open-at-point-functions'."
|
||||
"Try to navigate \"id:\" link to find and visit node with an assigned ID.
|
||||
Assumes that the cursor was put where the link is."
|
||||
(let* ((context (org-element-context))
|
||||
(type (org-element-property :type context))
|
||||
(id (org-element-property :path context)))
|
||||
@ -1173,7 +1149,7 @@ To be added to `org-open-at-point-functions'."
|
||||
(t nil))))))
|
||||
|
||||
(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))
|
||||
|
||||
(add-hook 'org-roam-find-file-hook #'org-roam-open-id-with-org-roam-db-h)
|
||||
@ -1200,7 +1176,8 @@ Any top level properties drawers are incorporated into the new heading."
|
||||
(org-roam--file-keyword-kill "FILETAGS")))
|
||||
|
||||
(defun org-roam-refile ()
|
||||
"Refile to node."
|
||||
"Refile node at point to an Org-roam node.
|
||||
If region is active, then use it instead of the node at point."
|
||||
(interactive)
|
||||
(let* ((regionp (org-region-active-p))
|
||||
(region-start (and regionp (region-beginning)))
|
||||
|
Reference in New Issue
Block a user