Compare commits

...

35 commits
4.2.1 ... main

Author SHA1 Message Date
Protesilaos 110ced9999
Acknowledge kimsaram32 for commit 840ca21
This was done in pull request 728: <https://github.com/protesilaos/denote/pull/728>.
The change is small, meaning that its author does not need to assign
copyright to the Free Software Foundation.
2026-09-09 14:37:04 +03:00
Protesilaos 32d83aa68b
Merge pull request #728 from kimsaram32/docs-remove-obsolete-functions
Remove obsolete functions in the documentation
2026-09-09 14:35:59 +03:00
kimsaram32 840ca21f92 Remove obsolete functions in the documentation 2026-09-09 19:31:13 +09:00
Protesilaos 0a157981e5
Rename a helper function to be private and have a more accurate name
Also tweak its docstring.
2026-08-28 16:40:30 +03:00
Protesilaos 2c8cf137ac
Fix typo in the manual
Thanks to Ali Bozorgzadeh for reporting it in issue 727:
<https://github.com/protesilaos/denote/issues/727>.
2026-08-27 17:38:03 +03:00
Protesilaos e401e70405
Merge pull request #726 from jeanphilippegg/move-unix-timestamps-code
Move Unix timestamps code in `denote-valid-date-p`
2026-08-24 12:35:53 +03:00
Jean-Philippe Gagné Guay ec73303bff Move Unix timestamps code in denote-valid-date-p 2026-08-23 21:38:04 -04:00
Protesilaos 42085330f3
Update the :package-version of denote-org-store-link-to-heading
This is because it now has a new option, per commit b90b26e (pull
request 723 by Michael Korat: <https://github.com/protesilaos/denote/pull/723>).
2026-08-23 13:33:39 +03:00
Protesilaos 27cdd67b68
Document denote-org-store-link-to-heading "local" value in the manual
This was introduced by Michael Korat in commit 9a354e4 as part of pull
request 723: <https://github.com/protesilaos/denote/pull/723>.
2026-08-23 13:31:39 +03:00
Protesilaos b90b26e938
Acknowledge Michael Korat for commit 9a354e4
This was done in pull request 723: <https://github.com/protesilaos/denote/pull/723>.
The change is small, meaning that Michael does not need to assign
copyright to the Free Software Foundation.
2026-08-23 13:06:01 +03:00
Protesilaos 5effab91ca
Merge pull request #723 from mkorat/main
Add option to use simple heading links to denote-link-ol-store.
2026-08-23 13:05:08 +03:00
Protesilaos 9ae9d0e1ea
Make stylistic change to denote--date-parse-string
The original was contributed by Jeff Valk in commit 9083ad7, pull
request 722: <https://github.com/protesilaos/denote/pull/722>.
2026-08-10 11:38:16 +03:00
Protesilaos 8f7e988a67
Acknowledge Jeff Valk for commit 9083ad7
This was done in pull request 722: <https://github.com/protesilaos/denote/pull/722>.
The change is small, meaning that Jeff does not need to assign
copyright to the Free Software Foundation.
2026-08-10 11:30:39 +03:00
Protesilaos 7d0c06e0a4
Merge pull request #722 from jeffvalk/main
Support Unix timestamps in date input
2026-08-10 11:29:47 +03:00
Michael Korat 9a354e4362 Add option to use simple heading links to denote-link-ol-store. 2026-08-09 20:58:32 +02:00
Jeff Valk 9083ad781e Support Unix timestamps in date input
This allows for other recognized date patterns to be supported as well.
2026-07-31 12:20:10 -04:00
Protesilaos 3718a60305
Make denote-query-focus-last-search reuse the existing query buffer 2026-07-29 13:05:00 +03:00
Protesilaos 5b632ae958
Make denote-query-* commands work as intended in the backlinks buffer
Thanks to 82Kang for reporting the bug in issue 695:
<https://github.com/protesilaos/denote/issues/695>.
2026-07-29 13:04:16 +03:00
Protesilaos b4978d83cb
Make denote-link--collect-identifiers remove duplicates
Thanks to 82Kang for reporting the bug in issue 694:
<https://github.com/protesilaos/denote/issues/694>.
2026-07-29 12:55:45 +03:00
Protesilaos c8aa01c56a
Add denote-slug-remove-accents function
This is based on the code originally written by Jean-Philippe Gagné
Guay in issue 603: <https://github.com/protesilaos/denote/issues/603#issuecomment-2869702877>.
I made stylistic changes to it to make it fit with the rest of denote.el.

I am adding this in response to issue 603 and 718:

- <https://github.com/protesilaos/denote/issues/603> with
  participation from Davi Ramos and Jean-Philippe Gagné Guay;
- <https://github.com/protesilaos/denote/issues/718> with
  participation from o-rxw and Alan Schmitt.

In implementing this, I am changing my mind that this is purely a
documentation issue. I realised it is better for us to have the main
function in denote.el, so that we can test it better.
2026-07-27 19:53:13 +03:00
Protesilaos 1004f735b7
Mention the SIGNATURE in the docstring of all front matter variables
Thanks to Alan Schmitt for telling me this was missing. It was done in
issue 714: <https://github.com/protesilaos/denote/issues/714>.
2026-07-07 22:56:49 +03:00
Protesilaos 65f1bbf1de
Acknowledge Pavlo V. Lysov for commit 72d90f4
This is about mentioning Pavlo's 'denote-solo' package in the Denote
manual.

Done in pull request 713: <https://github.com/protesilaos/denote/pull/713>.
2026-07-06 10:31:07 +03:00
Protesilaos 8c80d91d06
Merge pull request #713 from pavlo/main
Add a section for denote-solo package
2026-07-06 10:28:12 +03:00
Pavlo V. Lysov 72d90f474e Add a section for denote-solo package 2026-07-06 08:49:53 +03:00
Protesilaos cd422b1d22
Acknowledge Matthieu Muller for commit 35d3a2a
This was done in pull request 711: <https://github.com/protesilaos/denote/pull/711>.
The change is small, menaing that Matthieu does not need to assign
copyright to the Free Software Foundation.
2026-06-11 21:41:01 +03:00
Protesilaos 04c39a157f
Merge pull request #711 from matthieumuller/add-denote-paperless-to-docs
Add a section on denote-paperless.el in the documentation
2026-06-11 21:39:34 +03:00
Matthieu MULLER 35d3a2a724 Add a section on denote-paperless.el in the documentation 2026-06-11 14:12:31 -04:00
Protesilaos 9fd6692a32
Bump version number to trigger GNU ELPA package rebuild to include commit 420710f 2026-05-27 20:30:00 +03:00
Protesilaos 420710fb17
Ensure :get-file-type-function is called only when file exists
Otherwise we get an error upon creating the file.

Thanks to potchie-maker for reporting the bug in issue 709:
<https://github.com/protesilaos/denote/issues/709>.
2026-05-27 20:28:38 +03:00
Protesilaos 77813e9956
Bump version number to trigger GNU ELPA rebuild
I am bumping it straight to 4.2.2 because I had a tag earlier for
4.2.1 even though I forgot to update this header...
2026-05-23 23:15:15 +03:00
Protesilaos cf1c81cba9
Make stylistic tweak to denote-file-prompt--format-identifier 2026-05-23 23:12:49 +03:00
Protesilaos 32960f828b
Acknowledge Marco Baringer for commits d47464e, 6ba2097
Those were sent as part of pull request 708: <https://github.com/protesilaos/denote/pull/708>.

The changes are small, meaning that Marco does not need to assign
copyright to the Free Software Foundation.
2026-05-23 23:10:04 +03:00
Protesilaos 197b0acd38
Merge pull request #708 from segv/main
denote-open-or-create errors in directories with oddly-named files (#707)
2026-05-23 23:09:24 +03:00
Marco Baringer d47464e23b
Require non-empty captures in the four field regexps
denote-{identifier,signature,title,keywords}-regexp used a lazy
zero-or-more capture ([^.]*?), so they matched the bare separator
followed by an extension, e.g. __.js, --.org, ==.org, @@.org. Combined
with denote-file-has-denoted-filename-p, this meant such files were
treated as valid denote notes. lodash's node_modules ships __.js files,
which made a denote-directory containing a lodash checkout enumerate
junk candidates in the file prompt (and previously crash, see preceding
commit).

Switch to a non-empty lazy capture ([^.]+?) so the field must contain at
least one character.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:20:49 +02:00
Marco Baringer 6ba209704d
Fix file-prompt crash when denote-directory contains files like __.js
Using denote in a directory that includes files matching '*/__.js'
breaks with "Wrong type argument: stringp, nil" on the file prompt.
lodash ships such files in node_modules, so accidentally pointing
denote at a lodash checkout (or having one under denote-directory)
triggers the error.

These files pass denote-file-has-denoted-filename-p because the empty
keywords section matches denote-keywords-regexp, but they have no
identifier, so denote-file-prompt--format-identifier passed nil to
propertize during affixation. Return nil in that case;
denote-file-prompt-affixate already substitutes "" for a nil prefix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:17:47 +02:00
3 changed files with 236 additions and 77 deletions

View file

@ -246,7 +246,7 @@ Here we include more of what you can configure with Denote ([[#h:998ae528-9276-4
:END:
At its core, Denote is a file-naming scheme ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
It is applies to new text files that Denote creates or to existing
It applies to new text files that Denote creates or to existing
files of any type (videos, PDFs, images, ...). Here is the big picture
view on how to get started with Denote:
@ -2450,6 +2450,8 @@ You have been warned.
:CUSTOM_ID: h:d1e4eb5b-e7f2-4a3b-9243-e1c653817a4a
:END:
[ Also see: [[#h:65a6a2ec-02b9-4c9e-995f-19dfe0611e20][Custom sluggification to remove diacterics or accented characters]]. ]
A common use-case for Denote is to rename files such as videos
downloaded from the Internet. Sometimes, those files have Unicode
characters that (i) not all fonts support and (ii) create all sorts of
@ -2482,7 +2484,52 @@ use the following in their Emacs configuration ([[#h:d375c6d2-92c7-425f-9d9d-219
(denote-slug-keep-only-ascii str))))
(defcustom denote-file-name-slug-functions
'((title . my-denote-sluggify-title)
'((identifier . identity) ; keep the original
(title . my-denote-sluggify-title)
(signature . my-denote-sluggify-signature)
(keyword . my-denote-sluggify-keyword)))
#+end_src
*** Custom sluggification to remove diacterics or accented characters
:PROPERTIES:
:CUSTOM_ID: h:65a6a2ec-02b9-4c9e-995f-19dfe0611e20
:END:
[ Also see: [[#h:d1e4eb5b-e7f2-4a3b-9243-e1c653817a4a][Custom sluggification to remove non-ASCII characters]]. ]
For languages with diacretics, like =ê= and =ñ=, users may want to
instruct Denote to remove the diacretical marks from the underlying
characters. This way, the file names will be uniform and easier to
search through, instead of checking if, say, =être= is written thus or
as =etre=.
This is only for the sluggification of file name components ([[#h:d375c6d2-92c7-425f-9d9d-219ff47ed2a3][User-defined sluggification of file name components]]).
Any front matter will retain the diacretics.
#+begin_src emacs-lisp
;; These are the same as the default Denote sluggification functions,
;; except they remove all diacretics from the underlying characters
;; (e.g. ê becomes e while ñ becomes n).
(defun my-denote-sluggify-title (str)
(downcase
(denote-slug-hyphenate
(replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" ""
(denote-slug-remove-accents str)))))
(defun my-denote-sluggify-signature (str)
(downcase
(denote-slug-put-equals
(replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/-]*" ""
(denote-slug-remove-accents str)))))
(defun my-denote-sluggify-keyword (str)
(downcase
(replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/_ =-]*" ""
(denote-slug-remove-accents str))))
(defcustom denote-file-name-slug-functions
'((identifier . identity) ; keep the original
(title . my-denote-sluggify-title)
(signature . my-denote-sluggify-signature)
(keyword . my-denote-sluggify-keyword)))
#+end_src
@ -3027,8 +3074,9 @@ The variables which hold the front matter format are:
- ~denote-yaml-front-matter~
These variables have a string value with specifiers that are used by the
~format~ function. The formatting operation passes four arguments which
include the values of the given entries. If you are an advanced user
~format~ function. The formatting operation passes five arguments which
include the values of the given entries: =TITLE=, =DATE=, =KEYWORDS=,
=IDENTIFIER=, and =SIGNATURE=. If you are an advanced user
who wants to edit this variable to affect how front matter is produced,
consider using something like =%2$s= to control where the Nth argument
is placed.
@ -3053,6 +3101,7 @@ for all variables.
#+DATE: %s
#+FILETAGS: %s
#+IDENTIFIER: %s
#+SIGNATURE: %s
\n")
;; Change the order (notice the %N$s notation)
@ -3061,6 +3110,7 @@ for all variables.
#+filetags: %3$s
#+date: %2$s
#+identifier: %4$s
#+signature: %5$s
\n")
;; Remove the date
@ -3068,12 +3118,14 @@ for all variables.
"#+title: %1$s
#+filetags: %3$s
#+identifier: %4$s
#+signature: %5$s
\n")
;; Remove the date and the identifier
(setq denote-org-front-matter
"#+title: %1$s
#+filetags: %3$s
#+signature: %5$s
\n")
#+end_src
@ -3362,9 +3414,16 @@ and the text of the current heading, like this:
: [[denote:20240118T060608::*Heading text][Some test::Heading text]].
If the value is ~local~, the link consists of the text of the current
heading, like this:
: [[*Heading text][Heading text]].
[ The ~local~ option is part of {{{development-version}}}. ]
However, if there already exists a =CUSTOM_ID= property for the
current heading, this is always given priority and is used instead of
the context.
the context or local heading.
If the value is ~id~ or, for backward-compatibility, any other non-nil
value, then Denote will use the standard Org mechanism of the
@ -4449,6 +4508,29 @@ across their configuration.
+ Git repository: <https://github.com/protesilaos/denote-silo>
+ Backronym: Denote... Silos Insulate Localised Objects.
** Use the ~denote-solo~ package
:PROPERTIES:
:CUSTOM_ID: h:3db6bbfb-e5b5-45a1-8064-ce52834436a2
:END:
Denote can operate on one of several independent note collections,
what Denote calls "silos" ([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directory silos for notes]]).
The ~denote-silo~ package helps with this by prompting the user to
pick a silo on every command.
The ~denote-solo~ package by Pavlo V. Lysov takes the opposite stance:
instead of prompting for a directory on every command, the user picks
one - a *solo* - once, and every subsequent Denote command operates on
it until the user switches again.
The active solo is remembered across Emacs sessions and shown in the
mode line. Its ~denote-keyword-history~ is kept separate per solo, so
keyword completions do not leak between collections. Toggling back and
forth between two solos takes a single keystroke, as the previously
active one is pre-selected in the switching prompt.
+ Git repository: <https://github.com/pavlo/denote-solo>
** Use the ~denote-search~ package as a search interface
:PROPERTIES:
:CUSTOM_ID: h:c905b733-e959-4aa4-8f2c-0ed9eba459df
@ -4721,6 +4803,27 @@ between file name and front matter, the validity of links, and
related. The package defines multiple warning levels, each with its
own semantics. Learn more here: <https://github.com/psmith1303/denote-lint>.
** Use the ~denote-paperless~ package
:PROPERTIES:
:CUSTOM_ID: h:2617d7ec-501d-4554-85ee-d4ca801e5bb2
:END:
The ~denote-paperless~ package by Matthieu Muller allows the user to
easily manage administrative document files such as bills, letters,
taxes, etc.
The workflow it implements is heavily inspired from how [[https://docs.paperless-ngx.com/][Paperless-ngx]]
operates: giving each document a date, a type, a correspondent, a
title, some keywords and (optionally) an archive serial number. It
leverage the ~SIGNATURE~ component to insert these new elements in the
file name.
The package is designed to be used alongside Denote: manage your notes
with Denote and your documents with Denote Paperless.
Read more from the packages documentation:
<https://codeberg.org/matthieumuller/denote-paperless>
* Extending Denote
:PROPERTIES:
:CUSTOM_ID: h:8ed2bb6f-b5be-4711-82e9-8bee5bb06ece
@ -4844,9 +4947,9 @@ commands:
#+begin_src emacs-lisp
(defun my-denote--note-has-no-contents-p (file)
"Return non-nil if FILE is an empty note.
This means that FILE conforms with `denote-file-is-note-p' and either
This means that FILE conforms with `denote-file-has-denoted-filename-p' and either
has no contents or has only the front matter."
(and (denote-file-is-note-p file)
(and (denote-file-has-denoted-filename-p file)
(or (denote--file-with-temp-buffer file
(re-search-forward "^$" nil t)
(if (re-search-forward "[^\s\t\n\r]+" nil t)
@ -4937,7 +5040,7 @@ title or keywords fields.
Add this function to the `after-save-hook'."
(let ((denote-rename-confirmations nil)
(denote-save-buffers t)) ; to save again post-rename
(when (and buffer-file-name (denote-file-is-note-p buffer-file-name))
(when (and buffer-file-name (denote-file-has-denoted-filename-p buffer-file-name))
(ignore-errors (denote-rename-file-using-front-matter buffer-file-name))
(message "Buffer saved; Denote file renamed"))))
@ -5656,11 +5759,6 @@ The following sections cover the specifics.
+ Function ~denote-date-identifier-p~ :: Return non-nil if =IDENTIFIER=
string is a Denote date identifier.
#+findex: denote-file-is-note-p
+ Function ~denote-file-is-note-p~ :: Return non-nil if =FILE= is an
actual Denote note. For our purposes, a note must satisfy
~file-regular-p~ and ~denote-filename-is-note-p~.
#+findex: denote-file-has-identifier-p
+ Function ~denote-file-has-identifier-p~ :: Return non-nil if =FILE=
has a Denote identifier.
@ -5945,10 +6043,6 @@ there will be no corresponding prompt.
+ Function ~denote-get-path-by-id~ :: Return absolute path of =ID=
string in ~denote-directory-files~.
#+findex: denote-get-identifier-at-point
+ Function ~denote-get-identifier-at-point~ :: Return the identifier
at point or =POINT=.
#+findex: denote-extract-keywords-from-path
+ Function ~denote-extract-keywords-from-path~ :: Extract keywords
from =PATH= and return them as a list of strings. =PATH= must be a
@ -6127,22 +6221,22 @@ there will be no corresponding prompt.
#+vindex: denote-org-front-matter
+ Variable ~denote-org-front-matter~ :: Specifies the Org front
matter. It is passed to ~format~ with arguments =TITLE=, =DATE=,
=KEYWORDS=, =ID= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
=KEYWORDS=, =IDENTIFIER=, =SIGNATURE= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
#+vindex: denote-yaml-front-matter
+ Variable ~denote-yaml-front-matter~ :: Specifies the YAML (Markdown)
front matter. It is passed to ~format~ with arguments =TITLE=,
=DATE=, =KEYWORDS=, =ID= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
=DATE=, =KEYWORDS=, =IDENTIFIER=, =SIGNATURE= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
#+vindex: denote-toml-front-matter
+ Variable ~denote-toml-front-matter~ :: Specifies the TOML (Markdown)
front matter. It is passed to ~format~ with arguments =TITLE=,
=DATE=, =KEYWORDS=, =ID= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
=DATE=, =KEYWORDS=, =IDENTIFIER=, =SIGNATURE= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
#+vindex: denote-text-front-matter
+ Variable ~denote-text-front-matter~ :: Specifies the plain text
front matter. It is passed to ~format~ with arguments =TITLE=,
=DATE=, =KEYWORDS=, =ID= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
=DATE=, =KEYWORDS=, =IDENTIFIER=, =SIGNATURE= ([[#h:7f918854-5ed4-4139-821f-8ee9ba06ad15][Change the front matter format]])
#+findex: denote-date-org-timestamp
+ Function ~denote-date-org-timestamp~ :: Format =DATE= using the Org
@ -6309,8 +6403,8 @@ there will be no corresponding prompt.
an identifier-only link in its context. The format of such links is
~denote-id-only-link-format~.
#+findex: denote-select-linked-file-prompt
+ Function ~denote-select-linked-file-prompt~ :: Prompt for linked
#+findex: denote-select-from-files-prompt
+ Function ~denote-select-from-files-prompt~ :: Prompt for linked
file among =FILES=.
#+findex: denote-get-links
@ -6343,6 +6437,10 @@ there will be no corresponding prompt.
~denote-link-description-format~ (which can optionally be bound to a
function).
#+findex: denote-get-link-identifier-or-query-term-at-point
+ Function ~denote-get-link-identifier-or-query-term-at-point~ :: Return the
Denote identifier or query term at point or optional =POSITION=.
** Xref interface for developers or advanced users
:PROPERTIES:
:CUSTOM_ID: h:e824c215-1c31-4b26-b994-7df67341d075
@ -7097,43 +7195,46 @@ Denote is meant to be a collective effort. Every bit of help matters.
Colin McLear, Damien Cassou, Eduardo Grajeda, Elias Storms, Eshel
Yaron, Florian, Glenna D., Graham Marlow, Hilde Rhyne, Ivan Sokolov,
Jack Baty, Jakub Szczerbowski, James Kalyan, Jean-Charles Bagneris,
Jean-Philippe Gagné Guay, Jianwei Hou, Joseph Turner, Jürgen Hötzel,
Kaushal Modi, Kai von Fintel, Kierin Bell, Kostas Andreadis,
Kristoffer Balintona, Kyle Meyer, Laurent Gatto, Lucas Quintana,
Maikol Solis, Marc Fargas, Matthew Batson, Matthew Lemon, Matto
Fransen, Noboru Ota (nobiot), Norwid Behrnd, Octavian, Peter Prevos,
Jean-Philippe Gagné Guay, Jeff Valk, Jianwei Hou, Joseph Turner,
Jürgen Hötzel, Kaushal Modi, Kai von Fintel, Kierin Bell, Kostas
Andreadis, Kristoffer Balintona, Kyle Meyer, Laurent Gatto, Lucas
Quintana, Maikol Solis, Marc Fargas, Marco Baringer, Matthew Batson,
Matthew Lemon, Matthieu Muller, Matto Fransen, Michael Korat, Noboru
Ota (nobiot), Norwid Behrnd, Octavian, Pavlo V. Lysov, Peter Prevos,
Philip Kaludercic, Ryota, Samuel W. Flint, Quiliro Ordóñez, Stephen
R. Kifer, Stefan Monnier, Stefan Thesing, Thibaut Benjamin, Tobias
Lidman-Strauss, Tomasz Hołubowicz, TomoeMami , Vedang Manerikar,
Wesley Harvey, Yann Dutrieux, Zhenxu Xu, alvmts, arsaber101,
bplubell, bryanrinders, dulikiles, eum3l, experimental-code-86,
ezchi, gnuhack, gvalson, jarofromel, leinfink (Henrik), l-o-l-h
(Lincoln), mattyonweb, maxbrieiev, mentalisttraceur, nescias,
pmenair, relict007, skissue.
ezchi, gnuhack, gvalson, jarofromel, kimsaram32, leinfink (Henrik),
l-o-l-h (Lincoln), mattyonweb, maxbrieiev, mentalisttraceur,
nescias, pmenair, relict007, skissue.
+ Ideas and/or user feedback :: Abin Simon, Aditya Yadav, Alan
Schmitt, Aleksandr Vityazev, Alex Griffin, Alex Hirschfeld, Alexis
Purslane, Alfredo Borrás, Alp Eren Kose, André Bering, Ashton
Wiersdorf, Bhargav Kulkarni, Benjamin Kästner, Claudio Migliorelli,
Claudiu Tănăselia, Colin McLear, Cosmin-Octavian C, Damien Cassou,
Elias Storms, Federico Stilman, Florian, Frédéric Willem Frank
Ehmsen, Glenna D., Guo Yong, Hanspeter Gisler Harold Ollivier,
IceAsteroid, Jack Baty, Jay Rajput, Jean-Charles Bagneris, Jeff
Valk, Jens Östlund, Jeremy Friesen, Jonathan Sahar, Johan Bolmsjö,
Jonas Großekathöfer, Jousimies, Juanjo Presa, Julian Hoch, Kai von
Fintel, Kaushal Modi, Kevin Izevbigie, Kolmas, Lukas C. Bossert, M.
Hadi Timachi, Maikol Solis, Mark Olson, Michael Jones, Mirko
Hernandez, Morten Kjeldgaard, Niall Dooley, Nick Bell, Oliver Epper,
Paul van Gelder, Peter Prevos, Peter Smith, Riccardo Giannitrapani,
Rory Molinari, Samuel W. Flint, Sergio Rey, Suhail Singh, Shreyas
Ragavan, Stefan Thesing, Summer Emacs, Sven Seebeck, Taoufik, TJ
Stankus, Vick (VicZz), Viktor Haag, Vineet C. Kulkarni, Wade
Mealing, Wilf, Yi Liu, Ypot, 82Kang, atanasj, azegas, babusri,
bdillahu, coherentstate, doolio, duli, drcxd, elge70, elliottw,
fingerknight, GuutBoy, hpgisler, hyperfocus1337,johkneisl,
jtpavlock, juh, leafarbelm, mentalisttraceur, mjkalyan, oatmealm,
Pratik-Mishra-4979, pRot0ta1p, rbenit68, relict007, sarcom-sar,
sienic, skissue, sundar bp, wuzhihao, yetanotherfossman, zadca123
Purslane, Alfredo Borrás, Ali Bozorgzadeh, Alp Eren Kose, André
Bering, Ashton Wiersdorf, Bhargav Kulkarni, Benjamin Kästner,
Claudio Migliorelli, Claudiu Tănăselia, Colin McLear,
Cosmin-Octavian C, Damien Cassou, Davi Ramos, Elias Storms, Federico
Stilman, Florian, Frédéric Willem Frank Ehmsen, Glenna D., Guo Yong,
Hanspeter Gisler Harold Ollivier, IceAsteroid, Jack Baty, Jay
Rajput, Jean-Charles Bagneris, Jeff Valk, Jens Östlund, Jeremy
Friesen, Jonathan Sahar, Johan Bolmsjö, Jonas Großekathöfer,
Jousimies, Juanjo Presa, Julian Hoch, Kai von Fintel, Kaushal Modi,
Kevin Izevbigie, Kolmas, Lukas C. Bossert, M. Hadi Timachi, Maikol
Solis, Mark Olson, Michael Jones, Mirko Hernandez, Morten
Kjeldgaard, Niall Dooley, Nick Bell, Oliver Epper, Paul van Gelder,
Peter Prevos, Peter Smith, Riccardo Giannitrapani, Rory Molinari,
Samuel W. Flint, Sergio Rey, Suhail Singh, Shreyas Ragavan, Stefan
Thesing, Summer Emacs, Sven Seebeck, Taoufik, TJ Stankus, Vick
(VicZz), Viktor Haag, Vineet C. Kulkarni, Wade Mealing, Wilf, Yi
Liu, Ypot, 82Kang, atanasj, azegas, babusri, bdillahu,
coherentstate, doolio, duli, drcxd, elge70, elliottw, fingerknight,
GuutBoy, hpgisler, hyperfocus1337,johkneisl, jtpavlock, juh,
leafarbelm, mentalisttraceur, mjkalyan, o-rxw, oatmealm,
potchie-maker, Pratik-Mishra-4979, pRot0ta1p, rbenit68, relict007,
sarcom-sar, sienic, skissue, sundar bp, wuzhihao, yetanotherfossman,
zadca123
Special thanks to Peter Povinec who helped refine the file-naming
scheme, which is the cornerstone of this project.

103
denote.el
View file

@ -5,7 +5,7 @@
;; Author: Protesilaos <info@protesilaos.com>
;; Maintainer: Protesilaos <info@protesilaos.com>
;; URL: https://github.com/protesilaos/denote
;; Version: 4.2.0
;; Version: 4.2.3
;; Package-Requires: ((emacs "28.1"))
;; This file is NOT part of GNU Emacs.
@ -485,6 +485,11 @@ and the text of the current heading, like this:
[[denote:20240118T060608::*Heading text][Some test::Heading text]].
If the value is `local', the link consists of the text of the current
heading, like this:
[[*Heading text][Heading text]].
However, if there already exists a CUSTOM_ID property for the current
heading, this is always given priority and is used instead of the
context.
@ -526,9 +531,10 @@ navigates to that heading.
identifier of the file, even if this user option is set to a
non-nil value. ]"
:group 'denote
:package-version '(denote . "4.0.0")
:package-version '(denote . "4.3.0")
:type '(choice (const :tag "No link to heading (default)" nil)
(const :tag "Link to the context" context)
(const :tag "Link to local heading" local)
(const :tag "Link wtih CUSTOM_ID, creating it if needed" id)))
(defcustom denote-templates nil
@ -906,16 +912,16 @@ The note's ID is derived from the date and time of its creation.")
(defconst denote-date-identifier-regexp "\\([0-9]\\{8\\}\\)\\(T[0-9]\\{6\\}\\)"
"Regular expression to match `denote-date-identifier-format'.")
(defconst denote-identifier-regexp "@@\\([^.]*?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
(defconst denote-identifier-regexp "@@\\([^.]+?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
"Regular expression to match the IDENTIFIER field in a file name.")
(defconst denote-signature-regexp "==\\([^.]*?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
(defconst denote-signature-regexp "==\\([^.]+?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
"Regular expression to match the SIGNATURE field in a file name.")
(defconst denote-title-regexp "--\\([^.]*?\\)\\(==.*\\|__.*\\|@@.*\\|\\..*\\)*$"
(defconst denote-title-regexp "--\\([^.]+?\\)\\(==.*\\|__.*\\|@@.*\\|\\..*\\)*$"
"Regular expression to match the TITLE field in a file name.")
(defconst denote-keywords-regexp "__\\([^.]*?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
(defconst denote-keywords-regexp "__\\([^.]+?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
"Regular expression to match the KEYWORDS field in a file name.")
(make-obsolete-variable
@ -1059,6 +1065,36 @@ This is useful as a helper function to construct
(characters (seq-filter #'characterp ascii-range)))
(mapconcat #'string characters)))
(defun denote-slug-remove-accents (str)
"Remove diacterics or accents from STR.
This means that something like ê becomes e while ñ becomes n."
;; Combining Diacritical Marks https://www.unicode.org/charts/PDF/U0300.pdf
(let* ((slug-trim-chars '(768 ; U+0300 COMBINING GRAVE ACCENT
769 ; U+0301 COMBINING ACUTE ACCENT
770 ; U+0302 COMBINING CIRCUMFLEX ACCENT
771 ; U+0303 COMBINING TILDE
772 ; U+0304 COMBINING MACRON
774 ; U+0306 COMBINING BREVE
775 ; U+0307 COMBINING DOT ABOVE
776 ; U+0308 COMBINING DIAERESIS
777 ; U+0309 COMBINING HOOK ABOVE
778 ; U+030A COMBINING RING ABOVE
779 ; U+030B COMBINING DOUBLE ACUTE ACCENT
780 ; U+030C COMBINING CARON
795 ; U+031B COMBINING HORN
803 ; U+0323 COMBINING DOT BELOW
804 ; U+0324 COMBINING DIAERESIS BELOW
805 ; U+0325 COMBINING RING BELOW
807 ; U+0327 COMBINING CEDILLA
813 ; U+032D COMBINING CIRCUMFLEX ACCENT BELOW
814 ; U+032E COMBINING BREVE BELOW
816 ; U+0330 COMBINING TILDE BELOW
817)) ; U+0331 COMBINING MACRON BELOW
(fn (lambda (char) (memq char slug-trim-chars)))
(chars (seq-remove fn (string-glyph-decompose str)))
(string (apply #'string chars)))
(string-glyph-compose string)))
(define-obsolete-function-alias
'denote--slug-hyphenate
'denote-slug-hyphenate
@ -1492,9 +1528,9 @@ there.")
(defun denote-file-prompt--format-identifier (file)
"Return identifier of FILE for `denote-file-prompt-affixate'."
(let* ((identifier (denote-retrieve-filename-identifier file))
(date-or-id (or (ignore-errors (denote-id-to-date identifier)) identifier))
(propertized (propertize date-or-id 'face 'completions-annotations)))
(when-let* ((identifier (denote-retrieve-filename-identifier file))
(date-or-id (or (ignore-errors (denote-id-to-date identifier)) identifier))
(propertized (propertize date-or-id 'face 'completions-annotations)))
(format "%s " propertized)))
(defun denote-file-prompt--format-keywords-and-signature (file)
@ -2195,8 +2231,8 @@ Denote file-naming scheme."
#+signature: %s
\n"
"Org front matter.
It is passed to `format' with arguments TITLE, DATE, KEYWORDS,
ID. Advanced users are advised to consult Info node `(denote)
It is passed to `format' with arguments TITLE, DATE, KEYWORDS, ID,
SIGNATURE. Advanced users are advised to consult Info node `(denote)
Change the front matter format'.")
(defvar denote-yaml-front-matter
@ -2208,8 +2244,8 @@ identifier: %s
signature: %s
---\n\n"
"YAML (Markdown) front matter.
It is passed to `format' with arguments TITLE, DATE, KEYWORDS,
ID. Advanced users are advised to consult Info node `(denote)
It is passed to `format' with arguments TITLE, DATE, KEYWORDS, ID,
SIGNATURE. Advanced users are advised to consult Info node `(denote)
Change the front matter format'.")
(defvar denote-toml-front-matter
@ -2221,8 +2257,8 @@ identifier = %s
signature = %s
+++\n\n"
"TOML (Markdown) front matter.
It is passed to `format' with arguments TITLE, DATE, KEYWORDS,
ID. Advanced users are advised to consult Info node `(denote)
It is passed to `format' with arguments TITLE, DATE, KEYWORDS, ID,
SIGNATURE. Advanced users are advised to consult Info node `(denote)
Change the front matter format'.")
(defvar denote-text-front-matter
@ -2233,8 +2269,8 @@ identifier: %s
signature: %s
---------------------------\n\n"
"Plain text front matter.
It is passed to `format' with arguments TITLE, DATE, KEYWORDS,
ID. Advanced users are advised to consult Info node `(denote)
It is passed to `format' with arguments TITLE, DATE, KEYWORDS, ID,
SIGNATURE. Advanced users are advised to consult Info node `(denote)
Change the front matter format'.")
(defun denote-format-string-for-md-front-matter (s)
@ -3159,6 +3195,12 @@ If DATE is nil or an empty string, return nil."
((and (or (numberp date) (listp date))
(decode-time date))
date)
(; Unix timestamps
(when-let* ((stringp date)
(_ (string-match "[0-9]\\{10\\}" date))
(match (match-string 0 date))
(seconds (string-to-number match)))
(seconds-to-time seconds)))
(t ; non-empty strings (e.g. "2024-01-01", "2024-01-01 12:00", etc.)
(date-to-time (denote--date-add-current-time date)))))
@ -3646,6 +3688,8 @@ here for clarity."
(defun denote-date-prompt (&optional initial-date prompt-text)
"Prompt for date, expecting YYYY-MM-DD or that plus HH:MM.
Unix timestamp format is also supported.
Use Org's more advanced date selection utility if the user option
`denote-date-prompt-use-org-read-date' is non-nil.
@ -3961,7 +4005,8 @@ Return nil if FILE is not recognized."
(found (seq-find
(lambda (type)
(let ((properties (cdr type)))
(if-let* ((file-type-fn (plist-get properties :get-file-type-function)))
(if-let* ((file-type-fn (plist-get properties :get-file-type-function))
(_ (file-exists-p file)))
(funcall file-type-fn file)
(ignore-errors
(denote--regexp-in-file-p (plist-get properties :title-key-regexp) file)))))
@ -5514,12 +5559,12 @@ the active region specially, is up to it."
(defun denote-link--collect-identifiers (regexp)
"Return collection of identifiers in buffer matching REGEXP."
(let (matches)
(let ((matches nil))
(save-excursion
(goto-char (point-min))
(while (re-search-forward regexp nil t)
(push (match-string-no-properties 1) matches)))
matches))
(seq-uniq matches)))
(make-obsolete 'denote-link--expand-identifiers nil "4.1.0")
@ -5902,6 +5947,7 @@ alist, such as `denote-backlinks-display-buffer-action'."
(dirs (denote-directories)))
(unless xref-alist
(error "No results to display"))
(setq denote-query--last-files (delete-dups (mapcar #'car xref-alist)))
;; Update group of each item in xref-alist
(dolist (x xref-alist)
(let* ((file-xref (car x)))
@ -5930,6 +5976,7 @@ alist, such as `denote-backlinks-display-buffer-action'."
DISPLAY-BUFFER-ACTION is a `display-buffer' action and concomitant
alist, such as `denote-backlinks-display-buffer-action'."
(setq denote-query--last-query identifier)
(if-let* ((xref-alist (denote-retrieve-xref-alist-for-backlinks identifier)))
(denote--display-buffer-from-xref-alist xref-alist buffer-name display-buffer-action)
(error "No matches for identifier `%s'" identifier)))
@ -6006,7 +6053,7 @@ generally, any command that relies on the `denote-make-links-buffer'."
(list (denote-query-prompt :focus)))
denote-query-mode)
(denote--user-error-if-not-major-mode 'denote-query-mode)
(denote-make-links-buffer query denote-query--last-files nil '(display-buffer-same-window))
(denote-make-links-buffer query denote-query--last-files (buffer-name) '(display-buffer-same-window))
(message "Searching `%s' in files: `%S'" query denote-query--last-files))
(defun denote-query--filter-files (regexp include-p)
@ -6994,9 +7041,13 @@ create a new one."
"Get current Org heading text."
(org-get-heading :no-tags :no-todo :no-priority :no-comment))
(defun denote-link-format-heading-description (file-text heading-text)
"Return description for FILE-TEXT with HEADING-TEXT at the end."
(format "%s::%s" file-text heading-text))
(defun denote-link--ol-format-heading-description (file-text heading-text)
"Return heading description.
Return description for FILE-TEXT with HEADING-TEXT at the end or
only HEADING-TEXT if `denote-org-store-link-to-heading' is set to `local' links."
(if (eq denote-org-store-link-to-heading 'local)
(format "%s" heading-text)
(format "%s::%s" file-text heading-text)))
;;;###autoload
(defun denote-link-ol-store (&optional _interactive?)
@ -7017,7 +7068,7 @@ Also see the user option `denote-org-store-link-to-heading'."
(org-link-store-props
:type "denote"
:description (if (and heading-links heading)
(denote-link-format-heading-description
(denote-link--ol-format-heading-description
description
heading)
description)
@ -7026,6 +7077,8 @@ Also see the user option `denote-org-store-link-to-heading'."
(format "denote:%s::#%s" file-id id)))
((and heading-links (eq denote-org-store-link-to-heading 'context) heading)
(format "denote:%s::*%s" file-id heading))
((and heading-links (eq denote-org-store-link-to-heading 'local) heading)
(format "*%s" heading))
((and heading-links heading)
(format "denote:%s::#%s" file-id (denote-link-ol-get-id)))
(t

View file

@ -146,6 +146,11 @@ The function also account for the value of the user option
`denote-allow-multi-word-keywords'."
(should (equal (denote-sluggify-keywords '("one !@# --- one" " two" "__ three __")) '("oneone" "two" "three"))))
(ert-deftest dt-denote-slug-remove-accents ()
"Test that `denote-slug-remove-accents' removed diacretics."
(should (string= (denote-slug-remove-accents "ê") "e"))
(should (string= (denote-slug-remove-accents "ñ") "n")))
(ert-deftest dt-denote--file-empty-p ()
"Test that `denote--file-empty-p' returns non-nil on empty file."
(let ((file (make-temp-file "denote-test")))