Fix denote: link previews during Org mode startup in silos - #715
Conversation
Directory-local variables are applied only after the major mode body
has run: 'run-mode-hooks' calls 'hack-local-variables' after the mode
hooks. Anything that resolves Denote paths while the mode is still
initializing therefore sees the global 'denote-directory' instead of
the silo's dir-local value. Org's startup link previews
('org-startup-with-link-previews') are one such case: previews of
'denote:' links inside a silo resolve against the wrong directory.
Make 'denote-directories' read the dir-local value directly from the
directory-local variables data in that window. A buffer-local value
or an explicit dynamic binding of 'denote-directory' still takes
precedence, preserving the documented let-binding override.
The read uses 'hack-dir-local--get-variables', which is available in
Emacs 30 or higher; older versions behave as before. The value is
read without the safe-local-variable filter, which is equivalent for
this variable because its 'safe-local-variable' predicate accepts any
string or list value.
denote-link-preview-file passed the resolved link target straight to
org-link-preview-file. When the identifier does not resolve to a
file, that target is nil and org-link-preview-file signals
wrong-type-argument. With link previews enabled at startup
('org-startup-with-link-previews'), the error aborts the entire
org-mode setup, leaving the buffer half-initialized with
directory-local variables never applied.
Skip the preview instead when the target does not resolve.
|
Thank you @lewang for doing this! For some reason I did not receive the notification and am only noticing this now.
I remember having such a problem one time, which had to do with my Otherwise, yes, I am keen on fixing this problem. |
|
No trouble at all about the notification. Thank you for the Just a note that the repro below is generated with AI assistance, but the script Yes, it happens consistently: the unpatched build failed on every run and Two things hide it:
It also needs Org >= 9.8, where the RecipeHands-off version, which pins Org from GNU ELPA into a throwaway init sh repro-715.sh /path/to/denoteBy hand: mkdir -p /tmp/silo /tmp/elsewhere
printf '((nil . ((denote-directory . "/tmp/silo"))))\n' > /tmp/silo/.dir-locals.el
cp any-image.png /tmp/silo/20260101T000001--pic__test.png
cat > /tmp/silo/20260101T000000--note__test.org <<'EOF'
#+title: note
#+identifier: 20260101T000000
[[denote:20260101T000001]]
EOF
emacs -Q -L /path/to/denoteM-: (progn (setq-default denote-directory "/tmp/elsewhere")
(require 'denote)
(setq org-startup-with-link-previews t))
C-x C-f /tmp/silo/20260101T000000--note__test.orgThen: the echo area flashes the error ( Cause
The two commitsTested separately, since either alone leaves something broken:
|
Follow-up to the
:previewsupport from #317. Withorg-startup-with-link-previewsenabled, previews ofdenote:linksfail in two ways when the notes live in a silo (a dir-local
denote-directory).Problem
run-mode-hookscallshack-local-variablesonly after the modehooks. Org renders startup link previews inside the
org-modebody,so
denote-directoriesresolves identifiers against the globaldenote-directoryinstead of the silo's dir-local value.denote-link-preview-filepasses nil to
org-link-preview-file, which signalswrong-type-argument. During startup previews this aborts theentire
org-modesetup, leaving the buffer half-initialized withdirectory-local variables never applied.
Changes
denote-directoriesnow honors a dir-localdenote-directorythathas not yet been applied to the buffer. A new helper,
denote-directories--dir-local-value, reads the value from thedirectory-local variables data on demand.
denote-link-preview-fileskips the preview when the target doesnot resolve, instead of erroring.
Technical Details
hack-dir-local--get-variables, availablein Emacs 30 or higher; the call is
fboundp-guarded, so olderversions behave exactly as before.
denote-directorystill takes precedence, preserving the documentedlet-binding override of
denote-directories.equivalent for this variable: its
safe-local-variablepredicateaccepts any string or list value.
Testing
tests/denote-test.el: the unapplied dir-localvalue is honored; a dynamic binding and a buffer-local value each
take precedence; an unresolvable preview target returns nil without
error.
with
org-startup-with-link-previewsnow initializes fully andrenders
denote:image previews.