mirror of
https://github.com/protesilaos/denote.git
synced 2026-09-16 02:06:23 -04:00
Introduce variable user-enforced-denote-directory
The full context is captured on the mailing list[^1]. In brief, the
problem and proposed solution:
Problem : Function `denote-directory` gives global preference to
`.dir-locals.el` in all contexts, with no way to override
it.
Solution : Allow an override so that users can create appropriate
wrapper functions which work properly in all contexts.
This commit adds a new variable `user-enforced-denote-directory`,
which the end-user can use in their wrapper functions to reliably
control which silo their function should execute in.
This commit also updates the README and modifies the following
functions to demonstrate the use of the variable:
- `my-denote-pick-silo-then-command` (this is the base-case)
- `my-denote-org-extract-subtree` (to cut notes from org files)
The section `Use custom commands to select a silo` contains a small
explanation of the new variable.
[^1]:
https://lists.sr.ht/~protesilaos/denote/%3CCABzEscY9f12VDk64nE9OXDJAZMjsLUT2vrw-es%3D4yO%3Dh6ZJ5wQ%40mail.gmail.com%3E#%3CCABzEscY9f12VDk64nE9OXDJAZMjsLUT2vrw-es=4yO=h6ZJ5wQ@mail.gmail.com%3E
This commit is contained in:
parent
2c54461a9d
commit
977c757f83
133
README.org
133
README.org
|
|
@ -817,47 +817,59 @@ read the video's path when called from there (e.g. by using Emacs'
|
|||
There are cases where the user (i) wants to maintain multiple silos
|
||||
and (ii) prefers an interactive way to switch between them without
|
||||
going through Dired. Since this is specific to the user's workflow,
|
||||
it is easier to have some custom code for it. The following should be
|
||||
it is easier to have some custom code for it. The following should be
|
||||
added to the user's Denote configuration:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defvar my-denote-silo-directories
|
||||
`("/home/prot/Videos/recordings"
|
||||
"/home/prot/Documents/books"
|
||||
;; You don't actually need to include the `denote-directory' here
|
||||
;; if you use the regular commands in their global context. I am
|
||||
;; including it for completeness.
|
||||
,denote-directory)
|
||||
"List of file paths pointing to my Denote silos.
|
||||
This is a list of strings.")
|
||||
(defvar my-denote-silo-directories
|
||||
`("/home/prot/Videos/recordings"
|
||||
"/home/prot/Documents/books"
|
||||
;; You don't actually need to include the `denote-directory' here
|
||||
;; if you use the regular commands in their global context. I am
|
||||
;; including it for completeness.
|
||||
,denote-directory)
|
||||
"List of file paths pointing to my Denote silos.
|
||||
This is a list of strings.")
|
||||
|
||||
(defvar my-denote-commands-for-silos
|
||||
'(denote
|
||||
denote-date
|
||||
denote-subdirectory
|
||||
denote-template
|
||||
denote-type)
|
||||
"List of Denote commands to call after selecting a silo.
|
||||
This is a list of symbols that specify the note-creating
|
||||
interactive functions that Denote provides.")
|
||||
(defvar my-denote-commands-for-silos
|
||||
'(denote
|
||||
denote-date
|
||||
denote-subdirectory
|
||||
denote-template
|
||||
denote-type)
|
||||
"List of Denote commands to call after selecting a silo.
|
||||
This is a list of symbols that specify the note-creating
|
||||
interactive functions that Denote provides.")
|
||||
|
||||
(defun my-denote-pick-silo-then-command (silo command)
|
||||
"Select SILO and run Denote COMMAND in it.
|
||||
SILO is a file path from `my-denote-silo-directories', while
|
||||
COMMAND is one among `my-denote-commands-for-silos'."
|
||||
(interactive
|
||||
(list (completing-read "Select a silo: " my-denote-silo-directories nil t)
|
||||
(intern (completing-read
|
||||
"Run command in silo: "
|
||||
my-denote-commands-for-silos nil t))))
|
||||
(let ((denote-directory silo))
|
||||
(call-interactively command)))
|
||||
(defun my-denote-pick-silo-then-command (silo command)
|
||||
"Select SILO and run Denote COMMAND in it.
|
||||
SILO is a file path from `my-denote-silo-directories', while
|
||||
COMMAND is one among `my-denote-commands-for-silos'."
|
||||
(interactive
|
||||
(list (completing-read "Select a silo: " my-denote-silo-directories nil t)
|
||||
(intern (completing-read
|
||||
"Run command in silo: "
|
||||
my-denote-commands-for-silos nil t))))
|
||||
(let ((user-enforced-denote-directory silo))
|
||||
(call-interactively command)))
|
||||
#+end_src
|
||||
|
||||
With this in place, =M-x my-denote-pick-silo-then-command= will use
|
||||
minibuffer completion to select a silo among the predefined options
|
||||
and then ask for the command to run in that context.
|
||||
|
||||
Note the use of the variable ~user-enforced-denote-directory~. This
|
||||
variable is specially meant for custom commands to select silos. When
|
||||
it is set, it overrides the global default value of ~denote-directory~
|
||||
as well as the value provided by the =.dir-locals.el= file. Use it
|
||||
only when writing wrapper functions like
|
||||
~my-denote-pick-silo-then-command~.
|
||||
|
||||
To see another example of a wrapper function that uses
|
||||
~user-enforced-denote-directory~, see:
|
||||
|
||||
[[#h:d0c7cb79-21e5-4176-a6af-f4f68578c8dd][Extending Denote: Split an Org subtree into its own note]].
|
||||
|
||||
** Exclude certain directories from all operations
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: h:8458f716-f9c2-4888-824b-2bf01cc5850a
|
||||
|
|
@ -2304,35 +2316,42 @@ file. The contents of the subtree become the contents of the new note
|
|||
and are removed from the old one.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun my-denote-org-extract-subtree ()
|
||||
"Create new Denote note using current Org subtree.
|
||||
Make the new note use the Org file type, regardless of the value
|
||||
of `denote-file-type'.
|
||||
(defun my-denote-org-extract-subtree (&optional silo)
|
||||
"Create new Denote note using current Org subtree.
|
||||
Make the new note use the Org file type, regardless of the value
|
||||
of `denote-file-type'.
|
||||
|
||||
Use the subtree title as the note's title. If available, use the
|
||||
tags of the heading are used as note keywords.
|
||||
With an optional SILO argument as a
|
||||
prefix (\\[universal-argument]), ask user to select a SILO from
|
||||
`my-denote-silo-directories`.
|
||||
|
||||
Delete the original subtree."
|
||||
(interactive)
|
||||
(if-let ((text (org-get-entry))
|
||||
(heading (org-get-heading :no-tags :no-todo :no-priority :no-comment)))
|
||||
(let ((element (org-element-at-point))
|
||||
(tags (org-get-tags)))
|
||||
(delete-region (org-entry-beginning-position)
|
||||
(save-excursion (org-end-of-subtree t) (point)))
|
||||
(denote heading
|
||||
tags
|
||||
'org
|
||||
nil
|
||||
(or
|
||||
;; Check PROPERTIES drawer for :created: or :date:
|
||||
(org-element-property :CREATED element)
|
||||
(org-element-property :DATE element)
|
||||
;; Check the subtree for CLOSED
|
||||
(org-element-property :raw-value
|
||||
(org-element-property :closed element))))
|
||||
(insert text))
|
||||
(user-error "No subtree to extract; aborting")))
|
||||
Use the subtree title as the note's title. If available, use the
|
||||
tags of the heading are used as note keywords.
|
||||
|
||||
Delete the original subtree."
|
||||
(interactive
|
||||
(list (when current-prefix-arg
|
||||
(completing-read "Select a silo: " my-denote-silo-directories nil t))))
|
||||
(if-let ((text (org-get-entry))
|
||||
(heading (org-get-heading :no-tags :no-todo :no-priority :no-comment)))
|
||||
(let ((element (org-element-at-point))
|
||||
(tags (org-get-tags))
|
||||
(user-enforced-denote-directory silo))
|
||||
(delete-region (org-entry-beginning-position)
|
||||
(save-excursion (org-end-of-subtree t) (point)))
|
||||
(denote heading
|
||||
tags
|
||||
'org
|
||||
nil
|
||||
(or
|
||||
;; Check PROPERTIES drawer for :created: or :date:
|
||||
(org-element-property :CREATED element)
|
||||
(org-element-property :DATE element)
|
||||
;; Check the subtree for CLOSED
|
||||
(org-element-property :raw-value
|
||||
(org-element-property :closed element))))
|
||||
(insert text))
|
||||
(user-error "No subtree to extract; aborting")))
|
||||
#+end_src
|
||||
|
||||
Have a different workflow? Feel welcome to discuss it in any of our
|
||||
|
|
|
|||
10
denote.el
10
denote.el
|
|
@ -531,9 +531,17 @@ things accordingly.")
|
|||
(not (file-directory-p denote-directory)))
|
||||
(make-directory denote-directory :parents)))
|
||||
|
||||
(defvar user-enforced-denote-directory nil
|
||||
"Meant to be used to hard-code the denote-directory in a let binding.
|
||||
|
||||
This is useful when the user is writing Lisp code. It helps them
|
||||
be sure nothing else can override the value of the
|
||||
denote-directory they want.")
|
||||
|
||||
(defun denote-directory ()
|
||||
"Return path of variable `denote-directory' as a proper directory."
|
||||
(let ((path (or (denote--default-directory-is-silo-p)
|
||||
(let ((path (or user-enforced-denote-directory
|
||||
(denote--default-directory-is-silo-p)
|
||||
(denote--make-denote-directory)
|
||||
(default-value 'denote-directory))))
|
||||
(file-name-as-directory (expand-file-name path))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue