mirror of
https://github.com/org-roam/org-roam
synced 2025-08-01 12:17:21 -05:00
(feat): Add a tagging system (#604)
Tags are used as meta-data for files: they facilitate interactions with notes where titles are insufficient. For example, tags allow for categorization of notes: differentiating between bibliographical and structure notes during interactive commands. Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com> Co-authored-by: N V <44036031+progfolio@users.noreply.github.com>
This commit is contained in:
@ -19,10 +19,9 @@ This manual is for Org-roam version 1.1.1.
|
|||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@gmail.com>
|
||||||
|
|
||||||
You can redistribute this document and/or modify it under the terms
|
You can redistribute this document and/or modify it under the terms of the GNU
|
||||||
of the GNU General Public License as published by the Free Software
|
General Public License as published by the Free Software Foundation, either
|
||||||
Foundation, either version 3 of the License, or (at your option) any
|
version 3 of the License, or (at your option) any later version.
|
||||||
later version.
|
|
||||||
|
|
||||||
This document is distributed in the hope that it will be useful,
|
This document is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
@ -174,7 +173,7 @@ Org-mode. However, to support additional functionality, Org-roam adds
|
|||||||
several Org-roam-specific keywords. These functionality are not crucial
|
several Org-roam-specific keywords. These functionality are not crucial
|
||||||
to effective use of Org-roam.
|
to effective use of Org-roam.
|
||||||
|
|
||||||
** File Titles
|
** Titles
|
||||||
|
|
||||||
To easily find a note, a title needs to be prescribed to a note. A note can have
|
To easily find a note, a title needs to be prescribed to a note. A note can have
|
||||||
many titles: this allows a note to be referred to by different names, which is
|
many titles: this allows a note to be referred to by different names, which is
|
||||||
@ -211,6 +210,41 @@ One can freely control which extraction methods to use by customizing
|
|||||||
information. If all methods of title extraction return no results, the file-name
|
information. If all methods of title extraction return no results, the file-name
|
||||||
is used in place of the titles for completions.
|
is used in place of the titles for completions.
|
||||||
|
|
||||||
|
If you wish to add your own title extraction method, you may push a symbol
|
||||||
|
='foo= into =org-roam-title-sources=, and define a
|
||||||
|
=org-roam--extract-titles-foo= which accepts no arguments. See
|
||||||
|
=org-roam--extract-titles-title= for an example.
|
||||||
|
|
||||||
|
** Tags
|
||||||
|
|
||||||
|
Tags are used as meta-data for files: they facilitate interactions with notes
|
||||||
|
where titles are insufficient. For example, tags allow for categorization of
|
||||||
|
notes: differentiating between bibliographical and structure notes during interactive commands.
|
||||||
|
|
||||||
|
Org-roam calls =org-roam--extract-tags= to extract tags from files. It uses the
|
||||||
|
variable =org-roam-tag-sources=, to control how tags are extracted. The tag
|
||||||
|
extraction methods supported are:
|
||||||
|
|
||||||
|
1. ='prop=: This extracts tags from the =#+ROAM_TAGS= property. Tags are space delimited, and can be multi-word using double quotes.
|
||||||
|
2. ='all-directories=: All sub-directories relative to =org-roam-directory= are
|
||||||
|
extracted as tags. That is, if a file is located at relative path
|
||||||
|
=foo/bar/file.org=, the file will have tags =foo= and =bar=.
|
||||||
|
3. ='last-directory=: Extracts the last directory relative to
|
||||||
|
=org-roam-directory= as the tag. That is, if a file is located at relative
|
||||||
|
path =foo/bar/file.org=, the file will have tag =bar=.
|
||||||
|
|
||||||
|
By default, only the ='prop= extraction method is enabled. To enable the other
|
||||||
|
extraction methods, you may modify =org-roam-tag-sources=:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq org-roam-tag-sources '(prop last-directory))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
If you wish to add your own tag extraction method, you may push a symbol ='foo=
|
||||||
|
into =org-roam-tag-sources=, and define a =org-roam--extract-tags-foo= which
|
||||||
|
accepts the absolute file path as its argument. See
|
||||||
|
=org-roam--extract-tags-prop= for an example.
|
||||||
|
|
||||||
** File Refs
|
** File Refs
|
||||||
|
|
||||||
Refs are unique identifiers for files. Each note can only have 1 ref.
|
Refs are unique identifiers for files. Each note can only have 1 ref.
|
||||||
@ -932,6 +966,7 @@ file within that directory, at least once.
|
|||||||
|
|
||||||
* _ :ignore:
|
* _ :ignore:
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
|
# eval: (refill-mode +1)
|
||||||
# before-save-hook: org-make-toc
|
# before-save-hook: org-make-toc
|
||||||
# after-save-hook: (lambda nil (progn (require 'ox-texinfo nil t) (org-texinfo-export-to-info)))
|
# after-save-hook: (lambda nil (progn (require 'ox-texinfo nil t) (org-texinfo-export-to-info)))
|
||||||
# indent-tabs-mode: nil
|
# indent-tabs-mode: nil
|
||||||
|
@ -51,10 +51,9 @@ This manual is for Org-roam version 1.1.1.
|
|||||||
@quotation
|
@quotation
|
||||||
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@@gmail.com>
|
Copyright (C) 2020-2020 Jethro Kuan <jethrokuan95@@gmail.com>
|
||||||
|
|
||||||
You can redistribute this document and/or modify it under the terms
|
You can redistribute this document and/or modify it under the terms of the GNU
|
||||||
of the GNU General Public License as published by the Free Software
|
General Public License as published by the Free Software Foundation, either
|
||||||
Foundation, either version 3 of the License, or (at your option) any
|
version 3 of the License, or (at your option) any later version.
|
||||||
later version.
|
|
||||||
|
|
||||||
This document is distributed in the hope that it will be useful,
|
This document is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
@ -79,19 +78,22 @@ General Public License for more details.
|
|||||||
* Diagnosing and Repairing Files::
|
* Diagnosing and Repairing Files::
|
||||||
* Appendix::
|
* Appendix::
|
||||||
* FAQ::
|
* FAQ::
|
||||||
|
* _: _ (2).
|
||||||
|
|
||||||
@detailmenu
|
@detailmenu
|
||||||
--- The Detailed Node Listing ---
|
--- The Detailed Node Listing ---
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
|
|
||||||
|
* _::
|
||||||
* Installing from MELPA::
|
* Installing from MELPA::
|
||||||
* Installing from the Git Repository::
|
* Installing from the Git Repository::
|
||||||
* Post-Installation Tasks::
|
* Post-Installation Tasks::
|
||||||
|
|
||||||
Anatomy of an Org-roam File
|
Anatomy of an Org-roam File
|
||||||
|
|
||||||
* File Aliases::
|
* Titles::
|
||||||
|
* Tags::
|
||||||
* File Refs::
|
* File Refs::
|
||||||
|
|
||||||
The Templating System
|
The Templating System
|
||||||
@ -117,6 +119,7 @@ Graphing
|
|||||||
|
|
||||||
Roam Protocol
|
Roam Protocol
|
||||||
|
|
||||||
|
* _: _ (1).
|
||||||
* Installation: Installation (1).
|
* Installation: Installation (1).
|
||||||
* The @samp{roam-file} protocol::
|
* The @samp{roam-file} protocol::
|
||||||
* The @samp{roam-ref} Protocol::
|
* The @samp{roam-ref} Protocol::
|
||||||
@ -176,14 +179,18 @@ Emacs is also a fantastic interface for editing text, and we can inherit many of
|
|||||||
@node Installation
|
@node Installation
|
||||||
@chapter Installation
|
@chapter Installation
|
||||||
|
|
||||||
Org-roam can be installed using Emacs' package manager or manually from its development repository.
|
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
* _::
|
||||||
* Installing from MELPA::
|
* Installing from MELPA::
|
||||||
* Installing from the Git Repository::
|
* Installing from the Git Repository::
|
||||||
* Post-Installation Tasks::
|
* Post-Installation Tasks::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
@node _
|
||||||
|
@section _ :ignore:
|
||||||
|
|
||||||
|
Org-roam can be installed using Emacs' package manager or manually from its development repository.
|
||||||
|
|
||||||
@node Installing from MELPA
|
@node Installing from MELPA
|
||||||
@section Installing from MELPA
|
@section Installing from MELPA
|
||||||
|
|
||||||
@ -310,22 +317,100 @@ several Org-roam-specific keywords. These functionality are not crucial
|
|||||||
to effective use of Org-roam.
|
to effective use of Org-roam.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* File Aliases::
|
* Titles::
|
||||||
|
* Tags::
|
||||||
* File Refs::
|
* File Refs::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node File Aliases
|
@node Titles
|
||||||
@section File Aliases
|
@section Titles
|
||||||
|
|
||||||
Suppose you want a note to be referred to by different names (e.g.
|
To easily find a note, a title needs to be prescribed to a note. A note can have
|
||||||
``World War 2'', ``WWII''). You may specify such aliases using the
|
many titles: this allows a note to be referred to by different names, which is
|
||||||
@samp{#+ROAM_ALIAS} attribute:
|
especially useful for topics or concepts with acronyms. For example, for a note
|
||||||
|
like ``World War 2'', it may be desirable to also refer to it using the acronym
|
||||||
|
``WWII''.
|
||||||
|
|
||||||
|
Org-roam calls @samp{org-roam--extract-titles} to extract titles. It uses the
|
||||||
|
variable @samp{org-roam-title-sources}, to control how the titles are extracted. The
|
||||||
|
title extraction methods supported are:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
@samp{'title}: This extracts the title using the file @samp{#+TITLE} property
|
||||||
|
@item
|
||||||
|
@samp{'headline}: This extracts the title from the first headline in the Org file
|
||||||
|
@item
|
||||||
|
@samp{'alias}: This extracts a list of titles using the @samp{#ROAM_ALIAS} property.
|
||||||
|
The aliases are space-delimited, and can be multi-worded using quotes
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
Take for example the following org file:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
#+TITLE: World War 2
|
#+TITLE: World War 2
|
||||||
#+ROAM_ALIAS: "WWII" "World War II"
|
#+ROAM_ALIAS: "WWII" "World War II"
|
||||||
|
|
||||||
|
* Headline
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@multitable {aaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaa}
|
||||||
|
@headitem Method
|
||||||
|
@tab Titles
|
||||||
|
@item @samp{'title}
|
||||||
|
@tab '(``World War 2'')
|
||||||
|
@item @samp{'headline}
|
||||||
|
@tab '(``Headline'')
|
||||||
|
@item @samp{'alias}
|
||||||
|
@tab '(``WWII'' ``World War II'')
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
One can freely control which extraction methods to use by customizing
|
||||||
|
@samp{org-roam-title-sources}: see the doc-string for the variable for more
|
||||||
|
information. If all methods of title extraction return no results, the file-name
|
||||||
|
is used in place of the titles for completions.
|
||||||
|
|
||||||
|
If you wish to add your own title extraction method, you may push a symbol
|
||||||
|
@samp{'foo} into @samp{org-roam-title-sources}, and define a
|
||||||
|
@samp{org-roam--extract-titles-foo} which accepts no arguments. See
|
||||||
|
@samp{org-roam--extract-titles-title} for an example.
|
||||||
|
|
||||||
|
@node Tags
|
||||||
|
@section Tags
|
||||||
|
|
||||||
|
Tags are used as meta-data for files: they facilitate interactions with notes
|
||||||
|
where titles are insufficient. For example, tags allow for categorization of
|
||||||
|
notes: differentiating between bibliographical and structure notes during interactive commands.
|
||||||
|
|
||||||
|
Org-roam calls @samp{org-roam--extract-tags} to extract tags from files. It uses the
|
||||||
|
variable @samp{org-roam-tag-sources}, to control how tags are extracted. The tag
|
||||||
|
extraction methods supported are:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
@samp{'prop}: This extracts tags from the @samp{#+ROAM_TAGS} property. Tags are space delimited, and can be multi-word using double quotes.
|
||||||
|
@item
|
||||||
|
@samp{'all-directories}: All sub-directories relative to @samp{org-roam-directory} are
|
||||||
|
extracted as tags. That is, if a file is located at relative path
|
||||||
|
@samp{foo/bar/file.org}, the file will have tags @samp{foo} and @samp{bar}.
|
||||||
|
@item
|
||||||
|
@samp{'last-directory}: Extracts the last directory relative to
|
||||||
|
@samp{org-roam-directory} as the tag. That is, if a file is located at relative
|
||||||
|
path @samp{foo/bar/file.org}, the file will have tag @samp{bar}.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
By default, only the @samp{'prop} extraction method is enabled. To enable the other
|
||||||
|
extraction methods, you may modify @samp{org-roam-tag-sources}:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(setq org-roam-tag-sources '(prop last-directory))
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
If you wish to add your own tag extraction method, you may push a symbol @samp{'foo}
|
||||||
|
into @samp{org-roam-tag-sources}, and define a @samp{org-roam--extract-tags-foo} which
|
||||||
|
accepts the absolute file path as its argument. See
|
||||||
|
@samp{org-roam--extract-tags-prop} for an example.
|
||||||
|
|
||||||
@node File Refs
|
@node File Refs
|
||||||
@section File Refs
|
@section File Refs
|
||||||
|
|
||||||
@ -754,15 +839,19 @@ Other options include @samp{'ido}, and @samp{'ivy}.
|
|||||||
@node Roam Protocol
|
@node Roam Protocol
|
||||||
@chapter Roam Protocol
|
@chapter Roam Protocol
|
||||||
|
|
||||||
Org-roam extending @samp{org-protocol} with 2 protocols: the @samp{roam-file}
|
|
||||||
and @samp{roam-ref} protocol.
|
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
* _: _ (1).
|
||||||
* Installation: Installation (1).
|
* Installation: Installation (1).
|
||||||
* The @samp{roam-file} protocol::
|
* The @samp{roam-file} protocol::
|
||||||
* The @samp{roam-ref} Protocol::
|
* The @samp{roam-ref} Protocol::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
@node _ (1)
|
||||||
|
@section _ :ignore:
|
||||||
|
|
||||||
|
Org-roam extending @samp{org-protocol} with 2 protocols: the @samp{roam-file}
|
||||||
|
and @samp{roam-ref} protocol.
|
||||||
|
|
||||||
@node Installation (1)
|
@node Installation (1)
|
||||||
@section Installation
|
@section Installation
|
||||||
|
|
||||||
@ -1191,5 +1280,8 @@ All files within that directory will be treated as their own separate
|
|||||||
set of Org-roam files. Remember to run @samp{org-roam-db-build-cache} from a
|
set of Org-roam files. Remember to run @samp{org-roam-db-build-cache} from a
|
||||||
file within that directory, at least once.
|
file within that directory, at least once.
|
||||||
|
|
||||||
|
@node _ (2)
|
||||||
|
@chapter _ :ignore:
|
||||||
|
|
||||||
Emacs 28.0.50 (Org mode 9.4)
|
Emacs 28.0.50 (Org mode 9.4)
|
||||||
@bye
|
@bye
|
||||||
|
@ -331,8 +331,11 @@ This uses the templates defined at `org-roam-capture-templates'."
|
|||||||
(when (org-roam-capture--in-process-p)
|
(when (org-roam-capture--in-process-p)
|
||||||
(user-error "Nested Org-roam capture processes not supported"))
|
(user-error "Nested Org-roam capture processes not supported"))
|
||||||
(let* ((completions (org-roam--get-title-path-completions))
|
(let* ((completions (org-roam--get-title-path-completions))
|
||||||
(title (org-roam-completion--completing-read "File: " completions))
|
(title-with-keys (org-roam-completion--completing-read "File: "
|
||||||
(file-path (cdr (assoc title completions))))
|
completions))
|
||||||
|
(res (gethash title-with-keys completions))
|
||||||
|
(title (plist-get res :title))
|
||||||
|
(file-path (plist-get res :file-path)))
|
||||||
(let ((org-roam-capture--info (list (cons 'title title)
|
(let ((org-roam-capture--info (list (cons 'title title)
|
||||||
(cons 'slug (org-roam--title-to-slug title))
|
(cons 'slug (org-roam--title-to-slug title))
|
||||||
(cons 'file file-path)))
|
(cons 'file file-path)))
|
||||||
|
@ -40,11 +40,12 @@
|
|||||||
(defvar org-roam-verbose)
|
(defvar org-roam-verbose)
|
||||||
|
|
||||||
(declare-function org-roam--org-roam-file-p "org-roam")
|
(declare-function org-roam--org-roam-file-p "org-roam")
|
||||||
(declare-function org-roam--extract-and-format-titles "org-roam")
|
(declare-function org-roam--extract-titles "org-roam")
|
||||||
(declare-function org-roam--extract-ref "org-roam")
|
(declare-function org-roam--extract-ref "org-roam")
|
||||||
|
(declare-function org-roam--extract-tags "org-roam")
|
||||||
(declare-function org-roam--extract-links "org-roam")
|
(declare-function org-roam--extract-links "org-roam")
|
||||||
(declare-function org-roam--list-all-files "org-roam")
|
(declare-function org-roam--list-all-files "org-roam")
|
||||||
(declare-function org-roam-buffer--update-maybe "org-roam-buffer")
|
(declare-function org-roam-buffer--update-maybe "org-roam-buffer")
|
||||||
|
|
||||||
;;;; Options
|
;;;; Options
|
||||||
(defcustom org-roam-db-location nil
|
(defcustom org-roam-db-location nil
|
||||||
@ -56,7 +57,7 @@ when used with multiple Org-roam instances."
|
|||||||
:type 'string
|
:type 'string
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
(defconst org-roam-db--version 3)
|
(defconst org-roam-db--version 4)
|
||||||
(defconst org-roam-db--sqlite-available-p
|
(defconst org-roam-db--sqlite-available-p
|
||||||
(with-demoted-errors "Org-roam initialization: %S"
|
(with-demoted-errors "Org-roam initialization: %S"
|
||||||
(emacsql-sqlite-ensure-binary)
|
(emacsql-sqlite-ensure-binary)
|
||||||
@ -128,6 +129,10 @@ SQL can be either the emacsql vector representation, or a string."
|
|||||||
(type :not-null)
|
(type :not-null)
|
||||||
(properties :not-null)])
|
(properties :not-null)])
|
||||||
|
|
||||||
|
(tags
|
||||||
|
[(file :unique :primary-key)
|
||||||
|
(tags)])
|
||||||
|
|
||||||
(titles
|
(titles
|
||||||
[(file :not-null)
|
[(file :not-null)
|
||||||
titles])
|
titles])
|
||||||
@ -215,6 +220,13 @@ This is equivalent to removing the node from the graph."
|
|||||||
:values $v1]
|
:values $v1]
|
||||||
(list (vector file titles))))
|
(list (vector file titles))))
|
||||||
|
|
||||||
|
(defun org-roam-db--insert-tags (file tags)
|
||||||
|
"Insert TAGS for a FILE into the Org-roam cache."
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into tags
|
||||||
|
:values $v1]
|
||||||
|
(list (vector file tags))))
|
||||||
|
|
||||||
(defun org-roam-db--insert-ref (file ref)
|
(defun org-roam-db--insert-ref (file ref)
|
||||||
"Insert REF for FILE into the Org-roam cache."
|
"Insert REF for FILE into the Org-roam cache."
|
||||||
(let ((key (cdr ref))
|
(let ((key (cdr ref))
|
||||||
@ -297,12 +309,21 @@ connections, nil is returned."
|
|||||||
(defun org-roam-db--update-titles ()
|
(defun org-roam-db--update-titles ()
|
||||||
"Update the title of the current buffer into the cache."
|
"Update the title of the current buffer into the cache."
|
||||||
(let* ((file (file-truename (buffer-file-name)))
|
(let* ((file (file-truename (buffer-file-name)))
|
||||||
(title (org-roam--extract-and-format-titles file)))
|
(title (org-roam--extract-titles)))
|
||||||
(org-roam-db-query [:delete :from titles
|
(org-roam-db-query [:delete :from titles
|
||||||
:where (= file $s1)]
|
:where (= file $s1)]
|
||||||
file)
|
file)
|
||||||
(org-roam-db--insert-titles file title)))
|
(org-roam-db--insert-titles file title)))
|
||||||
|
|
||||||
|
(defun org-roam-db--update-tags ()
|
||||||
|
"Update the tags of the current buffer into the cache."
|
||||||
|
(let* ((file (file-truename (buffer-file-name)))
|
||||||
|
(tags (org-roam--extract-tags)))
|
||||||
|
(org-roam-db-query [:delete :from tags
|
||||||
|
:where (= file $s1)]
|
||||||
|
file)
|
||||||
|
(org-roam-db--insert-tags file tags)))
|
||||||
|
|
||||||
(defun org-roam-db--update-refs ()
|
(defun org-roam-db--update-refs ()
|
||||||
"Update the ref of the current buffer into the cache."
|
"Update the ref of the current buffer into the cache."
|
||||||
(let ((file (file-truename (buffer-file-name))))
|
(let ((file (file-truename (buffer-file-name))))
|
||||||
@ -329,6 +350,7 @@ connections, nil is returned."
|
|||||||
(current-buffer))))
|
(current-buffer))))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(save-excursion
|
(save-excursion
|
||||||
|
(org-roam-db--update-tags)
|
||||||
(org-roam-db--update-titles)
|
(org-roam-db--update-titles)
|
||||||
(org-roam-db--update-refs)
|
(org-roam-db--update-refs)
|
||||||
(org-roam-db--update-cache-links)
|
(org-roam-db--update-cache-links)
|
||||||
@ -344,7 +366,7 @@ If FORCE, force a rebuild of the cache from scratch."
|
|||||||
(let* ((org-roam-files (org-roam--list-all-files))
|
(let* ((org-roam-files (org-roam--list-all-files))
|
||||||
(current-files (org-roam-db--get-current-files))
|
(current-files (org-roam-db--get-current-files))
|
||||||
(time (current-time))
|
(time (current-time))
|
||||||
all-files all-links all-titles all-refs)
|
all-files all-links all-titles all-refs all-tags)
|
||||||
(dolist (file org-roam-files)
|
(dolist (file org-roam-files)
|
||||||
(org-roam--with-temp-buffer
|
(org-roam--with-temp-buffer
|
||||||
(insert-file-contents file)
|
(insert-file-contents file)
|
||||||
@ -352,12 +374,14 @@ If FORCE, force a rebuild of the cache from scratch."
|
|||||||
(unless (string= (gethash file current-files)
|
(unless (string= (gethash file current-files)
|
||||||
contents-hash)
|
contents-hash)
|
||||||
(org-roam-db--clear-file file)
|
(org-roam-db--clear-file file)
|
||||||
(setq all-files
|
(push (vector file contents-hash time)
|
||||||
(cons (vector file contents-hash time) all-files))
|
all-files)
|
||||||
(when-let (links (org-roam--extract-links file))
|
(when-let (links (org-roam--extract-links file))
|
||||||
(setq all-links (append links all-links)))
|
(push links all-links))
|
||||||
(let ((titles (org-roam--extract-and-format-titles file)))
|
(when-let (tags (org-roam--extract-tags file))
|
||||||
(setq all-titles (cons (vector file titles) all-titles)))
|
(push (vector file tags) all-tags))
|
||||||
|
(let ((titles (org-roam--extract-titles)))
|
||||||
|
(push (vector file titles) all-titles))
|
||||||
(when-let* ((ref (org-roam--extract-ref))
|
(when-let* ((ref (org-roam--extract-ref))
|
||||||
(type (car ref))
|
(type (car ref))
|
||||||
(key (cdr ref)))
|
(key (cdr ref)))
|
||||||
@ -381,6 +405,11 @@ If FORCE, force a rebuild of the cache from scratch."
|
|||||||
[:insert :into titles
|
[:insert :into titles
|
||||||
:values $v1]
|
:values $v1]
|
||||||
all-titles))
|
all-titles))
|
||||||
|
(when all-tags
|
||||||
|
(org-roam-db-query
|
||||||
|
[:insert :into tags
|
||||||
|
:values $v1]
|
||||||
|
all-tags))
|
||||||
(when all-refs
|
(when all-refs
|
||||||
(org-roam-db-query
|
(org-roam-db-query
|
||||||
[:insert :into refs
|
[:insert :into refs
|
||||||
@ -388,12 +417,14 @@ If FORCE, force a rebuild of the cache from scratch."
|
|||||||
all-refs))
|
all-refs))
|
||||||
(let ((stats (list :files (length all-files)
|
(let ((stats (list :files (length all-files)
|
||||||
:links (length all-links)
|
:links (length all-links)
|
||||||
|
:tags (length all-tags)
|
||||||
:titles (length all-titles)
|
:titles (length all-titles)
|
||||||
:refs (length all-refs)
|
:refs (length all-refs)
|
||||||
:deleted (length (hash-table-keys current-files)))))
|
:deleted (length (hash-table-keys current-files)))))
|
||||||
(org-roam-message "files: %s, links: %s, titles: %s, refs: %s, deleted: %s"
|
(org-roam-message "files: %s, links: %s, tags: %s, titles: %s, refs: %s, deleted: %s"
|
||||||
(plist-get stats :files)
|
(plist-get stats :files)
|
||||||
(plist-get stats :links)
|
(plist-get stats :links)
|
||||||
|
(plist-get stats :tags)
|
||||||
(plist-get stats :titles)
|
(plist-get stats :titles)
|
||||||
(plist-get stats :refs)
|
(plist-get stats :refs)
|
||||||
(plist-get stats :deleted))
|
(plist-get stats :deleted))
|
||||||
|
217
org-roam.el
217
org-roam.el
@ -113,7 +113,7 @@ Each element in the list is either:
|
|||||||
1. a symbol -- this symbol corresponds to a title retrieval
|
1. a symbol -- this symbol corresponds to a title retrieval
|
||||||
function, which returns the list of titles for the current buffer
|
function, which returns the list of titles for the current buffer
|
||||||
2. a list of symbols -- symbols in the list are treated as
|
2. a list of symbols -- symbols in the list are treated as
|
||||||
with (1). The return value of this list is the first symbol in
|
with (1). The return value of this list is the first symbol in
|
||||||
the list returning a non-nil value.
|
the list returning a non-nil value.
|
||||||
|
|
||||||
The return results of the root list are concatenated.
|
The return results of the root list are concatenated.
|
||||||
@ -134,6 +134,31 @@ space-delimited strings.
|
|||||||
(symbol)))
|
(symbol)))
|
||||||
:group 'org-roam)
|
:group 'org-roam)
|
||||||
|
|
||||||
|
(defcustom org-roam-tag-sources '(prop)
|
||||||
|
"Sources to obtain tags from.
|
||||||
|
|
||||||
|
It should be a list of symbols representing any of the following
|
||||||
|
extraction methods:
|
||||||
|
|
||||||
|
`prop'
|
||||||
|
Extract tags from the #+ROAM_TAGS property.
|
||||||
|
Tags are space delimited.
|
||||||
|
Tags may contain spaces if they are double-quoted.
|
||||||
|
e.g. #+ROAM_TAGS: tag \"tag with spaces\"
|
||||||
|
|
||||||
|
`all-directories'
|
||||||
|
Extract sub-directories relative to `org-roam-directory'.
|
||||||
|
That is, if a file is located at relative path foo/bar/file.org,
|
||||||
|
the file will have tags \"foo\" and \"bar\".
|
||||||
|
|
||||||
|
`last-directory'
|
||||||
|
Extract the last directory relative to `org-roam-directory'.
|
||||||
|
That is, if a file is located at relative path foo/bar/file.org,
|
||||||
|
the file will have tag \"bar\"."
|
||||||
|
:type '(set (const :tag "#+ROAM_TAGS" prop)
|
||||||
|
(const :tag "sub-directories" all-directories)
|
||||||
|
(const :tag "parent directory" last-directory)))
|
||||||
|
|
||||||
;;;; Dynamic variables
|
;;;; Dynamic variables
|
||||||
(defvar org-roam-last-window nil
|
(defvar org-roam-last-window nil
|
||||||
"Last window `org-roam' was called from.")
|
"Last window `org-roam' was called from.")
|
||||||
@ -149,8 +174,8 @@ space-delimited strings.
|
|||||||
(push (cons prop val) res)))
|
(push (cons prop val) res)))
|
||||||
res))
|
res))
|
||||||
|
|
||||||
(defun org-roam--aliases-str-to-list (str)
|
(defun org-roam--str-to-list (str)
|
||||||
"Function to transform string STR into list of alias titles.
|
"Function to transform string STR into list of titles.
|
||||||
|
|
||||||
This snippet is obtained from ox-hugo:
|
This snippet is obtained from ox-hugo:
|
||||||
https://github.com/kaushalmodi/ox-hugo/blob/a80b250987bc770600c424a10b3bca6ff7282e3c/ox-hugo.el#L3131"
|
https://github.com/kaushalmodi/ox-hugo/blob/a80b250987bc770600c424a10b3bca6ff7282e3c/ox-hugo.el#L3131"
|
||||||
@ -314,69 +339,6 @@ it as FILE-PATH."
|
|||||||
names)))))))
|
names)))))))
|
||||||
links))
|
links))
|
||||||
|
|
||||||
(defcustom org-roam-title-include-subdirs nil
|
|
||||||
"When non-nil, include subdirs in title completions.
|
|
||||||
The subdirs will be relative to `org-roam-directory'."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'org-roam)
|
|
||||||
|
|
||||||
(defcustom org-roam-title-subdir-format 'default
|
|
||||||
"Function to use to format the titles of entries with subdirs.
|
|
||||||
Only relevant when `org-roam-title-include-subdirs' is non-nil.
|
|
||||||
The value should be a function that takes two arguments: the
|
|
||||||
title of the note, and the subdirs as a list. If set to
|
|
||||||
'default, `org-roam--format-title-with-subdirs' is used."
|
|
||||||
:type '(choice
|
|
||||||
(const :tag "Default" 'default)
|
|
||||||
(function :tag "Custom function"))
|
|
||||||
:group 'org-roam)
|
|
||||||
|
|
||||||
(defcustom org-roam-title-subdir-separator "/"
|
|
||||||
"String to use to separate subdirs.
|
|
||||||
Only relevant when `org-roam-title-include-subdirs' is non-nil."
|
|
||||||
:type 'string
|
|
||||||
:group 'org-roam)
|
|
||||||
|
|
||||||
(defun org-roam--format-title-with-subdirs (title subdirs)
|
|
||||||
"Format TITLE with SUBDIRS as '\(SUBDIRS) TITLE'."
|
|
||||||
(let* ((separator org-roam-title-subdir-separator)
|
|
||||||
(subdirs (and subdirs
|
|
||||||
(format "(%s) " (string-join subdirs separator)))))
|
|
||||||
(concat subdirs title)))
|
|
||||||
|
|
||||||
(defun org-roam--format-title (title &optional file-path)
|
|
||||||
"Format TITLE with relative subdirs from `org-roam-directory'.
|
|
||||||
When `org-roam-title-include-subdirs' is non-nil, FILE-PATH is
|
|
||||||
used to compute which subdirs should be included in the title.
|
|
||||||
If FILE-PATH is not provided, the file associated with the
|
|
||||||
current buffer is used."
|
|
||||||
(if org-roam-title-include-subdirs
|
|
||||||
(let* ((root (expand-file-name org-roam-directory))
|
|
||||||
;; If file-path is not provided, compute it
|
|
||||||
(path (or file-path
|
|
||||||
(-> (or (buffer-base-buffer)
|
|
||||||
(current-buffer))
|
|
||||||
(buffer-file-name)
|
|
||||||
(file-truename))))
|
|
||||||
(subdirs (--> path
|
|
||||||
(file-name-directory it)
|
|
||||||
(unless (equal root it)
|
|
||||||
(--> it
|
|
||||||
(file-relative-name it root)
|
|
||||||
;; Transform path-string to list of subdirs
|
|
||||||
(split-string (substring it nil -1) "/"))))))
|
|
||||||
(pcase org-roam-title-subdir-format
|
|
||||||
((pred functionp)
|
|
||||||
(funcall org-roam-title-subdir-format title subdirs))
|
|
||||||
((or 't 'default)
|
|
||||||
(org-roam--format-title-with-subdirs title subdirs))
|
|
||||||
('nil
|
|
||||||
(error "`org-roam-title-subdir-format' should not be nil"))
|
|
||||||
(wrong-type (signal 'wrong-type-argument
|
|
||||||
`((functionp symbolp)
|
|
||||||
,wrong-type)))))
|
|
||||||
title))
|
|
||||||
|
|
||||||
(defun org-roam--extract-titles-title ()
|
(defun org-roam--extract-titles-title ()
|
||||||
"Return title from \"#+TITLE\" of the current buffer."
|
"Return title from \"#+TITLE\" of the current buffer."
|
||||||
(let* ((prop (org-roam--extract-global-props '("TITLE")))
|
(let* ((prop (org-roam--extract-global-props '("TITLE")))
|
||||||
@ -389,7 +351,7 @@ current buffer is used."
|
|||||||
Reads from the \"ROAM_ALIAS\" property."
|
Reads from the \"ROAM_ALIAS\" property."
|
||||||
(let* ((prop (org-roam--extract-global-props '("ROAM_ALIAS")))
|
(let* ((prop (org-roam--extract-global-props '("ROAM_ALIAS")))
|
||||||
(aliases (cdr (assoc "ROAM_ALIAS" prop))))
|
(aliases (cdr (assoc "ROAM_ALIAS" prop))))
|
||||||
(org-roam--aliases-str-to-list aliases)))
|
(org-roam--str-to-list aliases)))
|
||||||
|
|
||||||
(defun org-roam--extract-titles-headline ()
|
(defun org-roam--extract-titles-headline ()
|
||||||
"Return the first headline of the current buffer."
|
"Return the first headline of the current buffer."
|
||||||
@ -418,13 +380,60 @@ If NESTED, return the first successful result from SOURCES."
|
|||||||
(cl-return))))
|
(cl-return))))
|
||||||
coll))
|
coll))
|
||||||
|
|
||||||
(defun org-roam--extract-and-format-titles (&optional file-path)
|
(defun org-roam--extract-tags-all-directories (file)
|
||||||
"Extract the titles from the current buffer and format them.
|
"Extract tags from using the directory path FILE.
|
||||||
If FILE-PATH is not provided, the file associated with the
|
All sub-directories relative to `org-roam-directory' are used as tags."
|
||||||
current buffer is used."
|
(when-let ((dir-relative (file-name-directory
|
||||||
(mapcar (lambda (title)
|
(file-relative-name file org-roam-directory))))
|
||||||
(org-roam--format-title title file-path))
|
(f-split dir-relative)))
|
||||||
(org-roam--extract-titles)))
|
|
||||||
|
(defun org-roam--extract-tags-last-directory (file)
|
||||||
|
"Extract tags from using the directory path FILE.
|
||||||
|
The final directory component is used as a tag."
|
||||||
|
(when-let ((dir-relative (file-name-directory
|
||||||
|
(file-relative-name file org-roam-directory))))
|
||||||
|
(last (f-split dir-relative))))
|
||||||
|
|
||||||
|
(defun org-roam--extract-tags-prop (_file)
|
||||||
|
"Extract tags from the current buffer's \"#ROAM_TAGS\" global property."
|
||||||
|
(let* ((prop (org-roam--extract-global-props '("ROAM_TAGS"))))
|
||||||
|
(org-roam--str-to-list (cdr (assoc "ROAM_TAGS" prop)))))
|
||||||
|
|
||||||
|
(defcustom org-roam-tag-sort nil
|
||||||
|
"When non-nil, sort the tags in the completions.
|
||||||
|
When t, sort the tags alphabetically, regardless of case.
|
||||||
|
`org-roam-tag-sort' can also be a list of arguments to be applied
|
||||||
|
to `cl-sort'. For example, these are the arguments used when
|
||||||
|
`org-roam-tag-sort' is set to t:
|
||||||
|
\('string-lessp :key 'downcase)
|
||||||
|
Only relevant when `org-roam-tag-sources' is non-nil."
|
||||||
|
:type '(choice
|
||||||
|
(boolean)
|
||||||
|
(list :tag "Arguments to cl-loop"))
|
||||||
|
:group 'org-roam)
|
||||||
|
|
||||||
|
(defun org-roam--extract-tags (&optional file)
|
||||||
|
"Extract tags from the current buffer.
|
||||||
|
If file-path FILE, use it to determine the directory tags.
|
||||||
|
Tags are obtained via:
|
||||||
|
|
||||||
|
1. Directory tags: Relative to `org-roam-directory': each folder
|
||||||
|
path is considered a tag.
|
||||||
|
2. The key #+ROAM_TAGS."
|
||||||
|
(let* ((file (or file (buffer-file-name (buffer-base-buffer))))
|
||||||
|
(tags (mapcan (lambda (source)
|
||||||
|
(funcall (intern (concat "org-roam--extract-tags-"
|
||||||
|
(symbol-name source)))
|
||||||
|
file))
|
||||||
|
org-roam-tag-sources)))
|
||||||
|
(pcase org-roam-tag-sort
|
||||||
|
('nil tags)
|
||||||
|
((pred booleanp) (cl-sort tags 'string-lessp :key 'downcase))
|
||||||
|
(`(,(pred symbolp) . ,_)
|
||||||
|
(apply #'cl-sort (push tags org-roam-tag-sort)))
|
||||||
|
(wrong-type (signal 'wrong-type-argument
|
||||||
|
`((booleanp (list symbolp …))
|
||||||
|
,wrong-type))))))
|
||||||
|
|
||||||
(defun org-roam--ref-type-p (type)
|
(defun org-roam--ref-type-p (type)
|
||||||
"Return t if the ref from current buffer is TYPE."
|
"Return t if the ref from current buffer is TYPE."
|
||||||
@ -522,7 +531,7 @@ Examples:
|
|||||||
If LOWERCASE, downcase the title before insertion.
|
If LOWERCASE, downcase the title before insertion.
|
||||||
FILTER-FN is the name of a function to apply on the candidates
|
FILTER-FN is the name of a function to apply on the candidates
|
||||||
which takes as its argument an alist of path-completions.
|
which takes as its argument an alist of path-completions.
|
||||||
If DESCRIPTION is provided, use this as the link label. See
|
If DESCRIPTION is provided, use this as the link label. See
|
||||||
`org-roam--get-title-path-completions' for details."
|
`org-roam--get-title-path-completions' for details."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let* ((region (and (region-active-p)
|
(let* ((region (and (region-active-p)
|
||||||
@ -535,10 +544,12 @@ If DESCRIPTION is provided, use this as the link label. See
|
|||||||
(if filter-fn
|
(if filter-fn
|
||||||
(funcall filter-fn it)
|
(funcall filter-fn it)
|
||||||
it)))
|
it)))
|
||||||
(title (org-roam-completion--completing-read "File: " completions
|
(title-with-tags (org-roam-completion--completing-read "File: " completions
|
||||||
:initial-input region-text))
|
:initial-input region-text))
|
||||||
|
(res (gethash title-with-tags completions))
|
||||||
|
(title (plist-get res :title))
|
||||||
|
(target-file-path (plist-get res :path))
|
||||||
(description (or description region-text title))
|
(description (or description region-text title))
|
||||||
(target-file-path (cdr (assoc title completions)))
|
|
||||||
(link-description (org-roam--format-link-title (if lowercase
|
(link-description (org-roam--format-link-title (if lowercase
|
||||||
(downcase description)
|
(downcase description)
|
||||||
description))))
|
description))))
|
||||||
@ -550,8 +561,8 @@ If DESCRIPTION is provided, use this as the link label. See
|
|||||||
(insert (org-roam--format-link target-file-path link-description)))
|
(insert (org-roam--format-link target-file-path link-description)))
|
||||||
(when (org-roam-capture--in-process-p)
|
(when (org-roam-capture--in-process-p)
|
||||||
(user-error "Nested Org-roam capture processes not supported"))
|
(user-error "Nested Org-roam capture processes not supported"))
|
||||||
(let ((org-roam-capture--info (list (cons 'title title)
|
(let ((org-roam-capture--info `((title . ,title-with-tags)
|
||||||
(cons 'slug (org-roam--title-to-slug title))))
|
(slug . ,(org-roam--title-to-slug title-with-tags))))
|
||||||
(org-roam-capture--context 'title))
|
(org-roam-capture--context 'title))
|
||||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--insert-link-h)
|
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--insert-link-h)
|
||||||
(setq org-roam-capture-additional-template-props (list :region region
|
(setq org-roam-capture-additional-template-props (list :region region
|
||||||
@ -560,19 +571,32 @@ If DESCRIPTION is provided, use this as the link label. See
|
|||||||
(org-roam--with-template-error 'org-roam-capture-templates
|
(org-roam--with-template-error 'org-roam-capture-templates
|
||||||
(org-roam-capture--capture))))))
|
(org-roam-capture--capture))))))
|
||||||
|
|
||||||
|
(defcustom org-roam-tag-separator ","
|
||||||
|
"String to use to separate tags.
|
||||||
|
Only relevant when `org-roam-tag-sources' is non-nil."
|
||||||
|
:type 'string
|
||||||
|
:group 'org-roam)
|
||||||
|
|
||||||
(defun org-roam--get-title-path-completions ()
|
(defun org-roam--get-title-path-completions ()
|
||||||
"Return a list of cons pairs for titles to absolute path of Org-roam files."
|
"Return a hash table for completion.
|
||||||
(let* ((rows (org-roam-db-query [:select [file titles] :from titles]))
|
The key is the displayed title for completion, and the value is a
|
||||||
res)
|
plist containing the path to the file, and the original title."
|
||||||
|
(let* ((rows (org-roam-db-query [:select [titles:file titles:titles tags:tags] :from titles
|
||||||
|
:left :join tags
|
||||||
|
:on (= titles:file tags:file)]))
|
||||||
|
(ht (make-hash-table :test 'equal)))
|
||||||
(dolist (row rows)
|
(dolist (row rows)
|
||||||
(let ((file-path (car row))
|
(pcase-let ((`(,file-path ,titles ,tags) row))
|
||||||
(titles (cadr row)))
|
(let ((titles (or titles (list (org-roam--path-to-slug file-path)))))
|
||||||
(if titles
|
(dolist (title titles)
|
||||||
(dolist (title titles)
|
(let ((k (concat
|
||||||
(push (cons title file-path) res))
|
(if tags
|
||||||
(push (cons (org-roam--path-to-slug file-path)
|
(concat "(" (s-join org-roam-tag-separator tags) ") ")
|
||||||
file-path) res))))
|
"")
|
||||||
res))
|
title))
|
||||||
|
(v (list :path file-path :title title)))
|
||||||
|
(puthash k v ht))))))
|
||||||
|
ht))
|
||||||
|
|
||||||
(defun org-roam-find-file (&optional initial-prompt filter-fn)
|
(defun org-roam-find-file (&optional initial-prompt filter-fn)
|
||||||
"Find and open an Org-roam file.
|
"Find and open an Org-roam file.
|
||||||
@ -585,15 +609,16 @@ which takes as its argument an alist of path-completions. See
|
|||||||
(if filter-fn
|
(if filter-fn
|
||||||
(funcall filter-fn it)
|
(funcall filter-fn it)
|
||||||
it)))
|
it)))
|
||||||
(title (org-roam-completion--completing-read "File: " completions
|
(title-with-tags (org-roam-completion--completing-read "File: " completions
|
||||||
:initial-input initial-prompt))
|
:initial-input initial-prompt))
|
||||||
(file-path (cdr (assoc title completions))))
|
(res (gethash title-with-tags completions))
|
||||||
|
(file-path (plist-get res :path)))
|
||||||
(if file-path
|
(if file-path
|
||||||
(find-file file-path)
|
(find-file file-path)
|
||||||
(if (org-roam-capture--in-process-p)
|
(if (org-roam-capture--in-process-p)
|
||||||
(user-error "Org-roam capture in process")
|
(user-error "Org-roam capture in process")
|
||||||
(let ((org-roam-capture--info (list (cons 'title title)
|
(let ((org-roam-capture--info `((title . ,title-with-tags)
|
||||||
(cons 'slug (org-roam--title-to-slug title))))
|
(slug . ,(org-roam--title-to-slug title-with-tags))))
|
||||||
(org-roam-capture--context 'title))
|
(org-roam-capture--context 'title))
|
||||||
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h)
|
(add-hook 'org-capture-after-finalize-hook #'org-roam-capture--find-file-h)
|
||||||
(org-roam--with-template-error 'org-roam-capture-templates
|
(org-roam--with-template-error 'org-roam-capture-templates
|
||||||
|
1
tests/roam-files/base.org
Normal file
1
tests/roam-files/base.org
Normal file
@ -0,0 +1 @@
|
|||||||
|
#+TITLE: Base
|
1
tests/roam-files/nested/deeply/deeply_nested_file.org
Normal file
1
tests/roam-files/nested/deeply/deeply_nested_file.org
Normal file
@ -0,0 +1 @@
|
|||||||
|
#+TITLE: Deeply Nested File
|
3
tests/roam-files/tags/no_tag.org
Normal file
3
tests/roam-files/tags/no_tag.org
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#+TITLE: Tagless File
|
||||||
|
|
||||||
|
This file has no tags, and should not yield any tags on extracting via =#+ROAM_TAGS=.
|
4
tests/roam-files/tags/tag.org
Normal file
4
tests/roam-files/tags/tag.org
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#+ROAM_TAGS: "t1" "t2 with space" t3
|
||||||
|
#+TITLE: Tags
|
||||||
|
|
||||||
|
This file is used to test functionality for =(org-roam--extract-tags)=
|
@ -141,6 +141,72 @@
|
|||||||
:to-equal
|
:to-equal
|
||||||
'("Headline" "roam" "alias" "TITLE PROP"))))))
|
'("Headline" "roam" "alias" "TITLE PROP"))))))
|
||||||
|
|
||||||
|
(describe "Tag extraction"
|
||||||
|
:var (org-roam-tag-sources)
|
||||||
|
(before-all
|
||||||
|
(test-org-roam--init))
|
||||||
|
|
||||||
|
(after-all
|
||||||
|
(test-org-roam--teardown))
|
||||||
|
|
||||||
|
(cl-flet
|
||||||
|
((test (fn file)
|
||||||
|
(let* ((fname (test-org-roam--abs-path file))
|
||||||
|
(buf (find-file-noselect fname)))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(funcall fn fname)))))
|
||||||
|
(it "extracts from prop"
|
||||||
|
(expect (test #'org-roam--extract-tags-prop
|
||||||
|
"tags/tag.org")
|
||||||
|
:to-equal
|
||||||
|
'("t1" "t2 with space" "t3"))
|
||||||
|
(expect (test #'org-roam--extract-tags-prop
|
||||||
|
"tags/no_tag.org")
|
||||||
|
:to-equal
|
||||||
|
nil))
|
||||||
|
|
||||||
|
(it "extracts from all directories"
|
||||||
|
(expect (test #'org-roam--extract-tags-all-directories
|
||||||
|
"base.org")
|
||||||
|
:to-equal
|
||||||
|
nil)
|
||||||
|
(expect (test #'org-roam--extract-tags-all-directories
|
||||||
|
"tags/tag.org")
|
||||||
|
:to-equal
|
||||||
|
'("tags"))
|
||||||
|
(expect (test #'org-roam--extract-tags-all-directories
|
||||||
|
"nested/deeply/deeply_nested_file.org")
|
||||||
|
:to-equal
|
||||||
|
'("nested" "deeply")))
|
||||||
|
|
||||||
|
(it "extracts from last directory"
|
||||||
|
(expect (test #'org-roam--extract-tags-last-directory
|
||||||
|
"base.org")
|
||||||
|
:to-equal
|
||||||
|
nil)
|
||||||
|
(expect (test #'org-roam--extract-tags-last-directory
|
||||||
|
"tags/tag.org")
|
||||||
|
:to-equal
|
||||||
|
'("tags"))
|
||||||
|
(expect (test #'org-roam--extract-tags-last-directory
|
||||||
|
"nested/deeply/deeply_nested_file.org")
|
||||||
|
:to-equal
|
||||||
|
'("deeply")))
|
||||||
|
|
||||||
|
(describe "uses org-roam-tag-sources correctly"
|
||||||
|
(it "'(prop)"
|
||||||
|
(expect (let ((org-roam-tag-sources '(prop)))
|
||||||
|
(test #'org-roam--extract-tags
|
||||||
|
"tags/tag.org"))
|
||||||
|
:to-equal
|
||||||
|
'("t1" "t2 with space" "t3")))
|
||||||
|
(it "'(prop all-directories)"
|
||||||
|
(expect (let ((org-roam-tag-sources '(prop all-directories)))
|
||||||
|
(test #'org-roam--extract-tags
|
||||||
|
"tags/tag.org"))
|
||||||
|
:to-equal
|
||||||
|
'("t1" "t2 with space" "t3" "tags"))))))
|
||||||
|
|
||||||
;;; Tests
|
;;; Tests
|
||||||
(xdescribe "org-roam-db-build-cache"
|
(xdescribe "org-roam-db-build-cache"
|
||||||
(before-each
|
(before-each
|
||||||
@ -202,7 +268,7 @@
|
|||||||
;; Expect rebuilds to be really quick (nothing changed)
|
;; Expect rebuilds to be really quick (nothing changed)
|
||||||
(expect (org-roam-db-build-cache)
|
(expect (org-roam-db-build-cache)
|
||||||
:to-equal
|
:to-equal
|
||||||
(list :files 0 :links 0 :titles 0 :refs 0 :deleted 0))))
|
(list :files 0 :links 0 :tags 0 :titles 0 :refs 0 :deleted 0))))
|
||||||
|
|
||||||
(xdescribe "org-roam-insert"
|
(xdescribe "org-roam-insert"
|
||||||
(before-each
|
(before-each
|
||||||
@ -216,15 +282,15 @@
|
|||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(with-simulated-input
|
(with-simulated-input
|
||||||
"Foo RET"
|
"Foo RET"
|
||||||
(org-roam-insert nil))))
|
(org-roam-insert))))
|
||||||
(expect (buffer-string) :to-match (regexp-quote "file:foo.org")))
|
(expect (buffer-string) :to-match (regexp-quote "file:foo.org")))
|
||||||
|
|
||||||
(it "temp2 -> nested/foo"
|
(it "temp2 -> nested/foo"
|
||||||
(let ((buf (test-org-roam--find-file "temp2.org")))
|
(let ((buf (test-org-roam--find-file "temp2.org")))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(with-simulated-input
|
(with-simulated-input
|
||||||
"Nested SPC Foo RET"
|
"(nested) SPC Nested SPC Foo RET"
|
||||||
(org-roam-insert nil))))
|
(org-roam-insert))))
|
||||||
(expect (buffer-string) :to-match (regexp-quote "file:nested/foo.org")))
|
(expect (buffer-string) :to-match (regexp-quote "file:nested/foo.org")))
|
||||||
|
|
||||||
(it "nested/temp3 -> foo"
|
(it "nested/temp3 -> foo"
|
||||||
@ -232,15 +298,15 @@
|
|||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(with-simulated-input
|
(with-simulated-input
|
||||||
"Foo RET"
|
"Foo RET"
|
||||||
(org-roam-insert nil))))
|
(org-roam-insert))))
|
||||||
(expect (buffer-string) :to-match (regexp-quote "file:../foo.org")))
|
(expect (buffer-string) :to-match (regexp-quote "file:../foo.org")))
|
||||||
|
|
||||||
(it "a/b/temp4 -> nested/foo"
|
(it "a/b/temp4 -> nested/foo"
|
||||||
(let ((buf (test-org-roam--find-file "a/b/temp4.org")))
|
(let ((buf (test-org-roam--find-file "a/b/temp4.org")))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(with-simulated-input
|
(with-simulated-input
|
||||||
"Nested SPC Foo RET"
|
"(nested) SPC Nested SPC Foo RET"
|
||||||
(org-roam-insert nil))))
|
(org-roam-insert))))
|
||||||
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/foo.org"))))
|
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/foo.org"))))
|
||||||
|
|
||||||
(xdescribe "rename file updates cache"
|
(xdescribe "rename file updates cache"
|
||||||
|
Reference in New Issue
Block a user