Commit Diff


commit - 2b7a791c1f2ee8221fd8c891bb137bdb0a7ae588
commit + 984e27bda33195f6f907a564679017b5a3ec9388
blob - /dev/null
blob + 1f7c4b790168032cdf15e155f3d3f3419b908ce0 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/.dir-locals.el
@@ -0,0 +1,4 @@
+;;; Directory Local Variables
+;;; For more information see (info "(emacs) Directory Variables")
+
+((emacs-lisp-mode . ((indent-tabs-mode . nil))))
blob - /dev/null
blob + 4f545859df79e2432e5f20cc98e1f5a13b2791f2 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/CHANGELOG.org
@@ -0,0 +1,6099 @@
+#+title: Change log of Denote
+#+author: Protesilaos Stavrou
+#+email: info@protesilaos.com
+#+language: en
+#+options: ':t toc:nil author:t email:t num:t
+#+startup: content
+
+This document contains the release notes for each tagged commit on the
+project's main git repository: <https://github.com/protesilaos/denote>.
+
+The newest release is at the top.  For further details, please consult
+the manual: <https://protesilaos.com/emacs/denote>.
+
+#+toc: headlines 1 insert TOC here, with one headline level
+
+* Version 4.0.0 on 2025-04-15
+:PROPERTIES:
+:CUSTOM_ID: h:8a134846-72cc-4fbf-830d-6ca9fd0f9ec8
+:END:
+
+This is a massive release. There is one breaking change, which should
+be easy to adapt to: this pertains to the reorganisation of the
+project to separate the "core" of Denote from its "extensions". The
+core is the ~denote~ package. Each extension now has its own package
+(details below).
+
+Other than that, this version includes lots of new features for
+searching and linking as well as quality-of-life refinements. We have
+generalised the infrastructure for performing queries in the
+~denote-directory~ and made the buffers with the search results more
+useful.
+
+Take your time to read through this publication. I am writing it for
+you. Also remember that the most up-to-date resource for anything
+related to Denote is its manual. You are always welcome to contact me:
+<https://protesilaos.com/contact>. Or join the development on the Git
+repository.
+
+As usual, special thanks to Jean-Philippe Gagné Guay for making high
+quality contributions to Denote since the beginning of the project ~3
+years ago. Those will not always be headline features, but are
+important improvements to the underlying code base.
+
+I mention contributions from Jean-Philippe and others in its context.
+Though I do not cover implementation details, otherwise this document
+will be the size of a book. This does not mean that they are no
+important though. Please consult the Git commit log for all the
+technicalities.
+
+** All the "extras" are in separate packages, including the Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:26ed2af1-60c8-4217-93b3-bbe344e4eb7b
+:END:
+
+In previous versions of Denote, we included some optional extensions
+as part of the ~denote~ package. These included the files
+=denote-org-extras.el= (Org dynamic blocks, among others),
+=denote-journal-extras.el= (streamlined for journaling),
+=denote-silo-extras.el= (working with multiple Denote silos).
+
+The files =denote-md-extras.el= (Markdown extras) and
+=denote-sequence.el= (sequence notes, including Luhmann-style
+alphanumeric sequences) were also part of the project during the last
+development cycle, though they never made it into a tagged release.
+
+All these are now available as standalone packages on the official GNU
+ELPA archive:
+
+- ~denote-org~ :: In the Emacs configuration file, replace all
+  instances of =denote-org-extras= with =denote-org=.
+
+- ~denote-journal~ :: Replace =denote-journal-extras= with =denote-journal=.
+
+- ~denote-silo~ :: Replace =denote-silo-extras= with =denote-silo=.
+
+- ~denote-markdown~  :: Replace =denote-md-extras= with =denote-markdown=.
+
+- ~denote-sequence~ :: No changes to any of the defined symbols.
+  Simply get the new package.
+
+I will document each of these packages further below. The plan, going
+forward, is to maintain all the packages and coordinate their new
+versions.
+
+** More things in "core"
+:PROPERTIES:
+:CUSTOM_ID: h:3820e9cf-f034-4c3c-a4ed-1e7d11f1cd23
+:END:
+
+While the extras are moved out to their own code repositories, all
+other features are merged into =denote.el=. Those include everything
+that was in =denote-sort.el= and =denote-rename-buffer.el=.
+
+- The "sort" mechanism is mostly for package developers. We use it
+  extensively in our Org dynamic blocks, which are now part of the
+  ~denote-org~ package.
+
+- The ~denote-dired~ command (alias ~denote-sort-dired~) is the only
+  user-facing "sort" command we have always provided. It produces a
+  fully fledged Dired buffer showing the results of the given search
+  for file names. The matching files are sorted according to the
+  user's expressed preference. The details are described in the
+  manual.
+
+- The ~denote-rename-buffer-mode~ and all of its user options are
+  unchanged. This mode automatically renames the buffer of a given
+  Denote file so that it is easier to read it. Again, the manual
+  covers the technicalities.
+
+Users do not need to make changes, unless they are explicitly loading
+=denote-sort-dired= and =denote-rename-buffer=. In that case, they may
+just remove those calls: only ~denote~ needs to be loaded.
+
+** The ~denote-query-mode~
+:PROPERTIES:
+:CUSTOM_ID: h:36f305e2-310d-4327-941a-ca0570b473d2
+:END:
+
+Many of the features I will describe below produce search results via
+the built-in Xref mechanism. Xref performs a search with a Grep or
+Grep-like program, subject to the user option ~xref-search-program~.
+The buffer those search results are displayed in runs the
+~denote-query-mode~. It supersedes ~denote-backlinks-mode~.
+
+The ~denote-query-mode~ supports the following:
+
+- Results are shown in the context, with the exact match in highlight.
+- Matches are grouped by file. Each file is a "heading".
+- Headings can be folded with =TAB=, just how it is done in Org buffers.
+- The results can be used for further queries. Type =C-h m=
+  (~describe-mode~) to learn about all the relevant commands.
+
+We have had support for Xref since the original version of Denote. It
+now is more generalised to cover backlinks, query links, and
+~denote-grep~ (more below).
+
+** Use query links for file contents or file names
+:PROPERTIES:
+:CUSTOM_ID: h:c217a37a-db73-46bd-ab5f-3f9c54f9d53b
+:END:
+
+Denote has always provided the option to link directly to a file with
+a given name by referencing its identifier. This can be done with the
+command ~denote-link~, among a few others like it (always consult the
+manual of Denote).
+
+In addition to these "direct links", we also support "query links".
+Those do not point to a file but instead trigger a search. The results
+are placed in a buffer that uses the appropriate major mode.
+
+There are two types of query links:
+
+- Query file contents :: Use the command ~denote-query-contents-link~
+  to insert a query link at point for "file contents". It perform a
+  search inside files in the ~denote-directory~ and put the results in
+  a ~denote-query-mode~ buffer.
+
+- Query file names :: Use the ~denote-query-filenames-link~ to insert
+  a query link for "file names". It performs the query against file
+  names (not contents!) and puts the results in a ~dired~ buffer.
+
+The display of the buffer with the query link results is controlled by
+the user option ~denote-query-links-display-buffer-action~.
+
+Query links are styled a little bit differently than direct links.
+Compare the ~denote-faces-link~ with ~denote-faces-query-link~. Both
+should look okay with most themes.
+
+Denote query links are supported as part of the =denote:= hyperlink
+type. They are available in all file types we define (per the user
+option ~denote-file-type~) and should, in principle, work in any
+custom file type (advanced users can check the variable ~denote-file-types~).
+
+** Backlinks now always show their context
+:PROPERTIES:
+:CUSTOM_ID: h:8ebc6ae8-1087-46fa-a0ec-464749f0ac4d
+:END:
+
+In the past, the command ~denote-backlinks~ would produce a bespoke
+buffer showing a list of file names that included links to the current
+file (any file with the Denote file-naming scheme can have backlinks,
+by the way, including PDFs, videos, etc.). This buffer did not provide
+any additional functionality. We used to support the option to show
+results in their context via ~denote-backlinks-show-context~. Those
+would be rendered in a standard Xref buffer.
+
+The contextual results are now the default and sole option. This is
+because we have expanded the functionality of those buffers to use the
+~denote-query-mode~, as explained above. Plus, it makes our code base
+simpler.
+
+Users will notice how backlikns look just like a query link for file
+contents. This is because backlinks are the original query links since
+day one of Denote.
+
+** Direct links to a file with matching contents
+:PROPERTIES:
+:CUSTOM_ID: h:a1a7b766-328d-4883-93b2-c68b49bd1aa3
+:END:
+
+The command ~denote-link-to-file-with-contents~ allows users to
+produce a direct link to a file whose contents (not file name!)
+includes the given query.
+
+Similarly, the command ~denote-link-to-all-files-with-contents~
+generates a typographic list (bullet list) to all files whose contents
+match the given query.
+
+The manual covers all linking commands in depth.
+
+** The essence of ~denote-search~ is part of ~denote~
+:PROPERTIES:
+:CUSTOM_ID: h:5d2ac378-304c-4ea8-bbfb-b3f7b649b27d
+:END:
+
+The ~denote-search~ package by Lucas Quintana uses the infrastructure
+of Denote to perform searches in file contents. We now provide its
+feature set as part of core ~denote~.
+
+We decided to do this since query links already introduced all of the
+requisite generalisations to ~denote-query-mode~.
+
+Users can rely on the commands ~denote-grep~, ~denote-grep-marked-dired-files~,
+and ~denote-grep-files-referenced-in-region~.
+
+The placement of these buffers is subject to the user option
+~denote-grep-display-buffer-action~.
+
+This functionality was introduced in two pull requests by Lucas
+Quintana, 571 and 573, with further changes by me:
+
+- <https://github.com/protesilaos/denote/pull/571>.
+- <https://github.com/protesilaos/denote/pull/573>.
+
+Lucas has assigned copyright to the Free Software Foundation.
+
+I think this was a much-needed addition to the core of Denote. It
+complements ~denote-dired~ and query links.
+
+** Formatting of links with ~denote-link-description-format~
+:PROPERTIES:
+:CUSTOM_ID: h:635b7f04-891a-4a8b-b420-4e0d9dadc232
+:END:
+
+The old user option ~denote-link-description-function~ is deprecated
+and superseded by the new ~denote-link-description-format~. The new
+user option still accepts a custom function as its value, so the old
+behaviour should be retained.
+
+What the new ~denote-link-description-format~ supports is an easier
+way to customise the description of a link by using format specifiers
+for common options. For example, users who only want to see the title
+of the linked file can do this:
+
+#+begin_src emacs-lisp
+(setq denote-link-description-format "%t")
+#+end_src
+
+The documentation of this user option covers all the format specifiers
+and further details.
+
+** Miscellaneous changes for all users
+:PROPERTIES:
+:CUSTOM_ID: h:76a56ab5-c44b-4c67-8048-25dd0dd88dcf
+:END:
+
+- The command ~denote-add-front-matter~ is superseded by
+  ~denote-rename-file~ and related. Those renaming commands will add
+  missing front matter or rewrite the modified lines of existing front
+  matter. This is due to refinements made by Jean-Philippe Gagné Guay
+  to the file renaming mechanism. We discussed this deprecation in
+  issue 498: <https://github.com/protesilaos/denote/issues/498>. Also
+  thanks to Samuel Flint for reporting an earlier problem with file
+  name signatures: <https://github.com/protesilaos/denote/issues/492>.
+
+- The user option ~denote-open-link-function~ specifies the function
+  used by Denote to open the file of a direct link.
+
+- The user option ~denote-org-store-link-to-heading~ can now be set to
+  form generic context links without a =PROPERTIES= drawer and
+  corresponding =CUSTOM_ID=. Set the value of this variable to
+  ='context=. Read its documentation for further details.
+
+- Also about ~denote-org-store-link-to-heading~, we have changed its
+  default value to ~nil~, which is what we were doing for most of
+  Denote's history. This means that, by default, ~org-store-link~ and
+  anything building on top of it will create a link only to the
+  current Denote file, like =denote:IDENTIFIER=, but not to the
+  current heading within that file. To create links to the
+  file+heading, set the value of this variable to ='id=.
+
+- The command ~denote-dired-link-marked-notes~ is an alias for
+  ~denote-link-dired-marked-notes~.
+
+- The user option ~denote-sort-dired-extra-prompts~ control what
+  ~denote-dired~ (alias ~denote-sort-dired~) prompts for. It accepts
+  either a nil value or a list of symbols among ~sort-by-component~,
+  ~reverse-sort~, and ~exclude-regexp~. The order those symbols appear
+  in the list is significant, with the leftmost coming first.
+
+- There is a new ~denote-sort-identifier-comparison-function~ variable
+  which determines how identifier-based sorting should be done by
+  default. It complements the existing ~denote-sort-title-comparison-function~,
+  ~denote-sort-keywords-comparison-function~, ~denote-sort-signature-comparison-function~.
+  Thanks to Maikol Solís for the contribution in pull request 517:
+  <https://github.com/protesilaos/denote/pull/517>. The change is
+  small, meaning that Maikol does not need to assign copyright to the
+  Free Software Foundation (though I believe the paperwork is done, anyway).
+
+- Lots of refinements to the doc strings of individual variables
+  and/or functions as well as the manual.
+
+- Lots of other contributions to discussions and questions on the Git
+  repository. Granted, these are not "changes" per se but are part of
+  the development effort nonetheless.
+
+- Made ~denote-get-path-by-id~ use ~denote-get-file-extension-sans-encryption~
+  instead of ~denote-get-file-extension~. This fixes a bug where the
+  extension is duplicated if it has an encryption component. Thanks to
+  eum3l for the patch in pull request 562: <https://github.com/protesilaos/denote/pull/562>.
+  The change is small, meaning that the author does not need to assign
+  copyright to the Free Software Foundation.
+
+- Same as above for ~denote--rename-file~, which was done in pull
+  request 557: <https://github.com/protesilaos/denote/pull/557>.
+
+** For developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:7eaf43a6-7d62-440e-bf7c-8d9536c7d36e
+:END:
+
+The following have been added or modified.
+
++ NEW Function ~denote-file-has-denoted-filename-p~ :: Return non-nil
+  if =FILE= respects the file-naming scheme of Denote. This tests the
+  rules of Denote's file-naming scheme. Sluggification is ignored. It
+  is done by removing all file name components and validating what
+  remains. Thanks to Jean-Philippe Gagné Guay for the pull request
+  515: <https://github.com/protesilaos/denote/pull/515>.
+
++ NEW Functions ~denote-infer-keywords-from-files~ :: Return list of
+  keywords in ~denote-directory-files~. With optional
+  =FILES-MATCHING-REGEXP=, only extract keywords from the matching
+  files. Otherwise, do it for all files. Keep any duplicates. Users
+  who do not want duplicates should refer to the functions
+  ~denote-keywords~.
+
++ MODIFIED Function ~denote-keywords~ :: Returns an appropriate list
+  of keyword candidates, while accounting for the value of the user
+  option ~denote-infer-keywords~. It now also accepts the optional
+  =FILES-MATCHING-REGEXP= parameter.
+
++ MODIFIED Function ~denote-directory-files~ :: Returns a list of
+  absolute file paths in variable ~denote-directory~. It now accepts
+  the optional =EXCLUDE-REGEXP= parameter.
+
++ MODIFIED Function ~denote-format-file-name~ :: Formats a file name.
+  The way it treats its =ID= parameter has changed. Please read its
+  doc string. Thanks to Jean-Philippe Gagné Guay for the pull request
+  496: <https://github.com/protesilaos/denote/pull/496>.
+
++ ALIAS Function ~denote-retrieve-filename-keywords-as-list~ :: This
+  is a name that is easier to discover than ~denote-extract-keywords-from-path~,
+  because of the many other functions with the =denote-retrieve-*= prefix.
+
++ MODIFIED Function ~denote-retrieve-filename-identifier~ :: Extracts
+  the identifier from =FILE= name, if present, else returns nil. To
+  create a new one from a date, refer to the ~denote-get-identifier~
+  function. Thanks to Jean-Philippe Gagné Guay for the pull request
+  476: <https://github.com/protesilaos/denote/pull/476>.
+
++ MODIFIED Function ~denote-get-identifier~ :: Converts =DATE= into a
+  Denote identifier using ~denote-id-format~. If =DATE= is nil, it
+  returns an empty string as the identifier. Also by Jean-Philippe in
+  pull request 476 mentioned right above.
+
++ MODIFIED Function ~denote-date-prompt~ :: Prompts for a date,
+  expecting =YYYY-MM-DD= or that plus =HH:MM= (or even =HH:MM:SS=).
+  Can also use Org's more advanced date selection utility if the user
+  option ~denote-date-prompt-use-org-read-date~ is non-nil. It now has
+  the optional parameters =INITIAL-DATE= and =PROMPT-TEXT=. Thanks to
+  Jean-Philippe Gagné Guay for the pull request 576:
+  <https://github.com/protesilaos/denote/pull/576>.
+
+- NEW Function ~denote-retrieve-groups-xref-query~ :: Accesses the
+  location of xrefs for =QUERY= and group them per file. Limit the
+  search to text files.
+
+- NEW Function ~denote-retrieve-files-xref-query~ :: Returns sorted,
+  deduplicated file names with matches for =QUERY= in their contents.
+  Limits the search to text files.
+
+- NEW Function ~denote-retrieve-xref-alist~ :: Returns xref alist of
+  files with the location of matches for =QUERY=. With optional
+  =FILES-MATCHING-REGEXP=, it limits the list of files accordingly
+  (per ~denote-directory-files~). At all times, it limits the search
+  to text files.
+
++ NEW Function ~denote-prepend-front-matter~ :: Prepend front matter
+  to =FILE=. The =TITLE=, =KEYWORDS=, =DATE=, =ID=, =SIGNATURE=, and
+  =FILE-TYPE= are passed from the renaming command and are used to
+  construct a new front matter block if appropriate.
+
++ MODIFIED Function ~denote-rewrite-front-matter~ :: Rewrites front
+  matter of note after ~denote-rename-file~ (or related). The =FILE=,
+  =TITLE=, =KEYWORDS=, =SIGNATURE=, =DATE=, =IDENTIFIER=, and
+  =FILE-TYPE= arguments are given by the renaming command and are used
+  to construct new front matter values if appropriate. If
+  ~denote-rename-confirmations~ contains ~rewrite-front-matter~,
+  prompt to confirm the rewriting of the front matter. Otherwise
+  produce a ~y-or-n-p~ prompt to that effect. Thanks to
+  Jean-Philippe Gagné Guay for the pull request 558:
+  <https://github.com/protesilaos/denote/pull/558>.
+
+** Denote "extensions" that are not in the ~denote~ package anymore
+:PROPERTIES:
+:CUSTOM_ID: h:40e030cd-f462-44ce-add9-ab1525359ae6
+:END:
+
+*** ~denote-journal~ integrates nicely with =M-x calendar=
+:PROPERTIES:
+:CUSTOM_ID: h:f8ab710d-852f-4d8b-b0f8-9a24c5c83808
+:END:
+
+The ~calendar~ can now highlight days that have journal entry. It may
+also be used as a date picker to view or write a journal entry for
+that day.
+
+- Thanks to Alan Schmitt for reporting an issue with the calendar
+  integration during development:
+  <https://github.com/protesilaos/denote-journal/issues/8>.
+
+- Thanks to Vineet C. Kulkarni for tweaking the identification of the
+  journal keyword to be more robust:
+  <https://github.com/protesilaos/denote-journal/pull/4>.
+
+- Thanks to Honza Pokorny for fixing two small issues with the path
+  expansion:
+  
+  - <https://github.com/protesilaos/denote-journal/pull/5>
+  - <https://github.com/protesilaos/denote-journal/pull/7>
+
+Other than that, the package is providing the same functionality as
+the discontinued =denote-journal-extras.el=.
+
+- Manual: <https://protesilaos.com/emacs/denote-journal>.
+- GitHub: <https://github.com/protesilaos/denote-journal>.
+
+*** ~denote-org~ is almost the same as the discontinued =denote-org-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:db491fe0-0c96-4c2e-9320-dc2697106e12
+:END:
+
+The only addition to dynamic blocks the optional =:not-regexp= parameter.
+This is a regular expression that can further filter the results of a
+search, such that the matching items are removed from the output.
+
+The official manual of ~denote-org~ covers the technicalities.
+
+- Manual: <https://protesilaos.com/emacs/denote-org>.
+- GitHub: <https://github.com/protesilaos/denote-org>.
+
+Also thanks to Elias Storms for fixing a small issue with the "missing
+links" Org dynamic block, in pull request 486: <https://github.com/protesilaos/denote/pull/486>
+
+*** ~denote-silo~ is the same as the discontinued =denote-silo-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:ed7c77f5-9b44-4e76-9ada-80ff0ed6d5f6
+:END:
+
+I have only made small tweaks to it, but nothing that changes the user
+experience.
+
++ Manual: <https://protesilaos.com/emacs/denote-silo>
++ GitHub: <https://github.com/protesilaos/denote-silo>
+
+*** ~denote-markdown~ for some Markdown-specific extras
+:PROPERTIES:
+:CUSTOM_ID: h:e01d236c-fb50-488f-9fb2-15e866fa122a
+:END:
+
+This package provides some convenience functions to better integrate
+Markdown with Denote. This is mostly about converting links from one
+type to another so that they can work in different applications
+(because Markdown does not have a standardised way to define custom
+link types). It also defines an "Obsidian" file type which does not
+have any front matter but only uses a level 1 heading for the title of
+the note.
+
+The code of ~denote-markdown~ used to be bundled up with the ~denote~
+package before version =4.0.0= of the latter and was available in the
+file =denote-md-extras.el=. Users of the old code will need to adapt
+their setup to use the ~denote-markdown~ package. This can be done by
+replacing all instances of =denote-md-extras= with =denote-markdown=
+across their configuration.
+
++ Manual: <https://protesilaos.com/emacs/denote-markdown>
++ GitHub: <https://github.com/protesilaos/denote-markdown>
+
+*** Write sequence notes (or "folgezettel") with ~denote-sequence~
+:PROPERTIES:
+:CUSTOM_ID: h:6181df9e-790f-4fcf-8093-cefbba324cb5
+:END:
+
+Users who want their notes to have an inherent structure can use
+~denote-sequence~. The idea is to have thoughts that naturally form
+sequences and are named accordingly. The sequence scheme is either
+numeric or alphanumeric. The manual of the package explains all the
+details.
+
++ Manual: <https://protesilaos.com/emacs/denote-sequence>
++ GitHub: <https://github.com/protesilaos/denote-sequence>
+
+I had a lot of fun developing this comprehensive package during the
+winter holidays.
+
+Thanks to Claudio Migliorelli, Kierin Bell, Mirko Hernandez for
+helping me fix some issues during development:
+
+- <https://github.com/protesilaos/denote/pull/518>.
+- <https://github.com/protesilaos/denote/pull/528>.
+- <https://github.com/protesilaos/denote/pull/540>.
+- <https://github.com/protesilaos/denote/pull/541>.
+- <https://github.com/protesilaos/denote-sequence/issues/2>.
+
+** The ~consult-denote~ also gets a small update
+:PROPERTIES:
+:CUSTOM_ID: h:90a9287d-a7dd-4d65-9214-4be6ebdf5943
+:END:
+
+This has always been a standalone package. I made the function
+~consult-denote-file-prompt~ read the special-purpose variable
+~denote-file-prompt-use-files-matching-regexp~. This is related to
+commit =e0f1d47= in denote.git, about issue 536 as reported by Alan
+Schmitt: <https://github.com/protesilaos/denote/issues/536>. The
+variable =denote-file-prompt-use-files-matching-regexp= is meant to be
+~let~ bound and is for advanced users or developers.
+
+** Feature freeze at least until the end of April 2025
+:PROPERTIES:
+:CUSTOM_ID: h:8624e698-90cd-429e-a072-b0fa2df76662
+:END:
+
+I will not develop new features or accept pull request for a couple of
+weeks. The idea is to focus on fixing any bug reports. We can then
+publish point releases quickly.
+
+New features can be included after we are confident that the packages
+we have are okay.
+
+** Git commits
+:PROPERTIES:
+:CUSTOM_ID: h:5191b423-6dc5-4ca7-9bcc-39797be5707c
+:END:
+
+This is just an overview of the Git commits, though remember that
+there is more that goes into a project, such as the reporting of
+inconsistencies, discussion of new ideas, et cetera. Thanks to
+everybody involved! Plus, some commits are large while others are
+tiny.
+
+#+begin_src
+~/Git/Projects/denote $ git shortlog 3.1.0..4.0.0  --summary --numbered
+   470	Protesilaos Stavrou
+    90	Jean-Philippe Gagné Guay
+     6	Kierin Bell
+     4	Alan Schmitt
+     3	eum3l
+     2	Claudio Migliorelli
+     2	Lucas Quintana
+     2	grtcdr
+     1	Elias Storms
+     1	Laurent Gatto
+     1	Maikol Solís
+     1	Octavian
+     1	TomoeMami
+#+end_src
+
+The following are not accurate because they only reflect the changes
+after the reorganisation I made. But we have to start from somewhere.
+
+#+begin_src
+~/Git/Projects/denote-journal $ git shortlog  --summary --numbered
+    54	Protesilaos Stavrou
+     2	Honza Pokorny
+     1	Vineet C. Kulkarni
+#+end_src
+
+#+begin_src
+~/Git/Projects/denote-sequence $ git shortlog  --summary --numbered
+    22	Protesilaos Stavrou
+#+end_src
+
+#+begin_src
+~/Git/Projects/denote-silo $ git shortlog  --summary --numbered
+    17	Protesilaos Stavrou
+#+end_src
+
+#+begin_src
+~/Git/Projects/denote-org $ git shortlog  --summary --numbered
+    15	Protesilaos Stavrou
+#+end_src
+
+#+begin_src 
+~/Git/Projects/denote-markdown $ git shortlog  --summary --numbered
+    11	Protesilaos Stavrou
+#+end_src
+
+* Version 3.1.0 on 2024-09-04
+:PROPERTIES:
+:CUSTOM_ID: h:f089ab11-4ad7-4fd9-9bf3-2deb2e070297
+:END:
+
+Denote is stable and reliable though we keep adding minor refinements
+to it. Remember that many---if not all---of these are intended for
+experienced users who have developed their own workflow and want to
+adapt Denote to its particularities. We may call them "power users".
+
+New users do not need to know about every single feature. A basic
+configuration is enough and is why the original video I did about
+Denote (from even before I published version =0.1.0=) is still relevant.
+For example:
+
+#+begin_src emacs-lisp
+;; Start with something like this.
+(use-package denote
+  :ensure t
+  :bind
+  (("C-c n n" . denote)
+   ("C-c n r" . denote-rename-file)
+   ("C-c n i" . denote-link) ; "insert" mnemonic
+   ("C-c n b" . denote-backlinks))
+  :config
+  (setq denote-directory (expand-file-name "~/Documents/notes/")))
+#+end_src
+
+And here is the same idea with a little bit more convenience:
+
+#+begin_src emacs-lisp
+;; Another basic setup with a little more to it.
+(use-package denote
+  :ensure t
+  :hook (dired-mode . denote-dired-mode)
+  :bind
+  (("C-c n n" . denote)
+   ("C-c n r" . denote-rename-file)
+   ("C-c n l" . denote-link)
+   ("C-c n b" . denote-backlinks))
+  :config
+  (setq denote-directory (expand-file-name "~/Documents/notes/"))
+
+  ;; Automatically rename Denote buffers when opening them so that
+  ;; instead of their long file name they have a literal "[D]"
+  ;; followed by the file's title.  Read the doc string of
+  ;; `denote-rename-buffer-format' for how to modify this.
+  (denote-rename-buffer-mode 1))
+#+end_src
+
+** The ~denote-sort-dired~ command is more configurable
+:PROPERTIES:
+:CUSTOM_ID: h:717765ae-f76f-4b41-96c0-895fe131a83d
+:END:
+
+The ~denote-sort-dired~ command asks for a literal string or regular
+expression and then produces a fully fledged Dired listing of matching
+files in the ~denote-directory~. Combined with the efficient Denote
+file-naming scheme, this is a killer feature to collect your relevant
+files in a consolidated view and have the full power of Dired available.
+
+By default ~denote-sort-dired~ prompts for the file name component to
+sort by and then asks whether to reverse the sorting or not. Users who
+want a more streamlined experience can configure the user option
+~denote-sort-dired-extra-prompts~.
+
+It is possible to skip the prompts altogether and use the default
+values for (i) which component to sort by and (ii) whether to reverse
+the sort. To this end, users can have something like this in their
+configuration:
+
+#+begin_src emacs-lisp
+;; Do not issue any extra prompts.  Always sort by the `title' file
+;; name component and never do a reverse sort.
+(setq denote-sort-dired-extra-prompts nil)
+(setq denote-sort-dired-default-sort-component 'title)
+(setq denote-sort-dired-default-reverse-sort nil)
+#+end_src
+
+For me, Dired is one of the best things about Emacs and I like how it
+combines so nicely with Denote file names (this is the cornerstone of
+Denote, after all).
+
+** The ~denote-sort-dired~ sorting functions are customisable
+:PROPERTIES:
+:CUSTOM_ID: h:7c4824c0-7f9b-46f5-98ea-4ebbab092193
+:END:
+
+Power users may want to control how the sorting works and what it is
+matching on a per file-name-component basis. The user options are
+these:
+
+- ~denote-sort-title-comparison-function~.
+- ~denote-sort-keywords-comparison-function~.
+- ~denote-sort-signature-comparison-function~.
+
+One use-case is to match specific patterns inside of file names, such
+as Luhmann-style signatures. I wrote about this in the manual as well
+as on my blog (with screenshots):
+<https://protesilaos.com/codelog/2024-08-01-emacs-denote-luhmann-signature-sort/>.
+
+Thanks to Riccardo Giannitrapani for discussing this with me and
+helping me understand the use-case better. This was done via a private
+channel and I am sharing it with permission.
+
+** Show the date of each linked file in Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:ad222eb0-06db-4416-820c-c60f31169f66
+:END:
+
+All our Org dynamic blocks that produce links to files now read the
+parameter =:include-date=. When it is set to =t=, the listed files
+will include their corresponding date inside of parentheses after the
+file's title.
+
+Thanks to Sergio Rey for describing this idea to me. This was done via
+a private channel and the information is shared with permission.
+
+** Exclude specific directories from Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:5c0b76fc-2758-4a33-875a-fa9eee705d83
+:END:
+
+The optional Org dynamic blocks we define let users collect links to
+other files (and more) in a quick and effective way. Each block
+accepts parameters which control its output, such as how to sort
+files.
+
+All our dynamic blocks now accept the =:excluded-dirs-regexp=. This is
+a regular expression which is matched against directory file system
+paths. Matching directories and their files are not included in the
+data handled by the dynamic block.
+
+Note that we have the user option ~denote-excluded-punctuation-regexp~
+which defines a global preference along the same lines.
+
+I did a video about this feature:
+<https://protesilaos.com/codelog/2024-07-30-emacs-denote-exclude-dirs-org-blocks/>.
+
+Thanks to Claudio Migliorelli for discussing this idea with me. It was
+done via a private channel and this information is shared with permission.
+
+** New dynamic block to insert files as headings
+:PROPERTIES:
+:CUSTOM_ID: h:0cae3fdb-ba83-46f0-9006-13d0073ae092
+:END:
+
+We already had an Org dynamic block that would insert file contents.
+Though that one inserts files as they are, optionally without their
+front matter. However, users may have a workflow where they want to
+eventually copy some of the block's output into the main file they are
+editing, at which point it is easier for the entire inserted file to
+appear as a series of headings. The =#+title= of the inserted file
+becomes a top-level heading and every other heading is pushed deeper
+one level.
+
+To this end, we provide the Org dynamic block known as ~denote-files-as-headings~.
+Insert it with the command ~denote-org-extras-dblock-insert-files-as-headings~
+or select it with the minibuffer after calling Org's own command
+~org-dynamic-block-insert-dblock~.
+
+The top-level headings (those that were the =#+title=) can optionally
+link back to the original file. Though please read the manual for all
+the parameters this dynamic block takes.
+
+** The dynamic block for backlinks can be about the current heading only
+:PROPERTIES:
+:CUSTOM_ID: h:6e6deff6-c02d-4157-85c0-fc405f64ad34
+:END:
+
+The Org dynamic block for backlinks can now read the optional
+=:this-heading-only= parameter. When it is set to =t=, the block will
+only include links that point to the specific heading inside of the
+current file. Otherwise, backlinks are about the whole file.
+
+To insert such a dynamic block, use the command
+~denote-org-extras-dblock-insert-backlinks~.
+
+** Toggle the detailed view in backlinks buffers
+:PROPERTIES:
+:CUSTOM_ID: h:01b4dfb0-3883-4cc8-ac41-8a7b55e42fe8
+:END:
+
+By default, the buffer produced by the command ~denote-backlinks~ has
+a compact view of showing the file names linking to the current file.
+With the user option ~denote-backlinks-show-context~ set to a non-nil
+value, the backlinks buffer produces a detailed listing of matching
+results, where the links are shown in their original context.
+
+Users can now choose to have this on-demand by calling the command
+~denote-backlinks-toggle-context~ which switches between the detailed
+and compact views.
+
+This blog post I wrote about it include screenshots:
+<https://protesilaos.com/codelog/2024-07-25-emacs-denote-backlinks-context-toggle/>.
+
+** Templates can have a function that returns a string
+:PROPERTIES:
+:CUSTOM_ID: h:8d0ac1eb-d057-4fce-bf60-98d5de932a0d
+:END:
+
+The ~denote-templates~ variable allows the user to specify one or more
+named templates which can then be inserted during the creation of a
+new note. One way to be prompted for a template among those specified
+is to modify the ~denote-prompts~ user option and then use the regular
+~denote~ command. Another way is to use the command ~denote-template~
+(alias ~denote-create-note-with-template~), which will prompt for the
+template to use.
+
+Templates ordinarily have a string as their value, though now their
+value can also be the symbol of a function. This function takes no
+arguments and is expected to return a string. Denote takes care to
+insert that below the front matter of the new note.
+
+So it can look like this:
+
+#+begin_src emacs-lisp
+(setq denote-templates
+      `((report . "* Some heading\n\n* Another heading") ; A string with newline characters
+        (blog . my-denote-template-function-for-blog) ; the symbol of a function that will return a string
+        (memo . ,(concat "* Some heading" ; expand this `concat' into a string
+                         "\n\n"
+                         "* Another heading"
+                         "\n\n"))))
+#+end_src
+
+Thanks to skissue (Ad) for the contribution in pull request 398:
+<https://github.com/protesilaos/denote/pull/398>. The change is small,
+meaning that its author does not need to assign copyright to the Free
+Software Foundation.
+
+Also thanks to Jean-Philippe Gagné Guay for extending this to
+~denote-org-capture~. Done in pull request 399:
+<https://github.com/protesilaos/denote/pull/399>. Jean-Philippe is a
+long-time contributor who has assigned copyright to the Free Software
+Foundation.
+
+** The ~denote-rename-buffer-mode~ can now show if a file has backlinks
+:PROPERTIES:
+:CUSTOM_ID: h:b163982b-3fea-48c8-90a0-d8358e066951
+:END:
+
+This global minor mode takes care to rename the buffers of Denote
+files to a pattern that is easier for users to read. As with
+everything, it is highly configurable. The default value now includes
+an indicator that shows if the current file has backlinks (other files
+linking to it).
+
+The exact characters used in this indicator are specified in the new
+user option ~denote-rename-buffer-backlinks-indicator~. The default
+value is ="<-->"=, which hopefully communicates the idea of a link
+(but, yeah, symbolism is hard). Users may want to modify this to add
+some fancier Unicode character.
+
+Thanks to Ashton Wiersdorf for the original contribution in pull
+request 392: <https://github.com/protesilaos/denote/pull/392>. Ashton
+has assigned copyright to the Free Software Foundation.
+
+** The ~denote-rename-buffer-format~ has changed
+:PROPERTIES:
+:CUSTOM_ID: h:8913785e-5c87-48ab-9df2-dafbbb9b1a5d
+:END:
+
+In the same theme as above, the user option ~denote-rename-buffer-format~
+has a new default value. Before, it would only show the title of the
+file. Now it shows the aforementioned ~denote-rename-buffer-backlinks-indicator~,
+if there are backlinks, plus the title, plus a literal ="[D]"= prefix.
+The prefix should make it easier to spot Denote files in a buffer
+listing.
+
+Read the documentation of ~denote-rename-buffer-format~ for how to
+tweak this to your liking.
+
+** New user option ~denote-kill-buffers~
+:PROPERTIES:
+:CUSTOM_ID: h:14177204-6269-48c1-bc65-de72b59d4e84
+:END:
+
+This controls whether and when Denote should automatically kill any
+buffer it generates while creating a new note or renaming an existing
+file. The manual describes the details.
+
+By default, Denote does not kill any buffers to give users the chance
+to review what is on display and confirm any changes or revert them
+accordingly.
+
+Thanks to Jean-Philippe Gagné Guay for the contribution in pull
+request 426: <https://github.com/protesilaos/denote/pull/426>. This is
+related to issues 273 and 413, so also thanks to Vineet C. Kulkarni
+and mentalisttraceur for their participation and/or questions.
+
+** The ~denote-journal-extras-new-or-existing-entry~ handles any filename component order
+:PROPERTIES:
+:CUSTOM_ID: h:0b570a97-3e0c-488f-9c9d-02d2f8ac786f
+:END:
+
+Version =3.0.0= of Denote introduced a new option to rearrange the
+file name components. All Denote commands should respect it. We did,
+however, have a problem with the command ~denote-journal-extras-new-or-existing-entry~ 
+which was not recognising the date properly.
+
+Thanks to Jakub Szczerbowski for the contribution in pull request 395:
+<https://github.com/protesilaos/denote/pull/395>. The change is small,
+meaning that Jakub does not need to assign copyright to the Free
+Software Foundation.
+
+While I am documenting this here, users should already have the fix as
+I published a minor release for it in July (in fact, there were 8
+minor releases in the aftermath of the =3.0.0= release, which
+addressed several small issues).
+
+** The ~denote-rename-file-using-front-matter~ recognises the file-at-point in Dired
+:PROPERTIES:
+:CUSTOM_ID: h:01f652c5-5713-4884-8a01-ee39f1388a12
+:END:
+
+This makes it consistent with how ~denote-rename-file~ works. I am
+implemented this in response to issue 401 where Alp Eren Kose assumed
+it was the default behaviour: <https://github.com/protesilaos/denote/issues/401>.
+
+I think it makes sense to have it this way to avoid such confusion.
+Still, it seems easier to edit the file and call ~denote-rename-file-using-front-matter~
+directly, rather do an intermediate step through Dired.
+
+** The ~denote-rename-file-using-front-matter~ does not ask to rewrite front matter
+:PROPERTIES:
+:CUSTOM_ID: h:337c5640-8e75-408e-b5cf-4a37ac8e249b
+:END:
+
+The workflow for this command is that the user modifies the front
+matter, invokes the command, and Denote takes care to rename the file
+accordingly. We had a regression were this would happen as expected,
+but Denote would still prompt if it was okay to update the front
+matter. That made no sense.
+
+As with the change mentioned above, this was also fixed in a minor
+release so that users would not have to wait all this time.
+
+** The ~denote-add-links~ and ~denote-find-link~ commands always works inside a silo
+:PROPERTIES:
+:CUSTOM_ID: h:9c343ddb-a31a-41d5-90c2-ce54622558fa
+:END:
+
+This was always the intended behaviour, though there was an issue with
+the implementation that prevented the directory-local value from being
+read.
+
+Thanks to yetanotherfossman for reporting the problem with
+~denote-add-links~ in issue 386 and to Kolmas for doing the same for
+~denote-find-link~:
+
+- <https://github.com/protesilaos/denote/issues/386>.
+- <https://github.com/protesilaos/denote/issues/416>.
+
+Also thanks to Jean-Philippe Gagné Guay for following up with a change
+to the code that should address the underlying problem with temporary
+buffers. This was done in pull request 419:
+<https://github.com/protesilaos/denote/pull/419>.
+
+** Denote commands should work in more special Org buffers
+:PROPERTIES:
+:CUSTOM_ID: h:e33bea49-f2b4-43ee-96ac-d24630c9bcd7
+:END:
+
+A case we already handled was ~org-capture~ buffers. Another one is
+the buffer produced by the command ~org-tree-to-indirect-buffer~.
+
+Thanks to coherentstate for bringing this matter to my attention in
+issue 418: <https://github.com/protesilaos/denote/issues/418>.
+
+Also thanks to skissue for noting another edge case that prevented
+~denote-rename-buffer-mode~ from doing the right thing. This was
+reported in issue 393: <https://github.com/protesilaos/denote/issues/393>.
+
+** Denote will not create a =CUSTOM_ID= via ~org-capture~ if not necessary
+:PROPERTIES:
+:CUSTOM_ID: h:c9c04d9a-776d-4b6b-826a-cd9a56f31643
+:END:
+
+If the ~org-capture~ template does not include one of the specifiers
+which produce a link, then we take care to not include a =CUSTOM_ID=
+in the properties of the current heading. We do this to make it
+possible to link directly to a heading inside of a file (a feature
+that is documented in the manual).
+
+Before, we were creating the =CUSTOM_ID= unconditionally, which was
+not the desired behaviour. Thanks to Jonas Großekathöfer for bringing
+this matter to my attention in issue 404:
+<https://github.com/protesilaos/denote/issues/404>.
+
+** The prompt for selecting a silo has the appropriate metadata
+:PROPERTIES:
+:CUSTOM_ID: h:cc5951b1-ee87-4126-b3f2-91c32e3431ae
+:END:
+
+All the Denote minibuffer prompts have the appropriate completion
+metadata to integrate with core Emacs functionalities and with
+third-party packages that leverage them. One such case pertains to the
+completion category our prompts report. This is used by a package such
+as ~embark~ to infer the set of relevant actions to perform or by the
+~marginalia~ package to produce the appropriate annotations.
+
+Users will now notice a difference while using commands such as
+~denote-silo-extras-create-note~ if they have ~marginalia-mode~
+enabled: all completion candidates will have file-related annotations.
+
+This is a small change which goes to show how the little things
+contribute to a more refined experience.
+
+** New name for option that controls where backlinks buffers are displayed
+:PROPERTIES:
+:CUSTOM_ID: h:3e0e2242-8802-4c63-adce-0e20d3f27ad9
+:END:
+
+The user option is now called ~denote-backlinks-display-buffer-action~.
+The old name ~denote-link-backlinks-display-buffer-action~ is an alias
+for it and will thus work the same way. Though you are encouraged to
+rename it in your configuration as I will eventually remove those
+obsolete symbols from the Denote code base.
+
+** The ~revert-buffer~ should do the right thing in backlinks buffers
+:PROPERTIES:
+:CUSTOM_ID: h:2982cfcd-6bef-452d-aa0d-d8ab4e721b25
+:END:
+
+I made several tweaks to the underlying code to ensure that reverting
+a backlinks buffer will always reuse the original parameters that
+generated it. Backlinks buffers are produced by the ~denote-backlinks~
+command, among others.
+
+** Lots of new entries in the manual with custom code
+:PROPERTIES:
+:CUSTOM_ID: h:991d980b-1353-4b53-8ae4-ae09450cce05
+:END:
+
+The manual of Denote is a rich resource of knowledge for how to use
+this package and how to extend it with custom code. I have written the
+following entries to further help you improve your productivity:
+
+- A custom ~denote-region~ that references the source
+- Custom sluggification to remove non-ASCII characters
+- Sort signatures that include Luhmann-style sequences
+- Why are some Org links opening outside Emacs?
+
+** More functions for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:2e41930a-1907-47f2-956e-fef8b2459461
+:END:
+
+The following functions are now public, meaning that they are safe to
+be used in the code of other packages or incorporated in user
+configurations:
+
+- ~denote-identifier-p~.
+
+- ~denote-get-identifier-at-point~. I am implementing this in response
+  to a question by Alan Schmitt in issue 400: <https://github.com/protesilaos/denote/issues/400>.
+
+- ~denote-org-extras-outline-prompt~.
+
+- ~denote-silo-extras-directory-prompt~.
+
+Consult their respective doc strings for the technicalities.
+
+Note that the Elisp convention is that private functions (intended for
+use only inside the package) have a double dash (=--=) in their name.
+In principle, these are undocumented and can change at any moment
+without any notice. I do try to avoid such cases and even add warnings
+when I make changes to them. Still, you should not use private
+functions without understanding the risks involved.
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:be41d902-8d65-4012-aad2-d66507d34f78
+:END:
+
+- Wrote more unit tests for various functions.
+- Improve the doc strings of several symbols (everything in the Denote
+  code base is documented).
+- Fix some typos thanks to Nicolas Semrau and bryanrinders:
+  - <https://github.com/protesilaos/denote/commit/e7cfd48bd63e0815718cd9f1f0465d8c1c4f4a84>.
+  - <https://github.com/protesilaos/denote/pull/425>.
+- Commented on all sorts of issues on the GitHub repository and many
+  more in private.
+
+** New release cycle starts in mid-September
+:PROPERTIES:
+:CUSTOM_ID: h:2b55dd84-6ebe-438d-aba8-97dd329ec34e
+:END:
+
+I have many ideas for how to further refine Denote. Maybe you do too.
+Though we must all wait a couple of weeks in case someone reports a
+bug. This way, it is easy to fix it and publish a new minor version.
+Otherwise, we may have to bundle the fix with some in-development
+feature that we have not fully tested yet.
+
+** Git commits
+:PROPERTIES:
+:CUSTOM_ID: h:c0da6de0-c683-4029-9d95-06c27102dc4a
+:END:
+
+This is just an overview of the Git commits, though remember that
+there is more that goes into a project, such as the reporting of
+inconsistencies, discussion of new ideas, etc.. Thanks to everybody
+involved!
+
+#+begin_src 
+~/Git/Projects/denote $ git shortlog 3.0.0..3.1.0 --summary --numbered
+   104	Protesilaos Stavrou
+     7	Jean-Philippe Gagné Guay
+     3	Ashton Wiersdorf
+     1	Ad
+     1	Jakub Szczerbowski
+     1	bryanrinders
+#+end_src
+
+* Version 3.0.0 on 2024-06-30
+:PROPERTIES:
+:CUSTOM_ID: h:bf5e869d-548f-4c77-bf1c-b7dcf6d1d4da
+:END:
+
+This major release comes about two years after the first version of
+Denote, which was published on 2022-06-27. A lot of technicalities
+have changed in the meantime, though the core idea remains the same.
+In fact, the original video presentation I did is still relevant,
+especially for those looking to get started with Denote (but remember
+to consult the latest documentation for up-to-date information---and
+ask me if you have any questions).
+
+Version 3 iterates on refinements that we made over the life cycle of
+version 2. Existing users will find that their workflow remains the
+same, though they now have even more options at their disposal.
+
+As usual, my release notes are detailed. Please take your time to read
+them: they are here for you.
+
+Special thanks to Jean-Philippe Gagné Guay, a long-time contributor to
+the project, for working on some of the items covered herein. I am not
+covering everything, as many important changes are not user-facing.
+Please consult the Git log for further details.
+
+** File name components can be written in any order
+:PROPERTIES:
+:CUSTOM_ID: h:fa0ffaf5-f762-4667-abe2-350f4ea4aac5
+:END:
+
+[ Relevant blog post: <https://protesilaos.com/codelog/2024-05-19-emacs-denote-reorder-file-name-components/>.]
+
+Users can now change the variable ~denote-file-name-components-order~
+to affect how Denote file names are constructed. By default, file
+names are written using this scheme (consult the manual for the
+details):
+
+: IDENTIFIER--TITLE__KEYWORDS.EX
+
+An optional =SIGNATURE= field can be added, thus:
+
+: IDENTIFIER==SIGNATURE--TITLE__KEYWORDS.EXT
+
+By modifying the ~denote-file-name-components-order~, users can
+produce file names like these:
+
+: --TITLE__KEYWORDS@@IDENTIFIER.EXT
+: __SIGNATURE--TITLE__KEYWORDS@@IDENTIFIER.EXT
+: __SIGNATURE--TITLE@@IDENTIFIER__KEYWORDS.EXT
+
+Note that when the =DATE= is not the first component, it gets the =@@=
+prefix to (i) remain unambiguous and (ii) make it easy to target it
+directly for search purposes.
+
+Thanks to Jean-Philippe Gagné Guay for the contribution in pull
+request 360: <https://github.com/protesilaos/denote/pull/360>.
+
+We discussed the possible delimiters for the =IDENTIFIER= in issue
+332: <https://github.com/protesilaos/denote/issues/332>. Thanks to
+Jean-Philippe, Nick Bell, Maikol Solis, and mentalisttraceur for their
+insights. Our concern was to use characters that are stylistically
+fine, while they are not special symbol in regular expressions (as
+those make searching a bit less convenient).
+
+Please remember that the file-naming scheme is the cornerstone of
+Denote. If you do change how your notes are named, make sure to be
+consistent throughout, otherwise you will likely make it harder for
+yourself to find what you need.
+
+** Exclude certain files from all prompts
+:PROPERTIES:
+:CUSTOM_ID: h:1c751e58-2f57-4aa8-9990-4ecb73054262
+:END:
+
+Sometimes users keep files in their ~denote-directory~ that they do
+not want to interactive with. These can, for example, be what Org
+produces when exporting to another file format or when archiving a
+heading.
+
+The user option ~denote-excluded-files-regexp~ makes is possible to
+omit all those files from the relevant Denote prompts.
+
+This is in response to requests for such a user option done by Samuel
+W. Flint and zadca123 in issues 376 and 384, respectively:
+
+- <https://github.com/protesilaos/denote/issues/376>
+- <https://github.com/protesilaos/denote/issues/384>
+
+[ Please let me know if you need this feature but do not know how to
+  write a regular expression. I can include concrete examples in the
+  manual, though I need to know about them first. ]
+
+** Links in plain text and Markdown files are buttonised differently
+:PROPERTIES:
+:CUSTOM_ID: h:9f9b978f-3c2b-4b27-9ff5-ec0ac24a76d0
+:END:
+
+Before we were using the function ~denote-link-buttonize-buffer~,
+which would create "buttons" for all the =denote:= links it would.
+Users probably had something like this in their configuration:
+
+#+begin_src emacs-lisp
+;; DEPRECATED method
+(add-hook 'text-mode-hook #'denote-link-buttonize-buffer)
+#+end_src
+
+We now provide an approach that is technically better by using Emacs'
+fontification mechanism. All the user needs is to add this to their
+configuration:
+
+#+begin_src emacs-lisp
+(add-hook 'text-mode-hook #'denote-fontify-links-mode-maybe)
+#+end_src
+
+The notion of "maybe" in the symbol of that function is because this
+will take care to be activated only in the right context.
+
+Thanks to Abdul-Lateef Haji-Ali for the contribution in pull request
+344 (further changes by me): <https://github.com/protesilaos/denote/pull/344>.
+
+Abdul-Lateef has assigned copyright to the Free Software Foundation.
+
+** How to make Org export work in a Denote silo
+:PROPERTIES:
+:CUSTOM_ID: h:dd39bb26-a2c0-47ad-8d54-61f1ba82d3d5
+:END:
+
+[ Relevant blog post: <https://protesilaos.com/codelog/2024-06-18-emacs-denote-silos-org-export/>. ]
+
+This is not a change in Denote per se, though I have added the
+relevant details in the manual. Basically, the Org export machinery
+dismisses directory-local variables, thus breaking how Denote silos
+work. We can work around this by having an extra =#+bind= directive in
+the front matter of each file. The manual, or the aforementioned blog
+post, describe the technicalities.
+
+** Org headings can have their own backlinks
+:PROPERTIES:
+:CUSTOM_ID: h:2464625e-e041-467c-a4fd-5744e3bb79c3
+:END:
+
+[ Relevant blog: <https://protesilaos.com/codelog/2024-04-21-emacs-denote-heading-backlinks/>. ]
+
+Denote could already link to an Org heading directly. Now it can also
+generate a backlinks buffer for the current heading, using the
+command ~denote-org-extras-backlinks-for-heading~.
+
+This is part of the optional extension =denote-org-extras.el= (it is
+part of the Denote package, but not loaded by default if you use
+something like =(require 'denote)=).
+
+I am providing this as an option for those who absolutely need it,
+though in my opinion it is better to have atomic notes, such that each
+file contains information that is relevant as a whole. In this
+workflow, individual headings can be added or removed, but the big
+picture idea of the file remain intact.
+
+At any rate, this change is possible due to the requisite refactoring
+of the code that handles the backlinks. We can technically produce
+backlinks to any pattern in files, though this may be more of interest
+to developers rather than foreshadow future features in core Denote.
+
+** Finer control over confirmations while renaming
+:PROPERTIES:
+:CUSTOM_ID: h:b3dc71a6-fa0b-48d1-b8a7-2842bf725092
+:END:
+
+The ~denote-rename-no-confirm~ is deprecated and superseded by the
+more flexible user option ~denote-rename-confirmations~.
+
+The command ~denote-rename-file~ (and others like it) prompts for
+confirmation before changing the name of a file and updating its front
+matter. The user option ~denote-rename-confirmations~ controls what
+the user is prompted for, if anything. Please consult its
+documentation for the technicalities.
+
+Thanks to Jean-Philippe Gagné Guay for the contribution in pull
+request 324: <https://github.com/protesilaos/denote/pull/324>.
+
+** The user option ~denote-save-buffer-after-creation~ is renamed to ~denote-save-buffers~
+:PROPERTIES:
+:CUSTOM_ID: h:10883c47-0f5e-4267-a122-86906bf25a61
+:END:
+
+Please update your configuration accordingly, if you were using the
+old name.
+
+** The commands ~denote-keywords-add~ and ~denote-keywords-remove~ are replaced by ~denote-rename-file-keywords~
+:PROPERTIES:
+:CUSTOM_ID: h:042699ec-5516-44ca-93ee-60b32e599029
+:END:
+
+The new command can add or remove keywords. It does this by
+prepopulating the minibuffer prompt with the existing keywords. Users
+can then use the ~crm-separator~ (normally a comma), to write new
+keywords or edit what is in the prompt to rewrite them accordingly. An
+empty input means to remove all keywords.
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input. The Emacs default setup accepts the empty
+  minibuffer contents as they are, though popular packages like
+  ~vertico~ use the first available completion candidate instead. For
+  ~vertico~, the user must either move one up to select the prompt and
+  then type =RET= there with empty contents, or use the command
+  ~vertico-exit-input~ with empty contents. That Vertico command is
+  bound to =M-RET= as of this writing on 2024-06-30 10:37 +0300. ]
+
+Technically, ~denote-rename-file-keywords~ is a wrapper for
+~denote-rename-file~, doing all the things that does.
+
+** The commands ~denote-rename-file-title~ and ~denote-rename-file-signature~
+:PROPERTIES:
+:CUSTOM_ID: h:2c2c0f6f-413b-4492-b6a2-062034692c4c
+:END:
+
+These are like the ~denote-rename-file-keywords~ we just covered.
+There are wrappers of the ~denote-rename-file~ command, which are used
+to change on the file name component they reference.
+
+If that component exists, its text is included in the minibuffer. The
+user can then modify it accordingly. If there is no text, the user is
+adding a new one. An empty input means to remove the title/signature
+from the file altogether (again, check your minibuffer for how to
+provide an empty input).
+
+** More commands to add/remove keywords in bulk from Dired
+:PROPERTIES:
+:CUSTOM_ID: h:01770801-c511-46c0-9a05-890276374b63
+:END:
+
+Two new specialised commands are available to help users add or remove
+keywords from many files at once. These are:
+
+- ~denote-dired-rename-marked-files-add-keywords~
+- ~denote-dired-rename-marked-files-remove-keywords~.
+
+They complement the ~denote-dired-rename-marked-files-with-keywords~,
+which we have had for a long time already, and which rewrites all the
+keywords (instead of only adding/removing from the list).
+
+All three of those commands operate only on the =KEYWORDS= component
+of the file name, leaving everything else as-is (while respecting the
+aforementioned ~denote-file-name-components-order~).
+
+Thanks to Vedang Manerikar for the contribution in pull request 316:
+<https://github.com/protesilaos/denote/pull/316>. Vedang has already
+assigned copyright to the Free Software Foundation.
+
+** The ~denote-org-extras-convert-links-to-file-type~ can return relative paths
+:PROPERTIES:
+:CUSTOM_ID: h:5f97d3f5-294d-467d-858b-281e46060625
+:END:
+
+The previous implementation would always return an absolute file path,
+ignoring the Org user option ~org-link-file-path-type~. Whereas now it
+will return a relative path if that user option is set to a value of
+either ='adaptive= or ='relative=.
+
+Thanks to Alexandre Rousseau for the contribution in pull request 325:
+<https://github.com/protesilaos/denote/pull/325>. The change is small,
+meaning that Alexandre does not need to assign copyright to the Free
+Software Foundation.
+
+** For developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:6911a5d6-6de3-4e04-b9d2-12a6526b4e97
+:END:
+
+*** The ~denote-add-prompts~ is made public
+:PROPERTIES:
+:CUSTOM_ID: h:28bfa74b-5a38-4f3c-a5fe-bf5a697385db
+:END:
+
+This is used to ~let~ bind any additional prompts that should be used
+by the ~denote~ command. Check the source code for how we are using
+this function.
+
+*** The ~denote-select-linked-file-prompt~ is now public
+:PROPERTIES:
+:CUSTOM_ID: h:669f8eee-bdab-406a-aada-73ee8de9caf2
+:END:
+
+This is used internally but the commands ~denote-find-link~,
+~denote-find-backlink~. Refer to the implementation of those commands
+to get an idea of how to use this prompt.
+
+*** The ~denote-retrieve-title-or-filename~ is just a wrapper
+:PROPERTIES:
+:CUSTOM_ID: h:414cfd70-1850-44bf-b0fe-fb3809af302e
+:END:
+
+It simply calls the ~denote-retrieve-front-matter-title-value~ or
+~denote-retrieve-filename-title~. We do not want it to return the
+~file-name-base~, as it used to, because this will duplicate the text
+of the file name when there is no =TITLE= component, as demonstrated by
+duli in issue 347: <https://github.com/protesilaos/denote/issues/347>.
+
+*** The ~denote-file-prompt~ is more robust
+:PROPERTIES:
+:CUSTOM_ID: h:f7fb9e1f-e7b9-4dd1-a517-79069f28dcfe
+:END:
+
+We have made this function show relative file paths for the
+convenience of the user, but we take care to internally return and
+store the full file path (which is unambiguous). Thanks to Alan
+Schmitt for noting that the history was not working properly. This was
+done in issue 339: <https://github.com/protesilaos/denote/issues/339>.
+A series of commits dealt with the implementation details, including a
+contribution by Jean-Philippe Gagné Guay in pull request 342:
+<https://github.com/protesilaos/denote/pull/342>. Also read 353 for a
+further set of tweaks from my side: <https://github.com/protesilaos/denote/discussions/353>.
+
+As part of these changes, the ~denote-file-prompt~ now takes a
+=NO-REQUIRE-MATCH= argument. It also respects the aforementioned user
+option of ~denote-excluded-files-regexp~.
+
+*** Relevant functions conform with the ~denote-rename-confirmations~
+:PROPERTIES:
+:CUSTOM_ID: h:b056abdf-b9d9-4799-8e24-ae6507b4780e
+:END:
+
+These include the ~denote-rename-file-prompt~ and
+~denote-rewrite-front-matter~, as well as the new
+~denote-add-front-matter-prompt~.
+
+This has the meaning of what I mentioned above. Commands that need to
+deviate from the user option ~denote-rename-confirmations~ can ~let~
+bind it accordingly: we even do this for some commands in =denote.el=,
+because certain prompts do not make sense there.
+
+*** All file name components can be ~let~ bound
+:PROPERTIES:
+:CUSTOM_ID: h:0118ad59-5fc2-4a19-8946-324410adb107
+:END:
+
+We define a new series of variables which can be set to a lexically
+scoped value to control what the ~denote~ function parses. These are:
+
+- ~denote-use-date~
+- ~denote-use-directory~
+- ~denote-use-file-type~
+- ~denote-use-keywords~
+- ~denote-use-signature~
+- ~denote-use-template~
+- ~denote-use-title~
+
+Employ those for custom extensions you may have.
+
+Thanks to Jean-Philippe Gagné Guay for adding those in pull request
+365: <https://github.com/protesilaos/denote/pull/365>.
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:1fc6d700-e8aa-4d05-bbae-5623a9565922
+:END:
+
+- All the Org dynamic blocks defined by Denote in the optional
+  =denote-org-extras.el= are now autoloaded. This means that
+  evaluating such a code block will work even if the user has not
+  explicitly used something like =(require 'denote-org-extras)=.
+  Thanks to Julian Hoch for asking for a relevant clarification in
+  issue 337: <https://github.com/protesilaos/denote/issues/337>.
+  Thanks to Kolmas for reporting some missing autoloads in issue 371:
+  <https://github.com/protesilaos/denote/issues/371>.
+
+- The value of the user option ~denote-link-backlinks-display-buffer-action~
+  is slightly modified to (i) make the buffer dedicated to its window
+  and (ii) try to preserve its size during automatic recombinations of
+  the frame's layout.
+
+- There was a regression in version =2.3.0= relative to =2.2.0= where
+  the ~denote-link~ command would fail in Org capture buffers. Thanks
+  to Sven Seebeck for reporting this bug in issue 298:
+  <https://github.com/protesilaos/denote/issues/298>.
+
+- The ~denote-filetype-heuristics~ function no longer chokes if it
+  gets a nil value (such as in Org capture buffers).
+
+- The ~denote-journal-extras-directory~ (part of the optional
+  =denote-journal-extras= file) falls back to ~denote-directory~ if
+  its value is nil. This is what the user option
+  ~denote-journal-extras-directory~ promises in its doc string.
+
+- All prompts should have their scope of application in all capital
+  letters, such as =Select TEMPLATE key=. The idea is to make it
+  easier for the user to quickly spot for the prompt is about.
+
+- The user option ~denote-link-description-function~ is documented in
+  the manual. Thanks to Sven Seebeck for noticing that we did not
+  document this for the =2.3.0= release. Thanks to Jean-Philippe Gagné
+  Guay for helping me refine the code. This was all done in issue 298:
+  <https://github.com/protesilaos/denote/issues/298>.
+
+- As part of internal changes to how our various "rename" commands
+  work, Kolmas reported a regression with wrongly assigned file
+  extensions. This was done in issue 343:
+  <https://github.com/protesilaos/denote/issues/343>.
+
+- In the =denote-org-extras.el= we now always jump to the correct Org
+  heading line, instead of missing it by 1 under certain conditions.
+  Thanks to kilesduli for bringing this matter to my attention in
+  issue 354: <https://github.com/protesilaos/denote/issues/354>.
+
+** Policy for the aftermath of this release
+:PROPERTIES:
+:CUSTOM_ID: h:250e8abe-8e8d-41b9-a9dc-b2951a07d5bd
+:END:
+
+The next few days or weeks are reserved for bug fixes. We first want
+to make sure that the current code base is rock solid, before making
+any further changes. Any bugs will be addressed outright and new point
+releases will be published (though those are not accompanied by a
+change log entry).
+
+** Git commits
+:PROPERTIES:
+:CUSTOM_ID: h:e9ea8288-99d1-407d-919a-b6024d35a501
+:END:
+
+Just an overview of what we did. Thanks again to everyone involved.
+
+#+begin_src sh
+~/Git/Projects/denote $ git shortlog 2.3.0..3.0.0 --summary --numbered
+   169  Protesilaos Stavrou
+    52  Jean-Philippe Gagné Guay
+     3  Al Haji-Ali
+     2  Alan Schmitt
+     1  Alexandre Rousseau
+     1  Jianwei Hou
+     1  Vedang Manerikar
+#+end_src
+
+* Version 2.3.0 on 2024-03-24
+:PROPERTIES:
+:CUSTOM_ID: h:e9d3ebdb-8a69-47a9-a5a2-619abc44b7d2
+:END:
+
+This release brings a host of user-facing refinements to an already
+stable base, as well as some impressive new features. There is a lot
+to cover, so take your time reading these notes.
+
+Special thanks to Jean-Philippe Gagné Guay for the numerous
+refinements to parts of the code base. Some of these are not directly
+visible to users, but are critical regardless. In the interest of
+brevity, I will not be covering the most technical parts here. I
+mention Jean-Philippe's contributions at the outset for this reason.
+Though the Git commit log is there for interested parties to study
+things further.
+
+** Check out the ~denote-explore~ package by Peter Prevos
+:PROPERTIES:
+:CUSTOM_ID: h:3e49dd9d-59db-40e5-9116-ce678231b08d
+:END:
+
+This package provides several neat extensions that help you make
+better sense of your knowledge base, while keeping it in good order.
+The ~denote-explore~ package has commands to summarise the usage of
+keywords, visualise connections between notes, spot infrequently used
+keywords, and jump to previous historical entries.
+
+- Git repository: <https://github.com/pprevos/denote-explore>.
+- Documentation: <https://lucidmanager.org/productivity/denote-explore>.
+
+Now on to Denote version =2.3.0=!
+
+** Link to a heading inside a Denote Org file
+:PROPERTIES:
+:CUSTOM_ID: h:ca7baf4f-04af-4467-a1e6-20403357280f
+:END:
+
+Denote creates links to files by using their unique identifier. As Org
+provides the =CUSTOM_ID= property for per-heading identifiers, we now
+leverage this infrastructure to compose links that point to a file and
+then to a heading therein. This only works for Org, as no other plain
+text major mode has a concept of heading identifiers (and it is not
+Denote's job to create such a feature).
+
+I demonstrated the functionality in a video:
+<https://protesilaos.com/codelog/2024-01-20-emacs-denote-link-org-headings/>
+
+Technically, the =denote:= link type has the same implementation
+details as Org's standard =file:= and has always had this potential to
+jump to a section inside the given file.
+
+*** The ~denote-org-store-link-to-heading~ user option
+:PROPERTIES:
+:CUSTOM_ID: h:a7864660-5b4c-4467-a252-9140baedeb1a
+:END:
+
+The user option ~denote-org-store-link-to-heading~ determines whether
+~org-store-link~ links to the current Org heading (such links are
+merely "stored" and need to be inserted afterwards with the command
+~org-insert-link~). Note that the ~org-capture~ command uses the
+~org-link~ internally if it has to store a link.
+
+When its value is non-nil, ~org-store-link~ stores a link to the
+current Org heading inside the Denote Org file. If the heading does
+not have a =CUSTOM_ID=, it creates it and includes it in the heading's
+=PROPERTIES= drawer. If a =CUSTOM_ID= exists, ~org-store-link~ use it
+as-is.
+
+This makes the resulting link a combination of the =denote:= link type,
+pointing to the identifier of the current file, plus the value of the
+heading's =CUSTOM_ID=, such as:
+
+- =[[denote:20240118T060608][Some test]]=
+- =[[denote:20240118T060608::#h:eed0fb8e-4cc7-478f-acb6-f0aa1a8bffcd][Some test::Heading text]]=
+
+Both lead to the same Denote file, but the latter jumps to the heading
+with the given =CUSTOM_ID=. Notice that the link to the heading also
+has a different description, which includes the heading text.
+
+The value of the =CUSTOM_ID= is determined by the Org user option
+~org-id-method~. The sample shown above uses the default UUID
+infrastructure.
+
+If ~denote-org-store-link-to-heading~ is set to a nil value, the
+command ~org-store-link~ only stores links to the Denote file (using
+its identifier), but not to the given heading. This is what Denote was
+doing in all versions prior to =2.3.0=.
+
+Thanks to Kristoffer Balintona for discussing with me how
+~org-capture~ interfaces with ~org-store-link~. I updated the
+documentation accordingly. This was done in issue 267:
+<https://github.com/protesilaos/denote/issues/267>.
+
+*** Insert link to an Org file with a further pointer to a heading
+:PROPERTIES:
+:CUSTOM_ID: h:dd054536-8d20-4251-b23d-77fec7d7d036
+:END:
+
+As part of the optional =denote-org-extras.el= extension that comes
+with the ~denote~ package, the command ~denote-org-extras-link-to-heading~
+prompts for a link to an Org file and then asks for a heading therein,
+using minibuffer completion. Once the user provides input at the two
+prompts, the command inserts a link at point which has the following
+pattern: =[[denote:IDENTIFIER::#ORG-HEADING-CUSTOM-ID]][Description::Heading text]]=.
+
+Because only Org files can have links to individual headings, the
+command ~denote-org-extras-link-to-heading~ prompts only for Org files
+(i.e. files which include the =.org= extension). Remember that Denote
+works with many file types.
+
+This feature is similar to the concept of the aforementioned user
+option ~denote-org-store-link-to-heading~. It is, however, interactive
+and differs in the directionality of the action. With that user
+option, the command ~org-store-link~ will generate a =CUSTOM_ID= for
+the current heading (or capture the value of one as-is), giving the
+user the option to then call ~org-insert-link~ wherever they see fit.
+By contrast, the command ~denote-org-extras-link-to-heading~ prompts
+for a file, then a heading, and inserts the link at point.
+
+** Refinements galore to minibuffer prompts
+:PROPERTIES:
+:CUSTOM_ID: h:e509402b-a58f-4a10-b364-b158b31d1ee5
+:END:
+
+*** All commands that affect file names conform with ~denote-prompts~
+:PROPERTIES:
+:CUSTOM_ID: h:11f0fc1e-552b-4a02-bf01-9d8508ce68c8
+:END:
+
+The scope of the ~denote-prompts~ user option is broadened to make it
+more useful. In the past, this variable would only affect the
+behaviour of the ~denote~ command. For example, the user would make
+the command prompt for a subdirectory, then keywords, then a title.
+But all other commands were not following this setting, as they were
+hardcoding the prompts for title and keywords.
+
+Take the ~denote-subdirectory~ command as an example. It would first
+prompt for a subdirectory to place the new note in, then for a title,
+and then for keywords. Whereas now, it prepends the =subdirectory=
+prompt to the list of ~denote-prompts~. So if the user has configured
+their ~denote-prompts~ to, for example, ask for a signature and a file
+type, the ~denote-subdirectory~ will do just that with the addition of
+the =subdirectory= prompt.
+
+Same idea for all commands that either create or modify file names,
+wherever conformity with ~denote-prompts~ makes sense. For example,
+the ~denote-rename-file~ will never ask for a =subdirectory= because
+our renaming policy is to always rename in place (to avoid
+mistakes---you can always move the file afterwards).
+
+This also means that the ~denote-rename-file~ and its multi-file
+counterpart, ~denote-dired-rename-files~, will only prompt for a
+signature if it is part of the ~denote-prompts~. Whereas in the
+previous version this was unconditional, thus burdening users who do
+not need the =SIGNATURE= file name component (more about renaming
+further into the release notes).
+
+Lots of Git commits went into this redesign, per my initiave in issue
+247: <https://github.com/protesilaos/denote/issues/247>. Thanks to
+Vedang Manerikar for the changes to the convenience wrappers of the
+~denote~ command (like ~denote-subdirectory~), which were done in pull
+request 248: <https://github.com/protesilaos/denote/pull/248>.
+
+Vedang has assigned copyright to the Free Software Foundation.
+
+Also thanks to Max Brieiev for joining the technical discussion
+therein.
+
+The renaming commands are more intuitive now, which addresses a
+discussion point raised by user babusri in issue 204:
+<https://github.com/protesilaos/denote/issues/204>.
+
+*** A simple tweak for more informative minibuffer prompts
+:PROPERTIES:
+:CUSTOM_ID: h:a502217d-8eff-4a6f-b66a-33e5e7ecda9d
+:END:
+
+The text of each prompt now has all capital letters for the word
+referencing its scope of its application, like =TITLE=, =KEYWORDS=,
+=SIGNATURE=. The idea is to make it easier to quickly scan the text,
+especially while working through multiple prompts. For example, the
+prompt for a title now reads:
+
+: New file TITLE:
+
+This paradigm is followed by all prompts. It is a small yet effective
+tweak to get a better sense of context.
+
+*** The file prompt uses relative names once again
+:PROPERTIES:
+:CUSTOM_ID: h:8f182ad3-c97f-45dc-a451-c552f2a7957c
+:END:
+
+In previous versions of Denote, the minibuffer prompt to pick a file
+(such as a file to link to) would show relative file names: the name
+without the full file system path. The functionality depended on the
+built-in =project.el= library, which did not allow us to do everything
+we wanted with our prompts, such as to have a dedicated minibuffer
+history or to easily enable the workflow of commands like
+~denote-open-or-create~.
+
+In the previous version, I made the decision to remove the
+=project.el= dependency and the concomitant presentation of relative
+names in order to add the functionality we want. I did it with the
+intention to find a better solution down the line. Et voilá! Relative
+file names are back. We now have all the functionality we need. Sorry
+if in the meantime you had to deal with those longer names! It was a
+necessary intermediate arrangement for the greater good.
+
+For the technicalities, refer to the source code of the function
+~denote-title-prompt~.
+
+*** Completion using previous inputs is now optional
+:PROPERTIES:
+:CUSTOM_ID: h:bcf382e4-bd00-49f3-859a-3f86e9770b77
+:END:
+
+All our minibuffer prompts have their dedicated history (you can
+persist histories with the built-in ~savehist-mode~). They store
+previous values, giving the user easy access to their past input
+values. Some of our commands not only record a history, but also
+leverage it to provide completion. These commands are named in the
+variable ~denote-prompts-with-history-as-completion~. As of this
+writing, they are:
+
+- ~denote-title-prompt~
+- ~denote-signature-prompt~
+- ~denote-files-matching-regexp-prompt~
+
+Users who do not want to use completion for those can set the new user
+option ~denote-history-completion-in-prompts~ to a nil value.
+
+** Renaming files got better all-round
+:PROPERTIES:
+:CUSTOM_ID: h:747e126a-b966-4ac8-a8ec-cf900012e37e
+:END:
+
+One of the pillars of the ~denote~ package is its ability to rename
+any file to use the efficient Denote file-naming scheme (makes file
+names predictable and easy to retrieve even with rudimentary tools).
+To this end, we provide several commands that affect file names,
+beside the commands that create new files.
+
+As noted above, the commands which rename files to follow the Denote
+file-naming scheme now conform with the user option ~denote-prompts~,
+but there is more!
+
+*** A broadened scope for the ~denote-rename-no-confirm~ option
+:PROPERTIES:
+:CUSTOM_ID: h:f93b8075-de2d-416e-9275-7225d03678ad
+:END:
+
+The implementation of this user option is redone (i) to save the
+underlying buffer outright if the user does not want to provide their
+confirmation for a rename each time and (ii) to cover all relevant
+commands that perform a rename operation. The assumption is that the
+user who opts in to this feature is familiar with the Denote renaming
+modalities and knows they are reliable.
+
+The default is still the same: Denote always asks for confirmation
+before renaming a file, showing the difference between the old and new
+names, as well as any changes to the file's contents. In this light,
+buffers are not saved to give the user the chance to further inspect
+the changes (such as by running ~diff-buffer-with-file~).
+
+Commands that will now skip all confirmation prompts to rename the file
+and, where relevant, save the corresponding buffer outright:
+
+- ~denote-rename-file~
+- ~denote-dired-rename-files~
+- ~denote-dired-rename-marked-files-with-keywords~
+- ~denote-rename-file-using-front-matter~
+- ~denote-rename-add-keywords~
+- ~denote-rename-remove-keywords~
+- ~denote-rename-add-signature~ (new, more below)
+- ~denote-rename-remove-signature~ (new, more below)
+
+*** Rename a file by adding or removing a =SIGNATURE= component
+:PROPERTIES:
+:CUSTOM_ID: h:01ab0277-b4d4-433e-bd25-b9a0357412f6
+:END:
+
+The =SIGNATURE= is an optional free-form field that is part of a
+Denote file name. A common use-case is to write sequence notes with
+it, though Denote does not enforce any particular convention (you may
+prefer to have it as a special kind of keyword for certain files that
+simply stands out more due to its placement).
+
+[ Besides, the ~denote-sort-dired~ command lets you filter and sort
+  files while putting them in a fully fledged Dired buffer, so
+  manually sequencing notes via their signature may not be needed. ]
+
+We now provide two commands to add or remove a signature from file
+names:
+
+- The ~denote-rename-add-signature~ prompts for a file and a
+  signature. The default value for the file prompt is the file of the
+  currently open buffer or the file-at-point in a Dired buffer. The
+  signature is an ordinary string, defaulting to the selected file's
+  signature, if any.
+
+- The ~denote-rename-remove-signature~ uses the same file prompt as
+  above. It performs its action only if the selected file has a
+  signature. Otherwise, it does nothing.
+
+Files that do not have a Denote file name are renamed accordingly.
+Though for such cases it is better to use ~denote-rename-file~ or
+~denote-dired-rename-files~ as they are more general.
+
+*** Use the ~denote-after-rename-file-hook~ for optional post-rename operations
+:PROPERTIES:
+:CUSTOM_ID: h:57f4f60c-7873-4542-a7a5-5c997cdbd137
+:END:
+
+All renaming commands run the ~denote-after-rename-file-hook~ after a
+successful operation. This is meant for users who want to do something
+specific after the renaming is done.
+
+** More optional features of the =denote-org-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:a0a2753e-5be9-4776-9f3f-e3b7556c13c1
+:END:
+
+I already covered the ~denote-org-extras-link-to-heading~, though the
+file =denote-org-extras.el= has some more optional goodies for those
+who work with Org files.
+
+*** Create a note from the current Org subtree
+:PROPERTIES:
+:CUSTOM_ID: h:fbf1e574-e9aa-4c67-8034-27341d7a5536
+:END:
+
+In Org parlance, an entry with all its subheadings and other contents
+is a "subtree". Denote can operate on the subtree to extract it from
+the current file and create a new file out of it. One such workflow is
+to collect thoughts in a single document and produce longer standalone
+notes out of them upon review.
+
+The command ~denote-org-extras-extract-org-subtree~ (part of the
+optional =denote-org-extras.el= extension) is used for this purpose.
+It creates a new Denote note using the current Org subtree. In doing
+so, it removes the subtree from its current file and moves its
+contents into a new file.
+
+The text of the subtree's heading becomes the =#+title= of the new
+note. Everything else is inserted as-is.
+
+Read the documentation string of ~denote-org-extras-extract-org-subtree~
+or consult the manual for further details.
+
+*** Convert =denote:= links to =file:= links
+:PROPERTIES:
+:CUSTOM_ID: h:042e26e8-e3e0-4c57-9855-6b363671ae9a
+:END:
+
+Sometimes the user needs to translate all =denote:= link types to
+their =file:= equivalent. This may be because some other tool does not
+recognise =denote:= links (or other custom links types---which are a
+standard feature of Org, by the way). The user thus needs to (i)
+either make a copy of their Denote note or edit the existing one, and
+(ii) convert all links to the generic =file:= link type that
+external/other programs understand.
+
+The optional extension =denote-org-extras.el= contains two commands
+that are relevant for this use-case:
+
++ Convert =denote:= links to =file:= links :: The command
+  ~denote-org-extras-convert-links-to-file-type~ goes through the
+  buffer to find all =denote:= links. It gets the identifier of the
+  link and resolves it to the actual file system path. It then
+  replaces the match so that the link is written with the =file:= type
+  and then the file system path. The optional search terms and/or link
+  description are preserved.
+
++ Convert =file:= links to =denote:= links :: The command
+  ~denote-org-extras-convert-links-to-denote-type~ behaves like the
+  one above. The difference is that it finds the file system path and
+  converts it into its identifier.
+
+*** The Denote Org dynamic blocks are now in =denote-org-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:51d72c47-d434-4954-98d6-2db7a7ea6812
+:END:
+
+As part of this version, all our dynamic blocks are defined in the
+file =denote-org-extras.el=. The file which once contained these block
+definitions, =denote-org-dblock.el=, now only has aliases for the new
+function names and dipslays a warning about its deprecation.
+
+There is no need to ~require~ the ~denote-org-extras~ feature because
+all of Denote's Org dynamic blocks are autoloaded (meaning that they
+work as soon as they are used). For backward compatibility, all
+dynamic blocks retain their original names as an alias for the newer
+one.
+
+We will not remove =denote-org-dblock.el= anytime soon to avoid any
+potential breakage with people's existing notes. Though if you are new
+to this functionality, you better avoid the deprecated symbols.
+
+*** Org dynamic block to only insert missing links
+:PROPERTIES:
+:CUSTOM_ID: h:45176e63-c609-40f6-a11d-1cc0c28460dd
+:END:
+
+The =denote-missing-links= block is available with the command
+~denote-org-extras-dblock-insert-missing-links~. It is like the
+=denote-links= block (documented at length in the manual), except it
+only lists links to files that are not present in the current buffer.
+The parameters are otherwise the same:
+
+: #+BEGIN: denote-missing-links :regexp "YOUR REGEXP HERE" :sort-by-component nil :reverse-sort nil :id-only nil
+:
+: #+END:
+
+Remember to type =C-c C-x C-u= (~org-dblock-update~) with point on the
+=#+BEGIN= line to update the block.
+
+This brings back a feature that was deprecated in version 2.2.0, but
+makes changes to it so that (i) it is more limited in scope and (ii)
+available as a standalone Org dynamic block.
+
+Thanks to Stephen R. Kifer, Peter Prevos, and Elias Storms for the
+discussion which made it clear to me that users do have a need for
+such functionality. This was done in the now-defunct mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C1db2104e-70bd-47f9-a7ed-b8d4bb370a7f%40app.fastmail.com%3E>.
+
+Also thanks to Vedang Manerikar for fixing an edge case bug. This was
+done in pull request 260: <https://github.com/protesilaos/denote/pull/260>.
+
+Org dynamic blocks are a powerful feature which also showcases how far
+we can go with Denote's efficient file-naming scheme.
+
+** Quality-of-life improvements
+:PROPERTIES:
+:CUSTOM_ID: h:08f27f36-0ed2-4a5e-b02b-f0075c6e904f
+:END:
+
+Here I include other changes we made to existing functionality.
+
+*** BREAKING User-defined sluggification of file name components
+:PROPERTIES:
+:CUSTOM_ID: h:240b80e7-242c-46fb-83d2-1ba36bdcaf66
+:END:
+
+In the previous version, we introduced the user option
+~denote-file-name-letter-casing~. This was used to control the letter
+casing of file name components, but was ultimately not flexible enough
+for our purposes. We are thus retiring it and replacing it with the
+more powerful, but also more advanced, user option
+~denote-file-name-slug-functions~.
+
+For existing users of the deprecated functionality, you can still
+preserve the input of a prompt verbatim with something like this:
+
+#+begin_src emacs-lisp
+(setq denote-file-name-slug-functions
+      '((title . denote-sluggify-title)
+        (keyword . identity)
+        (signature . denote-sluggify-signature)))
+#+end_src
+
+The manual explains the details and shows ready-to-use code samples.
+
+Remember that deviating from the default file-naming scheme of Denote
+will make things harder to use in the future, as files will have
+permutations that create uncertainty. The sluggification scheme and
+concomitant restrictions we impose by default are there for a very
+good reason: they are the distillation of years of experience. Here we
+give you what you wish, but bear in mind it may not be what you need.
+You have been warned.
+
+Thanks to Jean-Philippe Gagné Guay for introducing this variable,
+among other tweaks, in pull request 217: <https://github.com/protesilaos/denote/pull/217>.
+Jean-Philippe has assigned copyright to the Free Software Foundation.
+
+*** Option to automatically save the buffer of a new note
+:PROPERTIES:
+:CUSTOM_ID: h:3e1249f1-ac26-4187-9ddd-7391b4e5131f
+:END:
+
+The user option ~denote-save-buffer-after-creation~ controls whether
+commands that create new notes save their buffer right away.
+
+The default behaviour of commands such as ~denote~ (or related) is to
+not save the buffer they create. This gives the user the chance to
+review the text before writing it to a file. The user may choose to
+delete the unsaved buffer, thus not creating a new file on disk.
+
+If ~denote-save-buffer-after-creation~ is set to a non-nil value, such
+buffers are saved automatically and so the file is written to disk.
+
+*** The ~denote-menu-bar-mode~ and the placement of the Denote submenu
+:PROPERTIES:
+:CUSTOM_ID: h:c8336927-cf6b-4770-b041-123bf9186e57
+:END:
+
+The command ~denote-menu-bar-mode~ toggles the inclusion of the
+submenu with the Denote entries in the Emacs menu bar (which is on
+display when ~menu-bar-mode~ is enabled).
+
+This submenu is now shown after the =Tools= entry.
+
+Thanks to Joseph Turner for sending me the relevant patches. Joseph
+has assigned copyright to the Free Software Foundation.
+
+*** The =C-c C-o= works in ~markdown-mode~ for Denote links
+:PROPERTIES:
+:CUSTOM_ID: h:1c884b19-7ab7-4eb5-a332-815d25f7373c
+:END:
+
+In files whose major mode is ~markdown-mode~, the default key binding
+=C-c C-o= (which calls the command ~markdown-follow-thing-at-point~)
+correctly resolves =denote:= links. This method works in addition to
+the =RET= key, which is made available by the buttonization that we
+also provide. Interested users can refer to the function
+~denote-link-markdown-follow~ for the implementation details.
+
+Thanks to user pmenair for noting a case where this was breaking
+general Markdown linking functionality. This was done in issue 290:
+<https://github.com/protesilaos/denote/issues/290>.
+
+*** More fine-grained control of Denote faces for dates/identifiers
+:PROPERTIES:
+:CUSTOM_ID: h:c6f739ef-ea26-41b8-84e6-c87c4622cdba
+:END:
+
+We now define more faces for fine-grained control of the identifier in
+Dired. Thanks to mentalisttraceur for suggesting the idea in issue
+276: <https://github.com/protesilaos/denote/issues/276>.
+
+Before you ask, no, none of my themes will cover those faces because
+extra colouration is something only the user can decide if they want
+or not. In the above link I provide a sample with a screenshot (apart
+from the ~modus-themes~, my ~ef-themes~ and ~standard-themes~ have
+similar functionality):
+
+#+begin_src emacs-lisp
+(defun my-modus-themes-denote-faces (&rest _)
+  (modus-themes-with-colors
+    (custom-set-faces
+     `(denote-faces-year ((,c :foreground ,cyan)))
+     `(denote-faces-month ((,c :foreground ,magenta-warmer)))
+     `(denote-faces-day ((,c :foreground ,cyan)))
+     `(denote-faces-time-delimiter ((,c :foreground ,fg-main)))
+     `(denote-faces-hour ((,c :foreground ,magenta-warmer)))
+     `(denote-faces-minute ((,c :foreground ,cyan)))
+     `(denote-faces-second ((,c :foreground ,magenta-warmer))))))
+
+(add-hook 'modus-themes-post-load-hook #'my-modus-themes-denote-faces)
+#+end_src
+
+*** New convenience command for users of the optional =denote-journal-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:9e7bff88-a6ad-45e7-b802-0493153e0e20
+:END:
+
+The command ~denote-journal-extras-link-or-create-entry~ links to the
+journal entry for today or creates it in the background, if missing,
+and then links to it from the current file. If there are multiple
+journal entries for the same day, it prompts to select one among them
+and then links to it. When called with an optional prefix argument
+(such as =C-u= with default key bindings), the command prompts for a
+date and then performs the aforementioned. With a double prefix
+argument (=C-u C-u=), it also produces a link whose description
+includes just the file's identifier.
+
+Thanks to Alan Schmitt for contributing this command, based on
+previous discussions. It was done in pull request 243:
+<https://github.com/protesilaos/denote/pull/243>.
+
+** For developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:03778c8c-60aa-449c-96df-7e41916668a6
+:END:
+
+These has new parameters or are new symbols altogether. Please read
+their respective doc string for the details.
+
++ Function ~denote-convert-file-name-keywords-to-crm~.
++ Function ~denote-valid-date-p~.
++ Function ~denote-parse-date~.
++ Function ~denote-retrieve-title-or-filename~.
++ Function ~denote-get-identifier~.
++ Function ~denote-signature-prompt~.
++ Function ~denote-file-prompt~.
++ Function ~denote-keywords-prompt~.
++ Function ~denote-title-prompt~.
++ Function ~denote-rewrite-front-matter~.
++ Function ~denote-rewrite-keywords~.
++ Function ~denote-update-dired-buffers~.
++ Function ~denote-format-string-for-org-front-matter~.
++ Function ~denote-format-string-for-md-front-matter~.
++ Variable ~denote-link-signature-format~.
++ Function ~denote-link-description-with-signature-and-title~.
++ Variable ~denote-link-description-function~.
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:040f2678-674d-4e99-b428-659cd3a3b7c3
+:END:
+
+- The ~denote-sort-dired~ function no longer errors out when there is
+  no match for the given search terms. Thanks to Vedang Manerikar for
+  the initial patch! This was done in the now-defunct mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/patches/47625>. Further
+  changes by me.
+
+- The ~denote-keywords-sort~ function no longer tries to sort keywords
+  that are not a list. Thanks to Ashton Wiersdorf for the patch. The
+  change is small. As such, Ashton does not need to assign copyright
+  to the Free Software Foundation.
+
+- Documented in the manual that custom convenience commands can be
+  accessed by the ~denote-command-prompt~. Thanks to Glenna D. for
+  clarifying the language.
+
+- The ~denote-user-enforced-denote-directory~ is obsolete. Those who
+  used it in their custom code can simply ~let~ bind the value of the
+  variable ~denote-directory~. Thanks to Jean-Philippe Gagné Guay for
+  making the relevant changes (the Git history is not direct here and
+  I cannot quickly find the pull request---the commit is =a48a1da=).
+
+- The ~denote-link-return-links~ no longer keeps buffers around.
+  Thanks to Matteo Cavada for the patch. This was done in pull request
+  252: <https://github.com/protesilaos/denote/pull/252>. The change is
+  small and so Matteo does not need to assign copyright to the Free
+  Software Foundation.
+
+- Thanks to user jarofromel (recorded in Git as "random" author) for
+  fixing a mismatched parenthesis in ~denote-parse-date~. This was
+  done in pull request 258: <https://github.com/protesilaos/denote/pull/258>.
+
+- The ~denote-rename-buffer-mode~ now works as expected with
+  non-editable files, like PDFs. Thanks to Alan Schmitt for bringing
+  this matter to my attention and then refining the implementation
+  details in pull request 268: <https://github.com/protesilaos/denote/pull/268>.
+
+- All the Denote linking functions can be used from any file outside
+  the ~denote-directory~ (links are still resolved to files inside the
+  ~denote-directory~). Thanks to Jean-Philippe Gagné Guay for the
+  contribution in pull request 236: <https://github.com/protesilaos/denote/pull/236>.
+
+- We removed all glue code that integrated Denote with the built-in
+  ~ffap~, ~xref~, and ~project~ libraries. We may reconsider how best
+  to organise such features in the future. Thanks to Noboru Ota
+  (nobiot), who originally contributed those extensions, for
+  suggesting their removal from our code base. We did this by
+  evaluating all use-cases. The discussion with Noboru happened in
+  issue 264: <https://github.com/protesilaos/denote/issues/264>. Also
+  thanks to Jean-Philippe Gagné Guay and Alan Schnmitt for checking
+  the impact of this on how we generate backlinks. The latest
+  iteration of this was done in pull request 294, by Jean-Philippe:
+  <https://github.com/protesilaos/denote/pull/294>.
+
+- While renaming files, signatures no longer lose consecutive spaces.
+  Thanks to Wesley Harvey for the contribution in pull request 207:
+  <https://github.com/protesilaos/denote/pull/207>. The change is
+  within the ~15 line limit and so Wesley does not need to assign
+  copyright to the Free Software Foundation.
+
+- All of the above and lots more are documented at length in the
+  manual. This is a big task in its own right (as are release notes,
+  by the way), though it ensures we keep a high standard for the
+  entire package and can communicate all our knowledge to the user.
+
+** No more SourceHut
+:PROPERTIES:
+:CUSTOM_ID: h:9a0d6afc-95e0-490e-a573-5a50fe7bdf28
+:END:
+
+Development continues on GitHub with GitLab as a mirror. I explained
+my reasons here: <https://protesilaos.com/codelog/2024-01-27-sourcehut-no-more/>.
+
+This is a change that affects all my Emacs packages.
+
+** Forward guidance for Denote version 3.0.0
+:PROPERTIES:
+:CUSTOM_ID: h:61fb340e-5c7c-4a4b-927c-63faf4759a09
+:END:
+
+We will not any new features until mid-April or a bit later if
+necessary. This gives users enough time to report any potential issues
+with version =2.3.0=. If there are any bugs, they will be fixed right
+away and new minor releases will be introduced (though without release
+notes).
+
+Once we are done with this release cycle, we want to prepare for the
+next major version of Denote. The plan is to make the placement of
+file name components entirely customisable, among many other power
+user features. Though the defaults will remain intact.
+
+For the immediate future, please prioritise bug reports/fixes. Then
+see you around for another round of hacking. The Denote code base is a
+pleasure to work with due to how composable everything is. I happy to
+make it even better for developers and users alike.
+
+** Git commits
+:PROPERTIES:
+:CUSTOM_ID: h:a6fd8e16-ded9-49cf-afbb-6e1373c3c43d
+:END:
+
+Just an overview of what we did. Thanks again to everyone involved.
+
+#+begin_src sh
+~/Git/Projects/denote $ git shortlog 2.2.0..2.3.0 --summary --numbered
+   246	Protesilaos Stavrou
+    46	Jean-Philippe Gagné Guay
+     6	Vedang Manerikar
+     3	Joseph Turner
+     2	Alan Schmitt
+     2	Max
+     2	Peter Prevos
+     1	Ashton Wiersdorf
+     1	Glenna D.
+     1	Matteo Cavada
+     1	mattyonweb
+     1	random
+     1	wlharvey4
+#+end_src
+
+** All contributions are valuable
+:PROPERTIES:
+:CUSTOM_ID: h:967372fa-933b-40d2-b1a8-546d1a50d35d
+:END:
+
+I encourage you to provide feedback on any of the functionality of the
+Denote package. You do not need to be a developer or indeed an expert
+in Emacs. When you have an idea in mind on how you use Denote, or you
+think something could be done differently, please speak your mind. I
+do listen to feedback and am interested in further improving this
+package. Everybody is welcome!
+
+* Version 2.2.0 on 2023-12-10
+:PROPERTIES:
+:CUSTOM_ID: h:8efed390-cfa0-420d-b300-0cb76bf2c9f9
+:END:
+
+The present version covers four broad themes:
+
+1. Denote rename commands are more user-friendly and featureful.
+2. An optional sorting facility makes it possible to produce a
+   filtered and sorted Dired buffer with Denote files.
+3. The optional Denote Org dynamic blocks have received a lot of attention.
+4. Bug fixes and internal refinements.
+
+[ Remember that you do not need to be a programmer to contribute to
+  Denote. Report a bug, make a suggestion, or just describe how you
+  want to use this package. Every idea counts and we may implement it
+  if we can. ]
+
+** The rename commands can remove a Denote file name component
+:PROPERTIES:
+:CUSTOM_ID: h:54d803d8-4863-4160-bb2f-3302fb8bff23
+:END:
+
+The commands we provide to rename files using the Denote file-naming
+scheme---~denote-rename-file~, ~denote-dired-rename-files~, and
+~denote-dired-rename-marked-files-with-keywords~---can now remove
+Denote file name components. This is done by providing an empty string
+at the relevant prompt.
+
+For example, to remove the =TITLE= component from a file called
+=20231209T110322==sig--title__keywords.ext= we provide an empty string
+at the title prompt. The end result will look something like this:
+=20231209T110322==sig__keywords.ext=.
+
+All prompts now include a hint that leaving them empty will ignore the
+given field if it does not exist or remove it if it does exist.
+
+Note that you must *check how to input an empty string* with your
+minibuffer user interface of choice. For instance, with the ~vertico~
+package you can do that with the =M-RET= key binding or by selecting
+the prompt line directly (notice the counter showing something like
+=*/5= instead of =1/5=). Please make sure to consult the documentation
+of the package you are using as this behaviour is not controlled by
+Denote. Vertico, and others like it, selects the first candidate if
+you type =RET= without any input, which is not the same as an empty
+string---it is the first candidate.
+
+Also read the Denote manual on the matter of [[https://protesilaos.com/emacs/denote#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]. In short,
+we use this facility to name all our files, regardless of file type,
+in a consistent way that makes them easier to find (I do this with my
+videos, for example, and I do it across my filesystem for all personal
+files).
+
+** The file-to-be-renamed is easier to read in the minibuffer
+:PROPERTIES:
+:CUSTOM_ID: h:69d85d3b-0200-4cc1-baff-9d59aa0ff57b
+:END:
+
+The commands ~denote-rename-file~ and ~denote-dired-rename-files~ 
+show the name of the file they are operating on in the minibuffer
+prompt. This is now produced relative to the current directory,
+meaning that instead of =/some/rather/long/path/to/file-name.txt=
+Denote only displays =file-name.txt=.
+
+Our rename commands never move files to another directory, anyway, so
+we do not need to remind the user of the entire file system path.
+
+To make things easier for users/themes, file names highlighted in
+Denote prompts are fontified with either of following faces,
+depending on the specifics of the case:
+
+- ~denote-faces-prompt-old-name~
+- ~denote-faces-prompt-new-name~
+- ~denote-faces-prompt-current-name~
+
+These faces inherit the attributes of basic faces, so they should look
+decent without further tweaks across all themes.
+
+** Prompts for title, keywords, and signature accept an empty string
+:PROPERTIES:
+:CUSTOM_ID: h:5897bcc1-4637-4268-8518-8404d939b4b9
+:END:
+
+The prompts defined by Denote that apply to file name components all
+accept an empty string. This has the effect of skipping the given
+component. For example, we can create a file without a title and
+keywords, with the following sequence of actions (I assume you are
+using ~vertico~ for the minibuffer user interface):
+
+- Type =M-x denote=.
+- Type =M-RET= at the title prompt to input an empty string.
+- Now type =M-RET= at the keywords prompt for another empty string.
+
+The resulting file name is something like =20231209T110950.org=.
+
+** Dired with sorting and filtering
+:PROPERTIES:
+:CUSTOM_ID: h:05aa437b-2fc8-4e01-ac38-ab77baad83af
+:END:
+
+The new optional =denote-sort.el= library provides facilities to sort
+Denote files by any of their file name components. Users can benefit
+from this facility to produce a filtered and sorted listing of Denote
+files with the command ~denote-sort-dired~.
+
+~denote-sort-dired~ produces a fully fledged Dired buffer. It asks for a
+regular expression that matches file names in the ~denote-directory~.
+It then prompts for a sort key and finally checks with the user
+whether to reverse the order or not.
+
+[ Do not be discouraged by the term "regular expression". Ordinary
+  words work fine. Plus, with Denote's file-naming scheme we have
+  semantics such as =_keyword=, =-title=, ~=signature~, as explained
+  in the manual. This is the whole point of using a thoughtful naming
+  scheme. ]
+
+The resulting Dired listing is flat, meaning that files inside of
+subdirectories are bundled together with those present at the root of
+the ~denote-directory~. In this case, files inside of a subdirectory
+include the directory component as a prefix. So we have something like
+this:
+
+#+begin_example
+test-subdir/20230320T105950--a-new-note__testing.txt
+20231202T095629--rename-works-as-intended__one_test_two.org
+#+end_example
+
+I think this is a killer feature, as the fully fledged Dired buffer
+allows us to perform all supported operations on our Denote
+sorted+filtered files (e.g. change file permissions, move files to
+another directory, or open them in an external application).
+
+I recorded a video to show how this works:
+<https://protesilaos.com/codelog/2023-12-04-emacs-denote-sort-mechanism/>.
+
+[ Remember that we can rename any file using the Denote file-naming
+  scheme, meaning that our files can include stuff like PDFs and
+  videos. Combine this with the concept of "silos", which is covered
+  in the Denote manual, to organise your long-term storage and
+  retrieve it efficiently. ]
+
+** Combine contents of files with an Org dynamic block
+:PROPERTIES:
+:CUSTOM_ID: h:d41009c1-9833-4b28-8240-9666bfd26559
+:END:
+
+The new =denote-files= Org dynamic block produces a continuous stream
+of file contents. It joins together the contents of files inside the
+~denote-directory~ whose name matches the given regular expression.
+Optional parameters control whether to include links to those files,
+omit their front matter, sort by a given file name component, or tweak
+the separator between each file's contents.
+
+I produced a video to demonstrate the functionality:
+<https://protesilaos.com/codelog/2023-11-25-emacs-denote-org-dynamic-blocks/>.
+
+Use the command ~denote-org-dblock-insert-files~ to insert such a
+block directly at point. Read the Denote manual for the
+technicalities: [[https://protesilaos.com/emacs/denote#h:f15fa143-5036-416f-9bff-1bcabbb03456][Org dynamic block to insert file contents]].
+
+[ Videos I do will eventually be out-of-date. The manual is the source
+  of truth. ]
+
+Bear in mind that this feature is not "transclusion". We are simply
+printing a copy of the contents of the files in the current buffer.
+Changes made to this copy are not reflected in the original files.
+
+The =denote-files= Org dynamic block is an excellent way to quickly
+collect your thoughts on a given topic. Although dynamic blocks are a
+feature of Org, the contents of the files do not need to be in Org
+syntax (I write most of my notes in plain text (=.txt=)).
+
+Thanks to Claudiu Tănăselia for proposing this idea and discussing it
+with me. This was done via a private channel and the information is
+shared with permission.
+
+** Sort parameters are used in all Denote Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:7b51fe38-302e-488d-9816-7015a8071ddb
+:END:
+
+All Denote Org dynamic blocks make use of =denote-sort.el= (described
+further above). It powers the =:sort-by-component= and =:reverse-sort=
+parameters.
+
+Thanks to Glenna D. for suggesting this feature and discussing it with
+me. This was done via a private channel and the information is shared
+with permission. It is what inspired me to start work on
+=denote-sort.el=, which I then extended to cover Dired, as noted
+above.
+
+** The =:missing-only= parameter is removed from Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:2bd26aef-70ad-4d83-a4ab-c75a893a733a
+:END:
+
+I am removing it because the underlying functionality of
+~denote-add-missing-links~ was not always reliable.
+
+** Files with signature are linked appropriately in Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:144436eb-e674-4052-ac0a-d582b6aa2f53
+:END:
+
+In general, we provide the command ~denote-link-with-signature~ to let
+the user pick a file that has a signature and link to it. The
+description of such a link contains the signature text as well as the
+file title. The ~denote-link-with-signature~ is distinct from the
+standard ~denote-link~, as it allows the user to express intent about
+the inclusion of the signature.
+
+In Org dynamic blocks for links/backlinks, we make this happen
+automatically since there can be no manual intervention to express
+intent on a link-by-link basis.
+
+** Fontification in Dired can now extend to subdirectories
+:PROPERTIES:
+:CUSTOM_ID: h:46e08576-4c17-4b1e-a268-e0223250e7c1
+:END:
+
+The user option ~denote-dired-directories~ activates the
+~denote-dired-mode~ in the specified list of directories when the user
+sets this in their init file:
+
+#+begin_src emacs-lisp
+(add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)
+#+end_src
+
+The new user option ~denote-dired-directories-include-subdirectories~
+extends the reach of this feature to all subdirectories thereof.
+
+Thanks to Henrik Hörmann for discussing this with me and contributing
+a patch. This was originally done in pull request 191 on the GitHub
+mirror: <https://github.com/protesilaos/denote/pull/191>. Subsequent
+refinements by me.
+
+** Signatures are sluggified as intended
+:PROPERTIES:
+:CUSTOM_ID: h:73e1efaa-2c22-48ee-be46-072b55177c99
+:END:
+
+The file name signature component is now sluggified properly. This
+means that multiple words are separated by the equals sign, in
+accordance with the Denote file-naming scheme where a word separator
+is the same as the given field separator (this is the low-tech feature
+that makes Denote files so easy to retrieve without fancy extras).
+
+Vedang Manerikar fixed two relevant bugs in the "rename" commands,
+while I rewrote internal functions and tests in the interest of consistency. Vedang's patches: <https://lists.sr.ht/~protesilaos/denote/patches/46790>.
+
+[ The "signature" is a free form component of the file name. Users can
+  add anything they want there, such as to use it as a "category" that
+  is different from "tags/keywords", or to introduce sequences in
+  their notes, or to just have an extra marker for files they need to
+  spot quickly. ]
+
+** For developers
+:PROPERTIES:
+:CUSTOM_ID: h:79f2fd7e-d5a7-4c78-bce7-f8d21e86e32c
+:END:
+
+There is a section in the manual titled "For developers or advanced
+users". There we document functions or variables that are
+public-facing, meaning that we test and document their behaviour and
+encourage others to use them for code they write on top of Denote.
+Refer to this section if you are looking to extend Denote. Though you
+can also just check the source code, which is designed to be readable
+and hackable.
+
+- The ~denote-directory-files~ function gains new functionality that
+  subsumes that of the now-deprecated functions
+  ~denote-directory-files-matching-regexp~, ~denote-all-files~,
+  ~denote-directory-text-only-files~. Thanks to Jean-Philippe Gagné
+  Guay for the contribution, which was done in pull request 195 on the
+  GitHub mirror: <https://github.com/protesilaos/denote/pull/195>.
+
+- The font-lock keywords we define are consolidated into a single
+  variable: ~denote-faces-file-name-keywords~ instead of being split
+  into two variables. This means that we cover all our fontification
+  needs in the backlinks buffer as well as the ~denote-dired-mode~
+  with this one point of entry. It also works for ~denote-sort-dired~,
+  which can include files with their subdirectory component in the
+  same flat listing.
+
+- Use the function ~denote-retrieve-filename-keywords~ to extract
+  keywords from the file name alone, without going into the file
+  contents.
+
+- The ~denote-retrieve-filename-title~ function now returns an empty
+  string if no title is present. Its behaviour is thus consistent with
+  ~denote-retrieve-filename-keywords~ and ~denote-retrieve-filename-signature~.
+  
+- The ~denote-retrieve-filename-title~ will now use the
+  ~file-name-base~ function as a fallback subject to a non-nil
+  optional argument. This case come into effect when the file does not
+  have a title component. The new optional argument allows the caller
+  to handle such cases as they see fit.
+
+- The ~denote-signature-prompt~ and ~denote-title-prompt~ functions
+  accept an optional =DEFAULT-SIGNATURE= or =DEFAULT-TITLE= argument.
+  Internally, this is used as the =INITIAL-INPUT= of ~completing-read~
+  instead of the =DEF= argument. This matters because we want the
+  prompt to return an empty string if there is no input, whereas the
+  presence of =DEF= means that =DEF= is returned when the prompt is
+  empty.
+
+- All our functions that interactively match file names with a regular
+  expression now use the ~denote-files-matching-regexp-prompt~
+  function. When called from Lisp, it takes a =REGEXP= argument as
+  well as an optional =PROMPT-TEXT=.
+
+For the purposes of this release cycle, I am not documenting the
+points of entry provided by =denote-sort.el=. It is a new feature that
+I may eventually incorporate in =denote.el=. If you are interested in
+the functionality (e.g. to have more elaborate sorting algorithms),
+please take a look at the source code and then let us discuss the
+implementation details.
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:ce5c7865-9ec1-49ba-9388-5a251ab56735
+:END:
+
+- Rewrote the manual on the topic of Org dynamic blocks. Same idea for
+  practically the entirety of =denote-org-dblock.el=.
+
+- Marked the interactive specification of a few commands with the
+  major mode they belong to. This means that =M-X= (note the capital
+  X), which calls ~execute-extended-command-for-buffer~ by default,
+  will only show those commands in the relevant context.
+
+- Made internal refinements and simplified the implementation of a few
+  functions. This is important work to keep the code base clean and
+  easy to read/maintain. Thanks to Jean-Philippe Gagné Guay for the
+  contribution. It was done in pull request 193 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/193>.
+
+- Improved the doc string of the ~denote-format-file-name~ function.
+  Also introduced a unit test for it to be sure it does what we expect
+  (I eventually want to have tests for everything we do, but this is a
+  long-term project).
+
+** Git commits
+:PROPERTIES:
+:CUSTOM_ID: h:6830d3f3-130c-4346-b3ca-a3d4b0e9f974
+:END:
+
+Just an overview of what we did. Thanks again to everyone involved.
+
+#+begin_src sh
+~/Git/Projects/denote $ git shortlog 2.1.0..2.2.0 --summary --numbered
+   125	Protesilaos Stavrou
+    17	Jean-Philippe Gagné Guay
+     2	Vedang Manerikar
+     1	Henrik Hörmann
+#+end_src
+
+** Policy for the next development cycle
+:PROPERTIES:
+:CUSTOM_ID: h:cb0cae4f-c9a1-40b3-98ae-781a57270d4e
+:END:
+
+I will give a ~1 week pause on Denote development before making any
+feature changes. This is to ensure that we catch possible bugs and
+push fixes right away. If there are other changes in place, it is not
+possible to make point updates of this sort, as we must first wait for
+the new features to be tested in real-world scenaria.
+
+* Version 2.1.0 on 2023-11-12
+:PROPERTIES:
+:CUSTOM_ID: h:167beb8f-14be-40de-a1f2-d13910924c00
+:END:
+
+The general theme of this release is improvements to the quality of
+life with Denote. While these release notes and the overall
+documentation are comprehensive, make no mistake: Denote can be used
+with =M-x denote=, =M-x denote-link=, =M-x denote-backlinks=, =M-x
+denote-rename-file=. These have been rock solid from the beginning.
+Everything else is for more specialised workflows.
+
+I hope to produce a companion video to this changelog in the coming
+days. Though I am still reeling from the injury to my left hand (I
+wrote all this to not delay the package any longer). Please check back
+in my website's coding blog section to find the follow-up video:
+<https://protesilaos.com/codelog>.
+
+[ Remember to consult the manual whenever you have a question about
+  Denote. It is comprehensive and, in my opinion, a paradigm of how
+  free software should be done for the benefit of users. I document
+  everything in detail and am eager to continue this way. If something
+  is unclear, contact me in person, use the mailing list, or open an
+  issue on the GitHub/GitLab mirror. I do not check other fora or
+  media and will thus not help you there. If you are writing custom
+  code, remember to read the doc strings. I write them for you too. ]
+
+** Deprecated the ~denote-allow-multi-word-keywords~
+:PROPERTIES:
+:CUSTOM_ID: h:a086d1d2-adb3-4151-a7af-813d79b4b3dc
+:END:
+
+This user option enabled the use of keywords that consisted of
+multiple words. Those would be separated by hyphens. Such keywords do
+not work as Org =#+filetags= and also mess up with the neat search
+semantics of Denote's file-naming scheme where a hyphen prefix
+anchors the query to the =TITLE= component of the name.
+
+Users who absolutely need multi-word keywords are encouraged to use
+the new ~denote-file-name-letter-casing~ option. More below.
+
+** Control the letter casing of file name components
+:PROPERTIES:
+:CUSTOM_ID: h:29319b8a-698b-4a1c-bab4-7b106a623de8
+:END:
+
+By default, Denote downcases all components of the file name. The user
+option ~denote-file-name-letter-casing~ provides granular control over
+this behaviour.
+
+The value it accepts is an alist where each element is a cons cell of
+the form =(COMPONENT . METHOD)=. The manual, or the variable's doc
+string, cover the details. The gist is that we can now instruct Denote
+to accept input verbatim, such as because we want to apply a
+=camelCase= convention or variants thereof.
+
+Here is an example, where we downcase the title, but preserve the
+letter casing of the signature and keyword components with this:
+
+#+begin_src emacs-lisp
+(setq denote-file-name-letter-casing
+      '((title . downcase)
+        (signature . verbatim)
+        (keywords . verbatim)
+        (t . downcase)))
+#+end_src
+
+Users of the now-deprecated ~denote-allow-multi-word-keywords~ are
+encouraged to implement a letter casing convention with the help of
+this new user option.
+
+Relevant sections in the manual:
+
+- The file-naming scheme:
+  <https://protesilaos.com/emacs/denote#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d>.
+- Contol the letter casing of file names:
+  <https://protesilaos.com/emacs/denote#h:6ae1ab8c-5e36-4216-8e93-f37f4447582c>
+
+** The ~denote-dired-mode~ should now work while toggling ~wdired~
+:PROPERTIES:
+:CUSTOM_ID: h:18a3b515-9306-4911-ba2d-73e36efbdd32
+:END:
+
+The writable version of Dired would break the colouration applied by
+~denote-dired-mode~. I have arranged for this to not happen anymore,
+although it means that I had to add an advice to relevant wdired
+symbols because no proper hook is on offer.
+
+** The "do or create" commands are more intuitive to use
+:PROPERTIES:
+:CUSTOM_ID: h:5bcdc4b8-ecba-44d7-accc-0b26657aa29b
+:END:
+
+Denote provides several commands with a "do or create" logic. For
+example, the ~denote-open-or-create~ prompts for a file to visit: if
+something matches the user's input, it is visited in a buffer,
+otherwise a new note is created with the given input. Same for
+~denote-link-or-create~, mutatis mutandis.
+
+Before, the "... or create" step did not make it obvious how the
+previous search terms could be reused. Whereas now those are set as
+the default minibuffer value at the title prompt, meaning that typing
+=RET= at the empty prompt will use that value, while =M-n=
+(~next-history-element~ with default settings) will put the text into
+the prompt for further editing.
+
+I will answer this because I get asked about it: we still refrain from
+creating the new note outright because the search terms are not
+necessarily suitable for a new title. Remember that Denote's file name
+is optimised for searching: =-word= is specific to the title, =_word=
+to the keywords, and ==word= to the signature. Combine this with the
+~orderless~ package and you frequently type something like =_jou -he=
+to match a file with the =journal= keyword and the word =hesitation=
+in its title.
+
+*IMPORTANT NOTE:* some minibuffer completion User Interfaces preselect
+the first completion candidate, which is not always the same as the
+default value. Check with your UI of choice how to pass a default
+value and/or provide an empty input. For example, with the ~vertico~
+package one can move up from the first candidate to select the prompt
+itself (the counter switches from =1/N= to =*/N=).
+
+Relevant sections in the manual:
+
+- Open an existing note or create it if missing:
+  <https://protesilaos.com/emacs/denote#h:ad91ca39-cf10-4e16-b224-fdf78f093883>.
+- Link to a note or create it if missing:
+  <https://protesilaos.com/emacs/denote#h:9e41e7df-2aac-4835-94c5-659b6111e6de>.
+
+*** New "... or create with command" features for more flexibility
+:PROPERTIES:
+:CUSTOM_ID: h:6f475151-9d64-4dfb-8c59-694c93d56ce8
+:END:
+
+As part of the wider "do or create" feature set, Denote provides the
+option to run a specific note-creating command instead of just using
+the standard ~denote~ one. For example, it is possible to call the
+~denote-subdirectory~ command to pick a subdirectory of the
+~denote-directory~ for the new note. Commands providing this facility
+are ~denote-open-or-create-with-command~ and ~denote-link-after-creating-with-command~.
+
+Thanks to Vedang Manerikar for fixing a broken ~if~ clause during
+development: <https://lists.sr.ht/~protesilaos/denote/patches/46087>.
+
+** The title and signature prompts use minibuffer completion
+:PROPERTIES:
+:CUSTOM_ID: h:429847c8-ebf4-4b23-a597-5276309ef61a
+:END:
+
+All Denote minibuffer prompts come with their own history. This means
+that =M-p= (~previous-history-element~) and =M-n=
+(~next-history-element~) always return relevant input.
+
+The title and signature prompts now reuse their input history to
+provide completion. This means that the user can quickly access
+previous inputs, either to pass them directly or edit them further
+before inputting them.
+
+[ Use the built-in ~savehist-mode~ to persist histories across sessions. ]
+
+Remember to check with your minibuffer UI on how to input empty
+values at the prompt, should you ever need to do so.
+
+For posterity, I first implemented this in commit =0d855bb=. However,
+it did not work with the default minibuffer because the =SPC= key
+performs completion (popping up the Completions buffer). So users
+could not easily input an arbitrary string for the title/signature. I
+thus reverted that commit in =9f692cb=.
+
+[ The bug was reported by Suhail Singh on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C652d82c0.c80a0220.e6282.dc47%40mx.google.com%3E#%3C65392fa6.050a0220.da61c.0ac8@mx.google.com%3E>. ]
+
+Stefan Monnier suggested the use of the ~minibuffer-with-setup-hook~,
+which lets us disable =SPC= completion for the purposes of these
+functions. This is most welcome as the functionality is nice to have.
+Stefan's feedback was provided on the emacs-devel mailing list:
+<https://lists.gnu.org/archive/html/emacs-devel/2023-10/msg00631.html>.
+
+** Create a note with the region's contents
+:PROPERTIES:
+:CUSTOM_ID: h:ae798d1f-6fa2-4d99-91c9-0d5eb18b1bb0
+:END:
+
+The command ~denote-region~ takes the contents of the active region
+and then prompts for a title and keywords.  Once a new note is
+created, it inserts the contents of the region therein.  This is
+useful to quickly elaborate on some snippet of text or capture it for
+future reference.
+
+It also provides the ~denote-region-after-new-note-functions~ abnormal
+hook. Read the manual for more:
+<https://protesilaos.com/emacs/denote#h:2f8090f1-50af-4965-9771-d5a91a0a87bd>.
+
+** Comprehensive refinements to the ~denote-rename-buffer-mode~
+:PROPERTIES:
+:CUSTOM_ID: h:91b3ba9f-8b10-4f1c-a08b-70f5e7140923
+:END:
+
+This is an opt-in feature that automatically renames the buffer of
+newly visited Denote files according to the user's preferences. Not to
+be confused with renaming files: buffers are internal to Emacs. Enable
+it at startup by adding this to your configuration file:
+
+#+begin_src emacs-lisp
+(denote-rename-buffer-mode 1)
+#+end_src
+
+Relevant entries in the manual:
+
+- Automatically rename Denote buffers:
+  <https://protesilaos.com/emacs/denote#h:3ca4db16-8f26-4d7d-b748-bac48ae32d69>.
+- The ~denote-rename-buffer-format~ option:
+  <https://protesilaos.com/emacs/denote#h:35507c18-35b1-41b9-9d80-52f54fcef3cb>.
+
+*** The ~denote-rename-buffer-format~ option
+:PROPERTIES:
+:CUSTOM_ID: h:beeafe57-f110-4c11-87e7-10f682ca2386
+:END:
+
+The user option ~denote-rename-buffer-format~ controls how the
+function ~denote-rename-buffer~ chooses the name of the
+buffer-to-be-renamed. This function is the one used by the
+~denote-rename-buffer-mode~.
+
+Users may want, for example, to include some text that makes Denote
+buffers stand out, such as a =[D]= prefix. Examples:
+
+#+begin_src emacs-lisp
+;; Use the title (default)
+(setq denote-rename-buffer-format "%t")
+
+;; Use the title and keywords with some emoji in between.
+(setq denote-rename-buffer-format "%t 🤨 %k")
+
+;; Use the title with a literal "[D]" before it
+(setq denote-rename-buffer-format "[D] %t")
+#+end_src
+
+Users who need yet more flexibility are best served by writing their
+own function and assigning it to the ~denote-rename-buffer-function~
+(in such a case, please contact me as I am curious to know what the
+underlying need is).
+
+The manual or doc string of ~denote-rename-buffer-format~ cover the
+technicalities of the available format specifiers.
+
+Thanks to Jean-Philippe Gagné Guay for intermediately refining parts
+of the code. This was done in pull request 177 on the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/177>.
+
+Thanks to Vedang Manerikar for ensuring that the string of the buffer
+is trimmed so that it never starts with an empty space (those buffers
+count as "internal" to Emacs and are not shown to the user):
+<https://lists.sr.ht/~protesilaos/denote/patches/46243>.
+
+*** The ~denote-rename-buffer-mode~ also works with unsaved buffers
+:PROPERTIES:
+:CUSTOM_ID: h:e65bb546-af22-45fb-a918-d0e621b0e415
+:END:
+
+Internal refinements to a Denote Lisp macro make this minor mode also
+work with new and unsaved Denote buffers. Whereas before only the
+buffers of existing files would be renamed.
+
+** Denote's renaming facilities are better than ever
+:PROPERTIES:
+:CUSTOM_ID: h:703b9021-f917-4b3f-9406-14992b2a4fe8
+:END:
+
+Denote's value proposition is its efficient file-naming scheme that
+makes it easier to retrieve files even with rudimentary search tools.
+We provide several commands to rename existing files according to this
+scheme. The underlying file type does not matter (e.g. I use Denote to
+name my video files).
+
+Relevant sections in the manual:
+
+- Renaming files:
+  <https://protesilaos.com/emacs/denote#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca>.
+- Front matter:
+  <https://protesilaos.com/emacs/denote#h:13218826-56a5-482a-9b91-5b6de4f14261>.
+
+*** Rename like an expert with ~denote-rename-no-confirm~
+:PROPERTIES:
+:CUSTOM_ID: h:8798dd8c-819d-4fda-9865-77d9734da28c
+:END:
+
+By default, the ~denote-rename-file~ command asks for a final
+confirmation before carrying out its function. The new user option
+~denote-rename-no-confirm~ can be bound to a non-nil value to skip
+that step.
+
+This only applies to ~denote-rename-file~. Other commands that rename
+files in bulk never prompt for such confirmation (it would make them
+cumbersome to use, plus it is assumed that the user who performs a
+batch operation understands the implications).
+
+*** The ~denote-rename-file~ command prompts for a signature
+:PROPERTIES:
+:CUSTOM_ID: h:e4e7e3d8-40e3-4f58-a19f-df34ccbfdbbd
+:END:
+
+This command used to only ask for a title and keywords. Now it allows
+to use a signature as well. An empty input means that the signature is
+ignored. AGAIN, please check with your minibuffer completion UI on how
+to input an empty value, otherwise you will not get what you expect.
+
+*** Rename mutliple files sequentially with ~denote-dired-rename-files~
+:PROPERTIES:
+:CUSTOM_ID: h:dcb623aa-fc4d-4d84-80e4-a540b6dbb144
+:END:
+
+This provides the same interface as ~denote-rename-file~, only it
+works over a list of marked Dired files.
+
+Internally, the prompts for title, keywords, and signature are
+improved to display the underlying file that is affected by the
+current operation. As the user renames files, the prompts reflect
+which one is current.
+
+*** The name of ~denote-dired-rename-marked-files~ has changed
+:PROPERTIES:
+:CUSTOM_ID: h:f9a16fc1-840d-400f-a5ae-a7791fac441f
+:END:
+
+It is now called ~denote-dired-rename-marked-files-with-keywords~ to
+better communicate what it does. In short, this is a quick way to add
+the given keywords to a list of files, converting them to the Denote
+file-naming scheme in case they are not already using it. For the full
+interactive power, use the aforementioned ~denote-dired-rename-files~.
+
+*** The ~denote-rename-file-using-front-matter~ can be used without saving its buffer
+:PROPERTIES:
+:CUSTOM_ID: h:bfc194c2-5980-482a-aa1c-feb4ced992d1
+:END:
+
+This is now possible because of changes to underlying functions (a
+Denote Lisp macro---not to bother you with technicalities).
+
+Same principle for ~denote-rename-file-using-front-matter~.
+
+*** The name of ~denote-change-file-type~ has changed
+:PROPERTIES:
+:CUSTOM_ID: h:3bf4b6c4-8399-4d5d-8df1-6495f5bfc579
+:END:
+
+It is now called ~denote-change-file-type-and-front-matter~ to avoid
+confusion as to whether Denote converts files from one format to
+another (there are specialised tools for that).
+
+*** Renaming a file returns the new file path for programmatic use
+:PROPERTIES:
+:CUSTOM_ID: h:1d7bffd1-e422-420d-b453-9a36dd8508f7
+:END:
+
+Thanks to mentalisttraceur for requesting this feature in issue 183 on
+the GitHub mirror: <https://github.com/protesilaos/denote/issues/183>.
+
+** Link to a file with a signature
+:PROPERTIES:
+:CUSTOM_ID: h:b154ef64-c3b4-4e15-b533-c59d5b2ebf6b
+:END:
+
+The ~denote-link-with-signature~ command prompts for a file that has a
+=SIGNATURE= component and links to it. The link's description includes
+the text of the signature as well as the title.
+
+Thanks to Mark Olson for mentioning this idea. It was done in issue
+167 on the GitHub mirror: <https://github.com/protesilaos/denote/issues/167>.
+
+I implemented it live, while also refactoring relevant parts of the
+code to be more abstract/reusable:
+<https://protesilaos.com/codelog/2023-09-25-emacs-live-mostly-denote/>.
+
+Thanks to Alan Schmitt for spotting and fixing a regression caused by
+the above:
+<https://lists.sr.ht/~protesilaos/denote/%3Cm2cyy5rt68.fsf%40mac-03220211.irisa.fr%3E>.
+
+** Renaming GPG or Age encrypted file works as expected
+:PROPERTIES:
+:CUSTOM_ID: h:9ceaf432-797c-46e5-aaf8-d7180ad66689
+:END:
+
+Emacs can seamlessly visit a =.gpg= or =.age= file. Denote has nothing
+to do with encryption, though it takes care to recognise the
+underlying file type and to perform its work accordingly. However,
+prior versions of Denote contained a bug in how file extensions were
+handled: it would keep the encryption extension but remove the file
+type extension before it (so ".org.gpg" would wrongly become ".gpg").
+
+Thanks to Jens Östlund for reporting a bug with ~denote-keywords-add~
+on an encrypted file, which prompted me to investigate this further
+and fix the issue holistically. This was done in issue 172 on the
+GitHub mirror: <https://github.com/protesilaos/denote/issues/172>.
+
+Interested parties are advised to check the two new public functions,
+~denote-get-file-extension~ and ~denote-get-file-extension-sans-encryption~,
+for the implementation details. In short, we had a problem with all
+operations that needed to retrieve the file extension when that
+included an encryption component.
+
+** The optional ~denote-journal-extras~
+:PROPERTIES:
+:CUSTOM_ID: h:54723661-31f8-4cab-9be5-4cab19e44dc7
+:END:
+
+The manual of Denote has long provided code samples to achieve
+particularised results. Among those were snippets to streamline the
+use of Denote for journaling.
+
+To make things even easier for users, we now have the
+=denote-journal-extras.el=. It consolidates the rich corpus of
+documented snippets into an easy-to-use and formally maintained
+package. Thanks to Vedang Manerikar for providing the impetus for this
+process. This was done on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/patches/43255#%3C20230803170935.60833-2-ved.manerikar@gmail.com%3E>.
+
+The new file is optional. It can be loaded thus:
+
+#+begin_src emacs-lisp
+(require 'denote-journal-extras)
+#+end_src
+
+The main idea is to quickly create journal entries. Check the manual
+for the details, including the commands to use and the variables to
+configure: <https://protesilaos.com/emacs/denote#h:4a6d92dd-19eb-4fcc-a7b5-05ce04da3a92>.
+
+Thanks to Kostas Andreadis for working on a comment I had included in
+a working state of the code about the inclusion of templates. Kostas
+made it possible to use the Denote template prompt (per the
+~denote-templates~ user option) as part of the creation of a new
+journal entry. This was done in pull request 173 on the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/173>. The change is less
+than 15 lines and thus Kostas does not need to assign copyright to the
+Free Software Foundation.
+
+Also thanks to TJ Stankus for reporting a case where
+~denote-journal-extras-title-format~ did not accept a ~nil~ value (as
+it should). This was done in issue 176 on the GitHub mirror:
+<https://github.com/protesilaos/denote/issues/176>.
+
+** The optional ~denote-silo-extras~
+:PROPERTIES:
+:CUSTOM_ID: h:618495d2-0c5b-48b4-af88-56f3d969697c
+:END:
+
+This is the same idea as with the =denote-journal-extras.el=: we had
+the code in the manual and are now formally distributing it. Thanks
+again to Vedang Manerikar for initiating this process. It was done on
+the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/patches/43255>.
+
+Use this optional feature with:
+
+#+begin_src emacs-lisp
+(require 'denote-silo-extras)
+#+end_src
+
+Consult the manual for the details:
+<https://protesilaos.com/emacs/denote#h:e43baf95-f201-4fec-8620-c0eb5eaa1c85>.
+
+** The infrastructure for unique identifiers is more robust
+:PROPERTIES:
+:CUSTOM_ID: h:1d538d7f-52e6-4653-b057-c62606752934
+:END:
+
+For Denote version =2.0.0= I introduced a general scheme intended to
+avoid scenaria where duplicate identifiers could be created (thus
+breaking a premise of Denote). Jean-Philippe Gagné Guay iterated over
+the code to make it more robust and to fix some of the cases I had not
+accounted for. This was done in pull request 159 on the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/159>. Same idea in pull
+request 187: <https://github.com/protesilaos/denote/pull/187>.
+
+** For developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:9031dc82-ab75-438c-a2c8-a1250ae48671
+:END:
+
+Denote has a clean code base with small and composable functions. This
+encourages hackability. Each definition in the source is documented,
+while the manual provides an overview of every public symbol.
+
+- Added :: ~denote-get-file-extension~,
+  ~denote-get-file-extension-sans-encryption~,
+  ~denote-keywords-combine~,
+  ~denote-retrieve-keywords-value-as-string~,
+  ~denote-title-prompt-current-default~, ~denote-command-prompt~.
+
+- Refactored :: ~denote-all-files~, ~denote-signature-prompt~,
+  ~denote-file-prompt~, ~denote-title-prompt~,
+  ~denote-rewrite-front-matter~.
+
+Please read their documentation strings for the details. Or check the
+manual: <https://protesilaos.com/emacs/denote#h:c916d8c5-540a-409f-b780-6ccbd90e088e>.
+
+** Check out the ~denote-explore~ package by Peter Prevos
+:PROPERTIES:
+:CUSTOM_ID: h:759d0276-17e8-4461-9ee4-b4d07840dd7a
+:END:
+
+Peter posted this on the mailing list and I asked if it was okay to
+mention it in the release notes of Denote. If you have a relevant
+announcement to make, consider sending it to our mailing list.
+
+#+begin_quote
+Hi folks,
+
+I have just updated the denote-explore package:
+https://github.com/pprevos/denote-explore
+
+It does three things:
+
+1. Summary statistics: Count and visualise keywords and note types
+2. Random walks: Generate new ideas using serendipity
+3. Network visualisation: Visualise your Denote network of links
+
+It contains a rudimentary network visualisation function, relying
+on the R language. I will need some D3.js expertise to improve the
+visualisation.
+
+There should be a way to generate the basic network structure just
+using Elisp and feeding a JSON to D3.js.
+
+Regards
+
+P:)
+#+end_quote
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:01dc6bb0-53ac-43e1-b12e-484c99a6c2a7
+:END:
+
+- During this release cycle, I made lots of changes that in one way or
+  another related to the ~denote-file-prompt~. It was relying on a
+  =project.el= mechanism that did not allow us to do everything we
+  needed. I have thus arranged for it to use the standard
+  ~completing-read~ mechanism. There are subtle differences in
+  behaviour, though the core idea is the same. This change fixes a few
+  not-so-obvious bugs. Interested parties are advised to refer to the
+  message in commit =50d1bbdf1e8ffe0f449f2f5da02f9b70322fff7d=.
+
+- All commands that use the ~denote~ function internally (i.e.
+  anything that creates a new note) call the
+  ~denote-after-new-note-hook~ as part of their work. This hook is
+  mostly intended for advanced users who want to do something after a
+  new note is produced.
+
+- The ~menu-bar-mode~ submenu of Denote is now positioned where it
+  should be after the "Tools". Thanks to Noboru Ota for the patch:
+  <https://lists.sr.ht/~protesilaos/denote/patches/44738>.
+
+- The ~menu-bar-mode~ entry of Denote includes the new commands. This
+  is a nice way to discover more of what Denote can do.
+
+- The commands ~denote-backlinks-prev~ and ~denote-backlinks-next~ are
+  only meant to be used inside the Denote backlinks buffer. As such,
+  they now produce an error when called elsewhere (I wish I could hide
+  them from =M-x= altogether).
+
+- The ~denote-extract-keywords-from-front-matter~ always returns a
+  list, thus avoiding an erroneous case. Thanks to Vedang Manerikar
+  for fixing the bug: <https://lists.sr.ht/~protesilaos/denote/patches/46420>.
+
+- The =T= in the Denote identifier component now has its own face:
+  ~denote-faces-time-delimiter~. This is used by the backlinks buffer
+  and the ~denote-dired-mode~. The idea is to introduce a subtle
+  distinction between the date and time constituents of the
+  identifier. Those who want the =T= to be the same colour as the rest
+  of the identifier, can make the ~denote-faces-time-delimiter~
+  inherit the ~denote-faces-date~. For example:
+
+  #+begin_src emacs-lisp
+  (set-face-attribute 'denote-faces-time-delimiter nil :inherit 'denote-faces-date)
+  #+end_src
+
+  Thanks to Jean-Charles Bagneris for sending this patch:
+  <https://lists.sr.ht/~protesilaos/denote/patches/43072>.
+
+- Fixed a ~nil~ file expansion in the function
+  ~denote--extract-title-from-file-history~. Thanks to ezchi for
+  bringing this matter to my attention. It was done in issue 166 on
+  the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/166>.
+
+- A link can be created from inside an ~org-capture~ buffer. This
+  means that we can call ~denote-link~ (and related) while capturing a
+  new note with ~org-capture~. Thanks to Peter Smith for reporting the
+  bug in issue 186 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/186>.
+
+- We stopped using ~vc-rename-file~ to rename files. The reason is
+  that it requires the buffer to be saved, but we do not want that
+  after modifying the front matter because we want to give the user a
+  chance to confirm what happened. Thanks to Frédéric Willem for
+  reporting the problem in issue 185 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/185>.
+
+- Thanks to Ivan Sokolov for removing a double negative logic in a
+  snippet. This was done in pull request 162 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/162>.
+
+** Git commits
+:PROPERTIES:
+:CUSTOM_ID: h:d8f30943-70dd-45fe-8cf1-4c3918152aeb
+:END:
+
+Just an overview of what we did. Every contribution matters.
+
+#+begin_src
+~/Git/Projects/denote $ git shortlog 2.0.0..2.1.0 --summary --numbered
+   153	Protesilaos Stavrou
+    15	Jean-Philippe Gagné Guay
+     5	Vedang Manerikar
+     1	Alan Schmitt
+     1	Ivan Sokolov
+     1	Jean-Charles Bagneris
+     1	Kostas Andreadis
+     1	Noboru Ota
+     1	Peter Prevos
+#+end_src
+
+* Version 2.0.0 on 2023-07-21
+:PROPERTIES:
+:CUSTOM_ID: h:3f17bf03-4c47-4410-abf8-1db4a0ac7775
+:END:
+
+This is the second major version of Denote, close to one year after
+its initial release.  The video demo I did back then remains relevant,
+even though lots of details have changed.
+
+** Notes have a new optional SIGNATURE field
+:PROPERTIES:
+:CUSTOM_ID: h:a3a9e14d-4132-47c0-a23c-cb008a141668
+:END:
+
+It is now possible to create notes that include a =SIGNATURE= field in
+their file name.  Either use the convenience command ~denote-signature~
+or configure the user option ~denote-prompts~ to affect what the ~denote~
+command should prompt for.
+
+Signatures are arbitrary strings of characters that enable the user to
+further qualify their documents.  One possible workflow is to write
+relational notes, such that =1a1= is the first extension of another
+note with a =1a= signature.
+
+The design of the =SIGNATURE= field is consistent with the Denote
+file-naming scheme.  The field separator is the double equals sign
+(~==~), while words that comprise the signature are joined together by
+a single equals sign.  As such, the user can prefix a search with an
+equals sign to match words in the =SIGNATURE=, just as they would use
+dashes for the =TITLE= and underscores for the =KEYWORDS=.
+
+[ Read the manual for the technicalities of the Denote file-naming
+  scheme.  This is not limited to "notes": any file can be named
+  accordingly (I do it with my videos, for example). ]
+
+Signatures are not included in a file's front matter.  This is a
+strategic decision to preserve backward compatibility, while not
+introducing a feature that has not enjoyed widespread usage.  I want
+to make signatures behave the same as the rest of the file name
+fields, though I am interested to learn how users employ them in their
+workflow.
+
+The signature extension was discussed at length on the GitHub mirror
+in issue 115: <https://github.com/protesilaos/denote/issues/115>.
+Thanks to Stefan Thesing, Mirko Hernandez, Noboru Ota (nobiot),
+Xiaoxing Hu, nbehrnd, Elias Storms, and 101scholar for helping me
+reason about this feature, understand its scope, and prototype its
+implementation.
+
+Also thanks to Alfredo Borrás and Jeremy Friesen for discussing with
+me the field delimiter of signatures on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C2A597B4E-5F18-4D97-9457-B3C859DAA020%40zoho.eu%3E>.
+Thanks to Kai von Fintel for doing the same on the GitHub mirror in
+issue 147: <https://github.com/protesilaos/denote/issues/147>.
+
+Read the original announcement:
+<https://protesilaos.com/codelog/2023-03-20-emacs-denote-signature-feature/>.
+
+As part of the development, I fixed a case where
+~denote-rename-file-using-front-matter~ would fail if it could not
+find a signature
+
+The idea is that we want the command to behave the way it always did
+when the file has no signature and to preserve the signature when it
+is present.
+
+Thanks to relict for reporting the issue on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C87zg86lru9.fsf%40kotlak.com%3E>.
+
+** The rename commands avoid creating duplicate identifiers
+:PROPERTIES:
+:CUSTOM_ID: h:d24645a3-ad02-450c-b3d7-af7802aa0b26
+:END:
+
+Denote provides commands to rename an existing file to one that
+follows the Denote file-naming scheme (videos, PDFs, other text
+documents, ...).  Check, for example, the ~denote-rename-file~ and
+~denote-dired-rename-marked-files~.  The idea is to make everything
+easier to search.
+
+In prior versions, these commands could produce duplicate identifiers
+if the modification date of the underlying files was the same.  Such a
+scenario occurs when the files are modified programmatically, as with
+the =touch= command or the various =git= operations.
+
+Denote will now take care to increment the identifier until it becomes
+unique within the current scope.
+
+Thanks to Felipe Balbi for reporting this bug in issue 105 on the
+GitHub mirror: <https://github.com/protesilaos/denote/issues/105>.
+
+Thanks to Vedang Manerikar and Jean-Charles Bagneris for commenting on
+this feature on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C87v8emeus0.fsf%40protesilaos.com%3E>.
+
+Thanks to Ashton Wiersdorf for noticing a mistake I made that caused a
+regression in ~denote-rename-file~:
+<https://lists.sr.ht/~protesilaos/denote/%3Cm2lefbbzl1.fsf%40wiersdorfmail.net%3E>.
+
+*** Optional arguments affect ~denote-dired-rename-marked-files~
+:PROPERTIES:
+:CUSTOM_ID: h:6ea998be-83dd-4c67-945c-11011372818f
+:END:
+
+The ~denote-dired-rename-marked-files~ now accepts two optional
+arguments.  When called interactively, these are interpreted as a
+single or double universal prefix argument (=C-u= by default, though
+do =M-x where-is= and search for ~universal-argument~).
+
+The first argument, named =SKIP-FRONT-MATTER-PROMPT=, skips the "yes
+or no" prompt requested at the outset of the operation, passing to it
+an affirmative response.  Thanks to Jay Rajput for asking the question
+that inspired me to implement this.  It was done in issue 155 on the
+GitHub mirror: <https://github.com/protesilaos/denote/issues/155>.
+
+The second argument, named =NO-UNIQUE-ID-CHECK=, will not perform any
+checks for potential duplicate identifiers.  The default is to check
+for duplicates and increment them such that they become unique.  The
+reason this optional argument exists is for those who want to speed up
+the process, perhaps because they know ahead of time all identifiers
+will be unique or do not care about them.
+
+Thanks to Bruno Boal for refining how the prefix argument is
+processed.  The patch was sent via a private channel.  The change is
+small and thus does not require copyright assignment to the Free
+Software Foundation.
+
+** Menu entries help users discover Denote
+:PROPERTIES:
+:CUSTOM_ID: h:651e5561-f9ce-41f6-bad3-d54ce2dcff04
+:END:
+
+Users of ~menu-bar-mode~ and/or ~context-menu-mode~ will now find a
+submenu with points of entry to Denote.  Refer to the publication I
+made on my website, as it includes a picture:
+<https://protesilaos.com/codelog/2023-03-31-emacs-denote-menu/>.  I
+will save the thousand words for the following sections. 🙃
+
+There is a known issue where the ~menu-bar-mode~ entry is positioned
+before the =File= submenu.  Apparently, there exists an inelegant way
+to place the menu elsewhere, but I am not willing to maintain hacks
+for missing functionality.  If someone knows a clear way to put the
+submenu elsewhere, please contact me: I want it to be after =Tools=.
+
+Thanks to Kai von Fintel and Noboru Ota (nobiot) for discussing the
+placement of the submenu:
+<https://lists.sr.ht/~protesilaos/denote/%3C2B60992C-0FC9-42CC-B669-69A544450FEF%40mit.edu%3E>.
+
+** "Link" commands have simpler names
+:PROPERTIES:
+:CUSTOM_ID: h:acf95a79-3c45-423d-a88f-d6eed7fa5387
+:END:
+
+Originally, Denote was organised as a collection of several files,
+each of which had its own prefix like =denote-dired.el=, and
+=denote-link.el=.  This arrangement was deemed surplus to requirements
+and all core code was consolidated in =denote.el=.  An artefact of
+that design was the presence of symbols that retained their admittedly
+awkward names, like the command ~denote-link-backlinks~ or
+~denote-link-add-missing-links~.
+
+All such commands are deprecated.  They are replaced with more
+discoverable names.  The deprecation is done in such a way that the
+old names are aliases for the new ones, but the user is warned not to
+rely on them.
+
+The new names in detail:
+
+| Old name 🤨                         | New name 🤩                                                   |
+|-------------------------------------+---------------------------------------------------------------|
+| ~denote-link-add-links~             | ~denote-add-links~                                            |
+| ~denote-link-add-missing-links~     | ~denote-add-missing-links~                                    |
+| ~denote-link-backlinks~             | ~denote-backlinks~                                            |
+| ~denote-link-find-file~             | ~denote-find-link~                                            |
+| ~denote-link-insert-link~           | ~denote-insert-link~ (alias for ~denote-link~)                |
+| ~denote-link-show-backlinks-buffer~ | ~denote-show-backlinks-buffer~ (alias for ~denote-backlinks~) |
+
+** Denote buffers can have shorter names
+:PROPERTIES:
+:CUSTOM_ID: h:98f6b10a-ea29-49d1-8d3f-e2f0409f4c8f
+:END:
+
+The Denote file-naming scheme is designed to be a low-tech way of
+embedding information in files, making them easier to find.  A
+downside is that the names are longer than =blah.txt= and so the
+default Emacs behaviour is to derive a buffer name from the file name.
+
+The new optional =denote-rename-buffer.el= provides a minor mode to
+automatically rename the buffer of an existing file, such that it
+reflects the file's =TITLE= field.  Users must enable
+~denote-rename-buffer-mode~.
+
+The renaming procedure is controlled by the user option
+~denote-rename-buffer-function~.  By default, it provides the means to
+rename using (i) the title, (ii) the identifier, or (iii) a custom
+function that returns a string.  Experienced users can refer to
+~denote-rename-buffer-with-title~ to draw inspiration on the design of
+such a function.
+
+Thanks to Morgan Davidson for asking a question that inspired me to
+implement this feature.  The discussion took place in issue 151 on the
+GitHub mirror <https://github.com/protesilaos/denote/issues/151>.
+
+** Silos work as directory trees
+:PROPERTIES:
+:CUSTOM_ID: h:113820c4-7a6f-4126-9a44-92bfa59744e2
+:END:
+
+Denote provides a feature to isolate files in to their own silos, each
+of which functions as its own ~denote-directory~ variable.  The
+technicalities are explained in the manual.  Silos have proven to be a
+valuable aspect of file management and I have thus expanded their
+scope to work as fully fledged directory trees.  This means that we no
+longer assume a silo to be a flat directory listing, but instead
+recognise any subdirectories inside of it.
+
+Thanks to relict007, Hilde Rhyne, Mirko Hernández, Noboru Ota
+(nobiot), Alan Schmitt, hapst3r, and Hilde Rhyne for their
+participation in the relevant discussions:
+
+- <https://lists.sr.ht/~protesilaos/denote/%3C87fsb72nge.fsf%40protesilaos.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C80CBB671-D812-4EA8-8C80-85F9F4144051%40disroot.org%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C87pma6t59i.fsf%40kotlak.com%3E>
+- <https://github.com/protesilaos/denote/issues/129> (GitHub mirror)
+- <https://lists.sr.ht/~protesilaos/denote/%3CB124A5AF-9968-4F7E-9F4B-2BC763E0BFCF@disroot.org%3E#%3Cm0sff0nnhb.fsf@disroot.org%3E>.
+
+** Keywords do not accept multiple words by default
+:PROPERTIES:
+:CUSTOM_ID: h:08f23806-9570-4031-86e4-810b3e93be81
+:END:
+
+The idea is to have short keywords and then use more than one, if
+necessary.  We do not want to encourage the habit of long keywords
+that become overly specific, while we want to avoid the use of
+dashes as delimited in the file name's =KEYWORDS= field.
+
+Technically, this changes the default value of the user option
+~denote-allow-multi-word-keywords~.  Users who preferred the old
+behaviour can simply toggle it on.
+
+** Pass arguments to Org capture
+:PROPERTIES:
+:CUSTOM_ID: h:58ff6dd3-693a-4437-9217-8e876d92c975
+:END:
+
+Denote is not an extension of Org mode, though it can integrate with
+~org-capture~.  I now make it possible to design a capture template
+that uses specific prompts.  Consult the section in the manual titled
+"Create note with specific prompts using Org capture".
+
+Thanks to Aditya Yadav for asking about this in issue 132 on the
+GitHub mirror: <https://github.com/protesilaos/denote/issues/132>.
+
+** Change an existing note's file type
+:PROPERTIES:
+:CUSTOM_ID: h:e1e874e3-d8ad-4685-aa62-59ad07078db2
+:END:
+
+The command ~denote-change-file-type~ changes the file type of an
+existing note.  The available options are those among
+~denote-file-type~.  Thanks to Jean-Philippe Gagné Guay for the
+contribution, which was done in pull request 137 on the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/137>.
+
+** Denote dynamic blocks can now parse ~rx~ notation
+:PROPERTIES:
+:CUSTOM_ID: h:fe595ee7-8ba6-4ca3-aa66-35aa4e5ca0f5
+:END:
+
+Denote can leverage the Org feature of "dynamic blocks" to produce
+lists of links/backlinks.  This is especially useful for metanotes
+(read the Denote manual---I document everything for a reason).
+
+Before, regular expressions were implemented only as strings while now
+they can also be written using the ~rx~ notation.  Thanks to Mirko
+Hernandez for proposing this feature and discussing it with me in
+issue 122 on the GitHub mirror:
+<https://github.com/protesilaos/denote/issues/122>.
+
+Thanks to Elias Storms, the author of =denote-org-dblock.el=, for
+iterating on this functionality.  This was done in pull request 130 on
+the GitHub mirror: <https://github.com/protesilaos/denote/pull/130>.
+
+** Made links to non-note files works as intended
+:PROPERTIES:
+:CUSTOM_ID: h:431a8952-0d71-4ba6-b6ae-85e5f7d520b9
+:END:
+
+The function ~denote-get-path-by-id~ is refactored to accept any file
+with an identifier.  This always was its intended purpose.  The user
+was always able to create =denote:= Org link types to, for example,
+=jpg= files but ~denote-get-path-by-id~ was refusing to resolve the
+otherwise valid path.  Thanks to user relict007 for reporting the
+problem and discussing it with me in issue 135 on the GitHub mirror:
+<https://github.com/protesilaos/denote/issues/135>.
+
+The change was not trivial.  It was followed up by a patch from Noboru
+Ota (nobiot) which elaborated on the conditionality.  Quoting from
+commit =9ce9a24=:
+
+#+begin_quote
+fix(denote-get-path-by-id): #135
+
+Reference: https://github.com/protesilaos/denote/issues/135
+
+This patch change function 'denote-get-path-by-id' to allow for the following:
+
+- A single ID points to multiple files with different extensions
+- Denote needs to find a single file out of the multiple files
+- This is not necessarily a user error (export an Org file to an HTML)
+- Denote should let user decide their "primary" file extension
+
+The case the patch is intended to fix goes something like this:
+
+- You have 20230216__mynotes--tag.org.
+- You export it to 20230216__mynotes--tag.html.
+- Both files are in denote-directory
+- This means you have two files with the same ID with different
+  extensions denote-link-find-file, denote-link-find-backlink, and xref
+  integration might find the html file INSTEAD OF the .org file
+
+This is because html is earlier in the alphabetical order than
+org. Because the function uses seq-find, it will find the .html file
+first and returns it.
+#+end_quote
+
+** The ~denote-rename-file-using-front-matter~ works with empty keywords
+:PROPERTIES:
+:CUSTOM_ID: h:b00f228d-7f84-4d84-8d5f-ac90ea6b1065
+:END:
+
+Keywords are an optional field in the Denote file-naming scheme.
+However, an earlier version of the command mentioned in this heading
+was considering them mandatory and would refuse to proceed if the
+keywords were nil.  Thanks to Eduardo Grajeda for fixing this:
+<https://lists.sr.ht/~protesilaos/denote/patches/39896>.
+
+The change is within the ~15 line limit and does not require copyright
+assignment to the Free Software Foundation.
+
+** The ~denote-title-prompt~ has its own history
+:PROPERTIES:
+:CUSTOM_ID: h:91f370f4-9fd1-461b-8ba4-fd9ba2d9c7a8
+:END:
+
+Denote implements minibuffer histories for all its relevant functions.
+This makes it easier for users to retrieve their previous inputs and
+to not get irrelevant ones.
+
+Before, the ~denote-title-prompt~ was not using its own history but
+was instead relying on another one that was intended only for file
+paths, thus mixing unrelated inputs.
+
+Thanks to Jonathan Sahar for bringing this matter to my attention.
+This was done in issue 144 on the GitHub mirror:
+<https://github.com/protesilaos/denote/issues/144>.
+
+** For developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:dcc52671-2127-47e0-9167-003f40ca3a54
+:END:
+
+*** Made it possible to add predicates for recursive file listing
+:PROPERTIES:
+:CUSTOM_ID: h:62546ec1-6ec8-41c7-9a18-10a531b534ce
+:END:
+
+The helper function ~denote--directory-all-files-recursively~ accepts
+predicates to help speed up its work.
+
+Thanks to Wade Mealing for reporting the issue about the performance
+of the built-in function ~directory-files-recursively~ in large,
+nested directories.  And thanks to Graham Marlow for the patch, which
+was prepared as part of an extended discussion with me:
+
+- <https://lists.sr.ht/~protesilaos/denote/patches/40370>
+- <https://lists.sr.ht/~protesilaos/denote/%3C20230414000311.1981-1-graham%40mgmarlow.com%3E#%3C76ed9fe2-d597-f7b9-5e59-717aeb77c3c3@mgmarlow.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/patches/40384>
+- <https://lists.sr.ht/~protesilaos/denote/%3C87edonhvy0.fsf%40protesilaos.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C76ed9fe2-d597-f7b9-5e59-717aeb77c3c3%40mgmarlow.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C87zg75q4er.fsf%40protesilaos.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3CCAO4UgPQtxhhqW0tB7eZnVh4nF9vLvnVGx+5oB_78_dg32URSLA%40mail.gmail.com%3E>
+
+*** New public symbols
+:PROPERTIES:
+:CUSTOM_ID: h:ed723274-a78e-4cfd-9655-c3bfe0fb1e68
+:END:
+
+The following are now public symbols that we commit to support and
+document henceforth:
+
++ Function ~denote-file-type-extensions~ :: Return all file type
+  extensions in ~denote-file-types~.
+
++ Variable ~denote-encryption-file-extensions~ :: List of strings
+  specifying file extensions for encryption.
+
++ Function ~denote-file-type-extensions-with-encryption~ :: Derive
+  ~denote-file-type-extensions~ plus ~denote-encryption-file-extensions~.
+
++ Function ~denote-link-return-links~ :: Return list of links in
+  current or optional =FILE=.  Also see ~denote-link-return-backlinks~.
+
++ Function ~denote-link-return-backlinks~ :: Return list of links in
+  current or optional =FILE=.  Also see ~denote-link-return-links~.
+
++ Function ~denote-rewrite-front-matter~ :: Rewrite front matter of
+  note after ~denote-rename-file~ (or related) The =FILE=, =TITLE=,
+  =KEYWORDS=, and =FILE-TYPE= arguments are given by the renaming
+  command and are used to construct new front matter values if
+  appropriate.
+
++ Function ~denote-rewrite-keywords~ :: Rewrite =KEYWORDS= in =FILE=
+  outright according to =FILE-TYPE=.  Do the same as
+  ~denote-rewrite-front-matter~ for keywords, but do not ask for
+  confirmation.  This is for use in ~denote-keywords-add~,
+  ~denote-keywords-remove~, ~denote-dired-rename-marked-files~, or
+  related.
+
+I am publicising the ~denote-link-return-links~ and its counterpart in
+response to the mailing list thread started by relict007:
+<https://lists.sr.ht/~protesilaos/denote/%3C87a5ygk6yi.fsf@kotlak.com%3E>.
+relict007 is the developer of the ~denote-cache~ package (in
+progress): <https://git.sr.ht/~relict007/denote-cache>.
+
+Similarly, the ~denote-rewrite-keywords~ is made public upon the
+request of Alan Schmitt:
+<https://lists.sr.ht/~protesilaos/denote/%3Cm2ttzgn2wu.fsf%40m4x.org%3E>.
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:918087e6-8cd5-4d4f-a11a-b465dcbd9fe3
+:END:
+
+- Revised ~denote-link-return-{links,backlinks}~ to not produce a
+  ~user-error~.  The errors are reserved for the interactive
+  functions. The others are for developers. Thanks to Elias Storms for
+  bringing this matter to my attention:
+  <https://github.com/protesilaos/denote/commit/694c1517be73949edbc3993c105c764da8e2571f#commitcomment-112677876>.
+
+- Refrained from trying to find forward links in non-text-files.  If a
+  file extension is not in ~denote-file-types~, we have no way of
+  parsing or finding outgoing links in it. This change checks for the
+  file extension early on in 'when-let*' block and avoids opening the
+  file which is a relatively costly operation (and would fail finding
+  links anyway).  Thanks to relict007 for the patch.  This was done on
+  the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C87r0riffdx.fsf%40kotlak.com%3E>
+  The change is small and thus does not require copyright assignment
+  to the Free Software Foundation.
+
+- Explained how to troubleshoot Denote.  Refer to the section in the
+  manual titled "Troubleshoot Denote in a pristine environment."
+  While this is about Denote, the skills apply to all Emacs packages.
+
+- Ensured backlinks get correct ~denote-directory~ path.  The
+  backlinks buffer will now get the correct path when it is generated
+  inside a silo.  This is related to issue 129 reported by hapst3r on
+  the GitHub mirror: <https://github.com/protesilaos/denote/issues/129>.
+  The change is necessary because =.dir-locals.el= do not work for
+  buffers, so we must get the value from the file that calls
+  ~denote-link-backlinks~.
+
+- Added missing underscore from examples in exporting section.  Thanks
+  to Peter Prevos for bringing this matter to my attention:
+  <https://lists.sr.ht/~protesilaos/denote/%3C87fs8b85tq.fsf%40prevos.net%3E#%3C87lehiuxfo.fsf@protesilaos.com%3E>.
+
+- Made the command ~denote-open-or-create~ work with an empty
+  ~denote-directory~.  The ~denote-file-prompt~ would throw an error
+  before.  The correct behaviour is to proceed to the "Create" phase
+  if the ~denote-directory~ is empty.  Thanks to user drcxd for
+  reporting the bug in issue 131 on the GitHub mirror and for testing
+  my sample code: <https://github.com/protesilaos/denote/issues/131>.
+
+- Documented how to use tree-based file prompt on demand.  This is my
+  solution to a request made by Mirko Hernandez on the possible use of
+  the old Denote file prompt.  It is better not to introduce a user
+  option for this case, nor to keep multiple variants of the
+  ~denote-file-prompt~ in denote.el, as we want to keep things simple.
+  Mirko's feedback was provided in issue 121 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/121>.
+
+- Added the variable ~denote-user-enforced-denote-directory~.  This is
+  intended for users who write custom code to extend Denote.  The
+  value of this variable should be ~let~ bound around calls to the
+  function ~denote-directory~, thus overriding its return value.  This
+  was discussed on the mailing list and then introduced by Vedang
+  Manerikar in commit =977c757=, with further changes by me in
+  =20ddc97=: <https://lists.sr.ht/~protesilaos/denote/patches/41776>.
+  Vedang has assigned copyright to the Free Software Foundation.
+
+- Fixed ~my-denote-org-extract-subtree~ section of the documentation.
+  This is part of some sample code that is not part of =denote.el=,
+  but we provide as a convenience/inspiration for interested parties.
+
+  The provided function did not work correctly.
+
+  1. Tags are extracted before deleting the region from the source file.
+  2. The function ~org-end-of-subtree~ is called to calculate the
+     point we should delete up to.  The previously used function
+     ~org-entry-end-position~ ends at the first sub-heading under the
+     tree, which is not what we want.  Instead, we want to cut the
+     whole subtree.
+  3. The date information available in the subtree is retained.  We
+     look for three common places for this information: the =CREATED=
+     or =DATE= properties in the =PROPERTIES= drawer, and the =CLOSED=
+     cookie at the element level itself.
+
+  Thanks to Vedang Manerikar for the contribution:
+  <https://lists.sr.ht/~protesilaos/denote/%3CCABzEscbPx24LCUCc7JsMmQtVGwhou5fUH_5h+%3Dt%3Dqi4396NqNQ%40mail.gmail.com%3E>
+
+- Removed the dependency on the built-in ~xdg~ library and updated the
+  default value of the user option ~denote-directory~.  The reason is
+  that XDG is a Linux standard that does not work on other operating
+  systems, according to private feedback I received.
+
+- Fixed a regression for =M-p= (~previous-history-element~) in "do or
+  create" commands.  Read the doc string of the commands
+  ~denote-open-or-create~ or ~denote-link-or-create~ for how this is
+  supposed to work.  In short:
+
+  - Invoke the "do or create" command.
+  - Type something that does not match a file.
+  - In the following title prompt, hit =M-p= to bring back the last input.
+
+  I realised there was a regression when I read issue 152 on the
+  GitHub mirror, which was created by user "ustcpxy":
+  <https://github.com/protesilaos/denote/issues/152>.  The issue is
+  about skipping the file title prompt.
+
+- Simplified the internal ~denote--buffer-file-names~.  Thanks to Adam
+  Růžička for noting that my change was not compatible with older
+  Emacs versions, and for preparing the change.  This was discussed in
+  pull request 158 on the GitHub mirror, with my suggestion to not use
+  ~seq-filter~ as it affected the return value:
+  <https://github.com/protesilaos/denote/pull/158>. The change is
+  below the 15 line limit, meaning that Adam does have to assign
+  copyright to the Free Software Foundation.
+
+- Documented custom code in the manual on how to interactively select
+  a silo.  I am providing this in response to a request from GitHub
+  user rbenit68.  The discussion took place in issue 127 on the GitHub
+  mirror, with the participation of Mirko Hernandez:
+  <https://github.com/protesilaos/denote/issues/127>. The custom code
+  I provide is the expanded version of an idea put forth by Mirko, to
+  whom I am thankful.
+
+- Fixed an outdated reference in the ~denote-file-types~ doc string.
+  Thanks to user doolio for spotting the error and reporting it in
+  issue 139 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/139>.
+
+- Cited in the manual's section "Publications about Denote" an article
+  by Mohamed Suliman titled /Managing a bibliography of BiBTeX entries
+  with Denote/ (2022-12-20):
+  <https://www.scss.tcd.ie/~sulimanm/posts/denote-bibliography.html>.
+  If you have published something related to Denote, please let me
+  know and I will add to the list.
+
+- Cited the essay by Summer Emacs titled /An explanation of how I use
+  Emacs/ (2023-05-04):
+  <https://github.com/summeremacs/howiuseemacs/blob/main/full-explanation-of-how-i-use-emacs.org>
+
+- Cited the video series by Stefan Thesing titled /Denote as a
+  Zettelkasten/: <https://www.thesing-online.de/blog/denote-as-a-zettelkasten/>.
+
+- Added link to Karl Voit's work in the manual's section "Alternative
+  implementations and further reading."  Thanks to Norwid Behrnd for
+  the contribution in pull request 123 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/123>.
+
+- Fixed the broken link to jao's blog.  Thanks to Tomasz Hołubowicz
+  for the contribution, which was done in pull request 145 on the
+  GitHub mirror: <https://github.com/protesilaos/denote/pull/145>.
+
+- Authored lots of other ancillary changes/features to the code base
+  or the manual (yes, this change log is how I "cut the long story
+  short").
+
+* Version 1.2.0 on 2022-12-12
+:PROPERTIES:
+:CUSTOM_ID: h:92478a05-4a69-413c-8d95-1dacbcf6af2c
+:END:
+
+** Denote now requires Emacs version 28.1 or higher
+:PROPERTIES:
+:CUSTOM_ID: h:bc0e173a-3b9f-427c-9fb0-d435a5ef127e
+:END:
+
+With the help of Noboru Ota (nobiot), we realised that Denote was
+broken on Emacs 27 for quite a while.  The fact that we received no
+feedback about it suggests that this change is the best course of
+action going forward.  Discussion:
+<https://lists.sr.ht/~protesilaos/denote/%3C86r0yvzm12.fsf%40nobiot.com%3E#%3C86sfja78ik.fsf@nobiot.com%3E>
+
+Emacs 27 lacks certain Xref facilities that we need for the
+backlinking facility.  It was holding us back for no good reason,
+while also adding to the maintenance burden.
+
+If you are using Denote on Emacs 27 and things are working for you,
+there is no need to update the package.  Do it when you also upgrade
+Emacs to a newer version.
+
+** Display context in backlinks' buffer
+:PROPERTIES:
+:CUSTOM_ID: h:dafbdbae-36f1-487a-94c8-2762568a766e
+:END:
+
+By default, the generic backlinks' buffer, which can be displayed with
+the command ~denote-link-backlinks~ (alias ~denote-link-show-backlinks-buffer~),
+only shows the file names of the linked notes.
+
+We have made it possible to produce a more informative view by showing
+the context of the link and also listing all links per file.  This is
+done by setting the user option ~denote-backlinks-show-context~ to a
+non-nil value.
+
+To illustrate the difference, this is the default backlinks' buffer:
+
+#+begin_example
+Backlinks to "On being honest" (20220614T130812)
+------------------------------------------------
+
+20220614T145606--let-this-glance-become-a-stare__journal.txt
+20220616T182958--feeling-butterflies-in-your-stomach__journal.txt
+#+end_example
+
+And this is the one with ~denote-backlinks-show-context~ enabled:
+
+#+begin_example
+Backlinks to "On being honest" (20220614T130812)
+------------------------------------------------
+
+20220614T145606--let-this-glance-become-a-stare__journal.txt
+37: growing into it: [[denote:20220614T130812][On being honest]].
+64: As I said in [[denote:20220614T130812][On being honest]] I have never
+20220616T182958--feeling-butterflies-in-your-stomach__journal.txt
+62: indifference.  In [[denote:20220614T130812][On being honest]] I alluded
+#+end_example
+
+Granted, here we show plain text though in Emacs the results have the
+appropriate colours of the active theme and are easier to read.
+
+Thanks to Noboru Ota (nobiot) for implementing this feature.  We
+discussed it at length on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C86r0yvzm12.fsf%40nobiot.com%3E>.
+
+Noboru has assigned copyright to the Free Software Foundation.
+
+** Dynamic Org blocks for lists of Denote links
+:PROPERTIES:
+:CUSTOM_ID: h:f7904a57-22c0-446f-b7e3-7a736332002c
+:END:
+
+Denote now includes the ~denote-org-dblock~ library.  Activate it
+thus:
+
+#+begin_src emacs-lisp
+;; Register Denote's Org dynamic blocks
+(require 'denote-org-dblock)
+#+end_src
+
+A dynamic block gets its contents by evaluating a given function,
+depending on the type of block.  The type of block and its parameters
+are stated in the opening =#+BEGIN= line of the block.  Typing =C-c
+C-c= with point on that line runs the function, with the given
+arguments, and populates the block's contents accordingly.
+
+What Denote has is ways to write blocks that produce a list of links
+matching a given regular expression while conforming with some other
+parameters.  The manual explains how to use this powerful feature
+(which is necessarily specific to the Org file type):
+<https://protesilaos.com/emacs/denote#h:8b542c50-dcc9-4bca-8037-a36599b22779>.
+
+Thanks to Elias Storms for authoring ~denote-org-dblock~ and for
+discussing this issue at length with me on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3Cm2sfisexx7.fsf%40MBA21.fritz.box%3E>.
+
+Elias has assigned copyright to the Free Software Foundation.
+
+** Integration with the built-in project.el and xref.el libraries
+:PROPERTIES:
+:CUSTOM_ID: h:e8a7d08c-cdf0-4207-92c1-391415b8371f
+:END:
+
+Denote was already using Xref internally but has now gained more
+capabilities which help it find files more effectively.  With the help
+of Emacs' standard project library, all file-related prompts (e.g. to
+add a link) search all items in the ~denote-directory~ regardless of
+whether the user is in a subdirectory or not.
+
+All Denote commands benefit from this refactoring.  One such request
+to "Make ~denote-open-or-create~ work better across subfolders" was
+made in issue 114 on the GitHub mirror:
+<https://github.com/protesilaos/denote/issues/114>.
+
+Thanks to Noboru Ota (nobiot) for introducing this feature together
+with a new system of "modules" for incorporating additional built-in
+functionality:
+
+- <https://lists.sr.ht/~protesilaos/denote/%3C86a64ooxyi.fsf%40nobiot.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C86k03f4iq6.fsf%40nobiot.com%3E>
+
+I will not document the new user option ~denote-modules~ right now as
+my ongoing job search prevented me from exploring the full potential
+of this feature.  I promise to do it for the next version of Denote
+and update the manual accordingly.  Nevertheless, the doc string of
+~denote-modules~ already provides all one needs to get started.
+
+** Re-use last input in "do or create" commands
+:PROPERTIES:
+:CUSTOM_ID: h:5a003d44-7ad0-4c92-b908-ec7cf016b2dd
+:END:
+
+The commands ~denote-open-or-create~, ~denote-link-or-create~ first
+prompt for an existing note.  If they find it, they act on it,
+otherwise they prompt for the creation of a new note to operate on.
+
+At the first prompt, it is common to use regular expressions and
+out-of-order pattern matching (such as with the ~orderless~ package),
+so the input can be something like =_test ^2022 some title=, which we
+obviously don't want to automatically reuse as the new note's actual
+title.
+
+To this end, and to accommodate all workflows, we leverage Emacs'
+minibuffer history to make the last input accessible with =M-p= at the
+minibuffer prompt (=M-x previous-history-element=).  The text is
+available for further editing before it is submitted as the new note's
+title.  Simple, effective, and flexible!
+
+Thanks to Guo Yong for starting the discussion that led me to this
+improvement:
+<https://lists.sr.ht/~protesilaos/denote/%3CNF6pFBq--3-9%40tutanota.com%3E>.
+
+** Add support for any file type
+:PROPERTIES:
+:CUSTOM_ID: h:e73a4e76-6c00-4691-8893-8f885c26f306
+:END:
+
+Denote provides the user option ~denote-file-type~ which specifies the
+file type to use for new notes.  Options include Org mode (the
+default), Markdown+YAML, Markdown+TOML, and plain text.  Furthermore,
+there exists the convenience command ~denote-type~ (alias
+~denote-create-note-using-type~) which prompts for a file type to use
+when creating a new note (I normally write in plain text, but
+sometimes switch to Org or Markdown).
+
+The variable ~denote-file-types~ (which is NOT a user option)
+specifies all the parameters of what a "file type" means, such as how
+to format its front matter, what style of date+time to use, which file
+type extension to write, how to rename the file, what style of link to
+apply, and so on.  Advanced users can now edit this variable to either
+register new file types or redefine the behaviour of existing ones.
+Read this comprehensive guide on how to do it:
+<https://protesilaos.com/codelog/2022-10-30-demo-denote-custom-file-type/>.
+
+I repeat: this is for advanced users or, anyhow, for those who are
+prepared to maintain some custom code in their setup.  The guide is
+accessible though and I am always willing to help anyone in need of
+assistance.
+
+A relevant request for such a feature can be found in issue 86 on the
+GitHub mirror: <https://github.com/protesilaos/denote/issues/86>.
+
+The ~denote-file-types~ were introduced by Jean-Philippe Gagné Guay in
+pull request 89 at the GitHub mirror and were part of Denote version
+0.6.0: <https://github.com/protesilaos/denote/pull/89>.  I have made
+lots of changes since then to make all parts of Denote work with it
+and to parameterise its various facets.
+
+** Exclude certain directories from all operations
+:PROPERTIES:
+:CUSTOM_ID: h:04f42aab-d8fe-4c4a-b865-3bb0655e2631
+:END:
+
+The user option ~denote-excluded-directories-regexp~ instructs all
+Denote functions that read or check file/directory names to omit
+directories that match the given regular expression.  The regexp needs
+to match only the name of the directory, not its full path.
+
+Affected operations include file prompts and functions that return the
+available files in the ~denote-directory~.  File prompts are used by
+several commands, such as ~denote-link~ and ~denote-subdirectory~.
+Functions that check for files include ~denote-directory-files~ and
+~denote-directory-subdirectories~.
+
+Thanks to Graham Marlow for the contribution which was done in pull
+request 112 on the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/112>.
+
+The original contribution, with the subsequent tweaks I made to it, is
+within the eligible line count and thus does not require copyright
+assignment to the Free Software Foundation.
+
+** Exclude certain keywords from being inferred
+:PROPERTIES:
+:CUSTOM_ID: h:226ba85e-1f5e-45f5-956a-f5e8a95c397e
+:END:
+
+The user option ~denote-excluded-keywords-regexp~ omits keywords that
+match a regular expression from the list of inferred keywords.
+
+Keywords are inferred from file names and provided at relevant prompts
+as completion candidates when the user option ~denote-infer-keywords~
+is non-nil.
+
+Thanks to Stefan Thesing for proposing this idea in issue 115 on the
+GitHub mirror: <https://github.com/protesilaos/denote/issues/115>.
+
+[ Other people participate in that thread and there may be something
+  more coming out of it. ]
+
+** Use the ~citar-denote~ package for bibliography notes
+:PROPERTIES:
+:CUSTOM_ID: h:ff16633f-5fb8-4935-9e2f-044ec998d3f7
+:END:
+
+Peter Prevos has produced the ~citar-denote~ package which makes it
+possible to write notes on BibTeX entries with the help of the ~citar~
+package.  These notes have the citation's unique key associated with
+them in the file's front matter.  They also get a configurable keyword
+in their file name, making it easy to find them in Dired and/or
+retrieve them with the various Denote methods.
+
+With ~citar-denote~, the user leverages standard minibuffer completion
+mechanisms (e.g. with the help of the ~vertico~ and ~embark~ packages)
+to manage bibliographic notes and access those notes with ease.  The
+package's documentation covers the details: <https://github.com/pprevos/citar-denote/>.
+
+Thanks to Peter Prevos for developing this package and for mentioning
+it on the Denote mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C877cz0e96r.fsf%40prevos.net%3E>.
+
+** New functions and variables for developers
+:PROPERTIES:
+:CUSTOM_ID: h:5cc2076d-d4d2-45be-b28e-9ec67eca82b4
+:END:
+
+Developers or users who maintain custom code now have access to:
+
++ Function ~denote-keywords-sort~
++ Function ~denote-keywords-prompt~
+
+Plus all the following which are related to the aforementioned ~denote-file-types~:
+
++ Variable ~denote-org-link-format~
++ Variable ~denote-md-link-format~
++ Variable ~denote-id-only-link-format~
++ Variable ~denote-org-link-in-context-regexp~
++ Variable ~denote-md-link-in-context-regexp~
++ Variable ~denote-id-only-link-in-context-regexp~
++ Function ~denote-date-org-timestamp~
++ Function ~denote-date-rfc3339~
++ Function ~denote-date-iso-8601~
+
+Again, users can implement support for ANY FILE TYPE and use it to
+write notes in, either as their default choice or on-demand.  If
+anything, this highlights the flexibility of Denote.
+
+** Miscellaneous
+:PROPERTIES:
+:CUSTOM_ID: h:acbb0cf7-ad17-495e-85d2-821cbbfc3158
+:END:
+
++ Added the ~denote-keywords-sort~ function.  The intent is to
+  abstract the task of sorting the keywords.  Before, it was handled
+  by the ~denote-keywords-prompt~, which meant that keywords were not
+  sorted when the ~denote~ function was called from Lisp.  Thanks to
+  Florian for bringing this matter to my attention, providing relevant
+  feedback, and fixing an omission of mine in ~denote-rename-file~:
+  <https://lists.sr.ht/~protesilaos/denote/%3C166689879712.8.6808878344988686135.71824507%40aboulafia.org%3E>.
+
++ Expanded the manual's entry on directory "silos" to include more
+  code examples.  Thanks to Viktor Haag for asking a question on the
+  mailing list that inspired me to produce this entry:
+  <https://lists.sr.ht/~protesilaos/denote/%3CCANnkwC6NLd0VneUEqFrjh7TCUBLBgEtLCcPwM37JDvJXJCShVQ%40mail.gmail.com%3E>.
+
++ Included a section in the manual with a non-exhaustive list of
+  references to publications about Denote.  As of this writing, it
+  includes entries from David Wilson (SystemCrafters), Jack Baty,
+  Jeremy Friesen, and Peter Prevos.  If you have an article about
+  Denote, please contact me about it directly or on the Denote mailing
+  list and I will add it to the manual.
+
++ Tweaked how Org's HTML export produces links in order to avoid
+  broken subdirectory paths.  Thanks to Thibaut Benjamin for the
+  contribution, which was done in pull request 116 on the GitHub
+  mirror: <https://github.com/protesilaos/denote/pull/116>.
+
+  The change concerns a single line and thus Thibaut requires no
+  copyright assignment to the Free Software Foundation.
+
++ Expanded the manual where necessary.
+
+* Version 1.1.0 on 2022-10-20
+:PROPERTIES:
+:CUSTOM_ID: h:8e0f536a-ab3b-4cab-82f7-529bc0e40dbd
+:END:
+
+** New commands or refinements to common use-cases
+:PROPERTIES:
+:CUSTOM_ID: h:5665e7ec-4f3a-4de3-8cb0-63d25a0db8c1
+:END:
+
++ The ~denote-link-add-missing-links~ is a companion to what we
+  already provide to produce a list of links to Denote files matching
+  a regular expression (the ~denote-link-add-links~).  This new
+  command adds links that are not already present in the current file.
+  So if you have a metanote that references, say, your journal entries
+  but have not updated it in a month, you can revisit the metanote,
+  invoke ~denote-link-add-missing-links~, and then type the search
+  terms (e.g. =_journal=) to include what remains.
+
+  Thanks to Elias Storms for the initial contribution, which was done
+  in pull request 108 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/108>.
+
+  Elias has assigned copyright to the Free Software Foundation.  It is
+  required for changes that exceed 15 lines in total.
+
++ The ~denote-link-find-backlink~ provides a minibuffer interface that
+  shows all backlinks to the current note.  It complements the
+  existing ~denote-link-backlinks~ command (which also has the alias
+  ~denote-link-show-backlinks-buffer~).  Each command has its own
+  niche: the minibuffer lets the user leverage powerful pattern
+  matching styles, such as those provided by the =orderless= package,
+  while the bespoke buffer provides an easy overview of what links to
+  the current note.
+
+  Thanks to Elias Storms for the original patch:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cm2fsg6o2t6.fsf%40MBA21.fritz.box%3E#%3Cm2pmfam7yi.fsf@MBA21.fritz.box%3E>.
+
++ The ~denote-keywords-add~ and ~denote-keywords-remove~ are two
+  commands that interactively operate on the current note's front
+  matter to add or remove keywords.  They use the familiar keywords'
+  prompt which means, among others, that they can read more than one
+  keyword at a time.  To specify multiple keywords, separate each
+  input with a comma (or whatever the value of ~crm-separator~ is,
+  which should be a comma unless something out-of-the-ordinary is in
+  force).
+
+  Thanks to Elias Storms for the original patch, which was done as
+  part of a discussion on the mailing list and then iterated on:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cm24jwvpbt2.fsf%40MBA21.fritz.box%3E#%3Cm28rlik0tc.fsf@MBA21.fritz.box%3E>.
+
++ The ~denote-link~ command will now recognise an active region and
+  use its text as the description of the inserted link.  The default
+  behaviour is to use the file's title from its front matter or file
+  name.  Thanks to Charanjit Singh for the original contribution,
+  which was done as part of pull request 109 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/109>.  A subsequent
+  tweak was implemented in pull request 110, following a discussion
+  with me: <https://github.com/protesilaos/denote/pull/110>.
+
+  Charanjit's contribution is below the ~15 line threshold and thus
+  does not require copyright assignment to the Free Software
+  Foundation.
+
++ The renaming operations are now aware of the underlying version
+  control system and will use the appropriate command when a VCS is
+  available.  In practice, renaming a file under, say, Git will
+  register it as a "rename" instead of two separate actions of
+  deletion and addition.
+
+  Thanks to Florian for the patch.  It was discussed on the mailing
+  list and then underwent some changes:
+  <https://lists.sr.ht/~protesilaos/denote/%3C166547153518.8.941129310186454444.68125516@aboulafia.org%3E>.
+
++ The ~denote-rename-file-using-front-matter~ no longer fails to carry
+  out its intended task when the front matter has no keywords.  If no
+  keywords are available, this is interpreted as a request to remove
+  the KEYWORDS component of the file name.  This was always
+  technically possible and could be achieved with various permutations
+  of the user option ~denote-prompts~ (as explained in its doc string
+  or the manual).  Denote only needs an identifier in the file name to
+  establish unique links (although I strongly encourage you to stick
+  to the standard file-naming scheme as it is informative, reliable,
+  and can work even if you access your data without Emacs).
+
+** For more advanced use-cases
+:PROPERTIES:
+:CUSTOM_ID: h:505c84dd-2959-4bd4-8af4-78d75592a6d5
+:END:
+
++ The variable ~denote-file-types~ has been tweaked to respond
+  directly to changes in its value done with ~setq~.  Thanks to Noboru
+  Ota for the patch: <https://lists.sr.ht/~protesilaos/denote/%3C86k05gsqsg.fsf%40nobiot.com%3E>.
+
+  Noboru has assigned copyright to the Free Software Foundation.
+
++ The =:front-matter= property of the ~denote-file-types~ now accepts
+  a nil value.  Denote could always work without front matter, but
+  this was not implemented flexibly in the ~denote-file-types~.
+  Thanks to Noboru Ota (nobiot) for pointing this out on the mailing
+  list: <https://lists.sr.ht/~protesilaos/denote/%3C86k05gsqsg.fsf%40nobiot.com%3E>.
+
++ The ~denote-file-prompt~ function now reads an optional
+  =INITIAL-TEXT= argument.  This is a string that prepopulates the
+  minibuffer.  It is useful for custom commands the user may have
+  where, for example, there is a need to automatically filter to
+  entries matching =_journal=.  Thanks to Alan Schmitt for suggesting
+  the idea: <https://lists.sr.ht/~protesilaos/denote/%3C87pmf676n1.fsf@m4x.org%3E>.
+
++ The ~denote-rename-file-using-front-matter~ accepts an optional
+  =AUTO-CONFIRM= argument.  It can either be passed interactively or
+  via Lisp.  The doc string (or the manual) explains the details.
+  Thanks to Elias Storms for the initial patch:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cm2a667aeku.fsf%40gmail.com%3E>.
+
++ The ~denote-prompt-for-date-return-id~ function uses the familiar
+  ~denote-date-prompt~ and returns the appropriate identifier.  It is
+  used internally by some of our function, but we also provide it for
+  anyone who wants to write their own custom code.
+
++ The ~denote-retrieve-or-create-file-identifier~ function reads and
+  option =DATE= argument to its mandatory =FILE= argument.  If =FILE=
+  does not have an identifier and optional =DATE= is non-nil, the
+  function invokes the ~denote-prompt-for-date-return-id~, as
+  mentioned above.
+
++ The ~denote-rename-file~ command accepts an optional =DATE=
+  argument.  It functionally does what is described right above, with
+  the exception that this is for an interactive function (a
+  "command").  Read the detailed doc string or the manual for
+  everything that pertains to this powerful command.
+
+  Thanks to Florian for suggesting the idea on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C166521684647.7.5483179875879361874.67576870%40aboulafia.org%3E>.
+
++ The ~denote-directory-text-only-files~ function filters the
+  ~denote-directory-files~ to only return a list of text files.  This
+  leaves out, say, mp3 files.  The function is used internally, though
+  it may also prove useful in custom user code.
+
+** Miscellaneous refinements
+:PROPERTIES:
+:CUSTOM_ID: h:0531047f-ef15-412e-b265-886c55526d57
+:END:
+
++ Implemented a ~revert-buffer-function~ for the backlinks' buffer,
+  which is produced by the command ~denote-link-backlinks~.  This
+  revert function is what the =g= key invokes with the default key
+  bindings (the command is ~revert-buffer~).  It produces the buffer
+  anew, updating the list of backlinks accordingly.
+
++ Documented how to speed up the creation of the backlinks' buffer.
+  As this depends on the built-in =xref= library, the change is done
+  by specifying the value of the user option ~xref-search-program~ in
+  Emacs 28 or higher.  For example:
+
+  #+begin_src emacs-lisp
+  (setq xref-search-program 'ripgrep)
+  #+end_src
+
+  For something more elaborate:
+
+  #+begin_src emacs-lisp
+  ;; Prefer ripgrep, then ugrep, and fall back to regular grep.
+  (setq xref-search-program
+        (cond
+         ((or (executable-find "ripgrep")
+              (executable-find "rg"))
+          'ripgrep)
+         ((executable-find "ugrep")
+          'ugrep)
+         (t
+          'grep)))
+  #+end_src
+
++ Removed some minor duplication of effort in how the buttonisation of
+  links is done (what makes them clickable).
+
++ Made refinements to the definition of functions such as
+  ~denote-link-add-links~.  There should be no noticeable change for
+  users, though this shows we care about code quality.
+
++ With Eshel Yaron, we tried to remove the empty indices for functions
+  and variables from the HTML version of the manual.  These indices
+  are useful in the Info version, which can be accessed directly from
+  Emacs when the =denote= package is installed (for example, evaluate
+  =(info "(denote) Top")=), but they do not work with HTML.  Alas,
+  what we tried to do did not work.  Maybe Org has a way to control
+  what is exported where.  We shall see.  At any rate, thanks to Eshel
+  for the effort: <https://lists.sr.ht/~protesilaos/denote/patches/36028>.
+
++ All code that integrates the =denote:= custom hyperlink type with
+  Org's link facility is now assigned =autoload= cookies.  These are
+  done to ensure that =denote= is loaded and is available in cases
+  where Org needs to access a =denote:= link at some early stage
+  (e.g. at startup before using Denote).  Thanks to Sven Seebeck for
+  reporting the problem: <https://lists.sr.ht/~protesilaos/denote/%3C87r0zovwix.fsf%40svenseebeck.me%3E>.
+  Although Sven could not reproduce a bug reliably, I believe this
+  prevents such an eventuality.
+
++ Expanded or otherwise updated the manual to account for all of the
+  above, where appropriate.
+
+* Version 1.0.0 on 2022-09-30
+:PROPERTIES:
+:CUSTOM_ID: h:053975d7-3fe2-49e5-96a0-336483e5861c
+:END:
+
+This is the first major release of Denote.  A part of the changes
+documented herein is for advanced users or developers who wish to
+extend Denote with their custom code.  Though we first cover what
+applies to everyone.
+
+** Changes for all users
+:PROPERTIES:
+:CUSTOM_ID: h:25692d4f-08da-4938-a81e-54070d91f51a
+:END:
+
++ The custom Org hyperlink type of =denote:= can be visited from
+  outside the ~denote-directory~.  We now provide the necessary glue
+  code that Org needs to store these =denote:= links.  Storing them
+  can be done with an ~org-capture~ template or via the command
+  ~org-store-link~.  Use this to, for example, capture a TODO that
+  references one of your notes.
+
+  =denote:= links work for as long as the referenced file is somewhere
+  in the ~denote-directory~ or one of its subdirectories.
+
+  Thanks to Marc Fargas for the contribution.  Marc did not need to
+  assign copyright to the Free Software Foundation, as the patch was
+  within the ~15 line limit that is permissible.
+
+  The contribution was discussed on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/patches/35137>.  A prior
+  exchange took place in issue 104 over at the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/104>.
+
+  Some further tweaks were made to the relevant function.  Thanks to
+  Elias Storms for reporting on the mailing list a bug which revealed
+  a regression I introduced to the Org link storing mechanism:
+  <https://lists.sr.ht/~protesilaos/denote/%3C15D55F4B-64D1-4083-AD5E-B5BACA8F1909%40ap.be%3E>.
+
++ Following from above, the command ~denote-link-find-file~ finds
+  files reliably, regardless of where the link is stored.  All it
+  needs is for the target file to be inside the ~denote-directory~.
+
+  I discovered this while exchanging views with Marc Fargas regarding
+  the aforementioned patch: <https://lists.sr.ht/~protesilaos/denote/patches/35137>.
+
++ The command ~denote-link-buttonize-buffer~, which "buttonizes"
+  =denote:= links in plain text and Markdown files, now performs its
+  task regardless of where the current file is stored.  Those links
+  work for as long as the file they reference is somewhere inside the
+  ~denote-directory~.
+
++ The commands ~denote-link-after-creating~, ~denote-link-or-create~
+  provide a convenience for users who need to create link to notes
+  that may not exist yet.  The idea is that one is expounding on a
+  given topic and wants to create a link to a relevant issue.  They
+  are not sure if they have written anything about it yet, so they
+  invoke the relevant command.  Consult their doc strings or read the
+  manual: <https://protesilaos.com/emacs/denote#h:9e41e7df-2aac-4835-94c5-659b6111e6de>.
+
+  Thanks to user sienic for suggesting the idea and for testing the
+  prototypes.  And thanks to Juanjo Presa for participating in the
+  discussion to share the view that this functionality should be part of
+  denote.el.  This happened in issue 96 over at the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/96>.
+
++ The command ~denote-open-or-create~ offers the convenience of
+  visiting a file, if it exists, else prompting for its creation.
+  Thanks to Alan Schmitt for the contribution.  The patch was sent on
+  the mailing list: <https://lists.sr.ht/~protesilaos/denote/%3C87fsgvddny.fsf%40protesilaos.com%3E>.
+  It is within the limit of what is allowed without assigning
+  copyright to the Free Software Foundation, though Alan has done the
+  relevant paperwork.
+
++ The manual expands on two sections: (1) Variants of
+  ~denote-open-or-create~, (2) Variants of ~denote-link-or-create~.
+  They show how one can use the above "do or create" commands with
+  different permutations of the Denote prompts for new note creation.
+
++ The manual includes a section titled "Create a note with the
+  region's contents".  Quote:
+
+  #+begin_quote
+  Sometimes it makes sense to gather notes in a single file and later
+  review it to make multiple notes out of it.  With the following
+  code, the user marks a region and then invokes the command
+  ~my-denote-create-new-note-from-region~: it prompts for a title and
+  keywords and then uses the region's contents to fill in the newly
+  created note.
+  #+end_quote
+
+  This is not part of denote.el, though we provide it in the manual
+  for users that may need it.  Thanks to sundar bp for suggesting the
+  idea.  This was done via a private channel and the information is
+  shared with permission.
+
++ The manual has another entry titled "Split an Org subtree into its
+  own note", which is similar to the above idea of using the region's
+  contents but has some extra niceties provided by Org.  Quote:
+
+  #+begin_quote
+  With Org files in particular, it is common to have nested headings which
+  could be split off into their own standalone notes.  In Org parlance an
+  entry with all its subheadings is a "subtree".  With the following code,
+  the user places the point inside the heading they want to split off and
+  invokes the command ~my-denote-split-org-subtree~.  It will create a
+  note using the heading's text and tags for the new file.  The contents
+  of the subtree become the contents of the new note and are removed from
+  the old one.
+  #+end_quote
+
+  Thanks to Sven Seebeck for suggesting the idea and for testing my
+  prototypes.  This information is shared with permission, as it was
+  provided via a private channel.
+
++ The manual describes how a user can leverage the built-in
+  ~dired-virtual-mode~ to perform arbitrary sorting of their list of
+  notes.  It also includes code for Eshell to quickly "export" a
+  command's output into a dedicated buffer (which can then be used to
+  derive a "virtual" Dired).  Thanks to Yi Liu for asking the question
+  that inspired this entry:
+  <https://lists.sr.ht/~protesilaos/denote/%3C1C75FF01-EC76-49DF-9AEB-ED718A2795FF@gmail.com%3E>.
+
++ The ~denote-faces-broken-link~ has been removed.  It was used for
+  Org links.  The idea was to apply a different style if the link was
+  broken.  However, the way fontification works means that there may
+  be a performance penalty as Org tries to check again and again if
+  the link is broken or note.  As =denote:= links are robust (unless
+  the user tries to break them), this penalty is unacceptable.  Thanks
+  to Peter Prevos for reporting the issue and discussing it with me on
+  the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C87k05umyyo.fsf%40prevos.net%3E>.
+
++ The "denote" group in Custom UI buffers now provides a link to the
+  Info manual that is shipped with the package.  To read the manual,
+  evaluate =(info "(denote) Top")=.  Else visit the official web page:
+  <https://protesilaos.com/emacs/denote>.
+
++ Fixed a case where an internal check for a note would throw an error
+  if the buffer was not visiting a file.  Thanks to Hilde Rhyne was
+  the patch: it is below the ~15 line threshold and thus does not
+  require copyright assignment to the Free Software Foundation.  The
+  issue was discussed on the mailing list and was pushed to users as
+  version =0.6.1=:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cm035d7nq22.fsf%40disroot.org%3E>.
+
++ When linking to a file that has no front matter, Denote tries to use
+  the TITLE component of the file name (per our file-naming scheme) as
+  the link's descriptive text.  We now make this look a bit better, by
+  capitalising only the first letter while dehyphenating the text,
+  converting =this-is-a-test= to =This is a test=.  Before, we would
+  capitalise all words.  Thanks to Clemens Radermacher for the patch.
+  It was sent via a private channel.  Clemens has assigned copyright
+  to the Free Software Foundation.
+
+** Changes for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:165cd056-5e27-4536-b8ac-57f88c927a43
+:END:
+
+Lots of functions and variables which once were for "private" use (the
+presence of double hyphens in the symbol) are now made public.
+Concretely this means that they no longer have double hyphens in their
+name and we pledge to support them henceforth.  "Support" means that
+we (i) consider them stable, (ii) document them properly, (iii) will
+record any changes made to them such as in a change log, a blog post
+on my website, and via ~make-obsolete~.
+
+The manual provides a complete reference of what is on offer.  The
+section is titled "For developers or advanced users":
+<https://protesilaos.com/emacs/denote#h:c916d8c5-540a-409f-b780-6ccbd90e088e>.
+
+Normally, we do not support private forms and can delete/modify them
+without notice.  However, I decided to write obsoletion aliases for
+all forms I made public or otherwise revised, in an effort not to
+break any existing custom code.  The following table covers all
+obsolete symbols and their new counterparts.  PLEASE UPDATE YOUR CODE
+as those aliases will be removed in the near future.
+
+| Index | Old symbol                                     | New symbol                                        |
+|-------+------------------------------------------------+---------------------------------------------------|
+|     1 | denote--id-format                              | denote-id-format                                  |
+|     2 | denote--id-regexp                              | denote-id-regexp                                  |
+|     3 | denote--title-regexp                           | denote-title-regexp                               |
+|     4 | denote--keywords-regexp                        | denote-keywords-regexp                            |
+|     5 | denote--punctuation-regexp                     | denote-excluded-punctuation-regexp                |
+|     6 | denote-punctuation-excluded-extra-regexp       | denote-excluded-punctuation-extra-regexp          |
+|     7 | denote--sluggify                               | denote-sluggify                                   |
+|     8 | denote--sluggify-and-join                      | denote-sluggify-and-join                          |
+|     9 | denote--sluggify-keywords                      | denote-sluggify-keywords                          |
+|    10 | denote--desluggify                             | denote-desluggify                                 |
+|    11 | denote--only-note-p                            | denote-file-is-note-p                             |
+|    12 | denote--file-has-identifier-p                  | denote-file-has-identifier-p                      |
+|    13 | denote--file-supported-extension-p             | denote-file-has-supported-extension-p             |
+|    14 | denote--writable-and-supported-p               | denote-file-is-writable-and-supported-p           |
+|    15 | denote--file-name-relative-to-denote-directory | denote-get-file-name-relative-to-denote-directory |
+|    16 | denote-link--id-from-string                    | denote-extract-id-from-string                     |
+|    17 | denote--directory-files                        | denote-directory-files                            |
+|    18 | denote--subdirs                                | denote-directory-subdirectories                   |
+|    19 | denote--get-note-path-by-id                    | denote-get-path-by-id                             |
+|    20 | denote--directory-files-matching-regexp        | denote-directory-files-matching-regexp            |
+|    21 | denote--retrieve-read-file-prompt              | denote-file-prompt                                |
+|    22 | denote--extract-keywords-from-path             | denote-extract-keywords-from-path                 |
+|    23 | denote--keywords-prompt                        | denote-keywords-prompt                            |
+|    24 | denote--retrieve-filename-identifier           | denote-retrieve-filename-identifier               |
+|    25 | denote--file-name-id                           | denote-retrieve-or-create-file-identifier         |
+|    26 | denote--retrieve-filename-title                | denote-retrieve-filename-title                    |
+|    27 | denote--retrieve-title-value                   | denote-retrieve-title-value                       |
+|    28 | denote--retrieve-title-line                    | denote-retrieve-title-line                        |
+|    29 | denote--retrieve-keywords-value                | denote-retrieve-keywords-value                    |
+|    30 | denote--retrieve-keywords-line                 | denote-retrieve-keywords-line                     |
+|    31 | denote--format-file                            | denote-format-file-name                           |
+|    32 | denote--barf-duplicate-id                      | denote-barf-duplicate-id                          |
+|    33 | denote--title-prompt                           | denote-title-prompt                               |
+|    34 | denote--file-type-prompt                       | denote-file-type-prompt                           |
+|    35 | denote--date-prompt                            | denote-date-prompt                                |
+|    36 | denote--subdirs-prompt                         | denote-subdirectory-prompt                        |
+|    37 | denote--template-prompt                        | denote-template-prompt                            |
+|    38 | denote--filetype-heuristics                    | denote-filetype-heuristics                        |
+|    39 | denote--rename-file                            | denote-rename-file-and-buffer                     |
+|    40 | denote--rename-file-prompt                     | denote-rename-file-prompt                         |
+
+If you are writing code that extends Denote and feel that something is
+either missing or has remained private, please contact us on the
+mailing list, the GitHub/GitLab mirror, or send me an email directly.
+I always respond in a timely fashion.
+
+** Open to everyone
+:PROPERTIES:
+:CUSTOM_ID: h:27a391cf-8d5e-4d19-942f-46fc52dea80c
+:END:
+
+The most common feedback I get about Denote is that its documentation
+is good.  As you can tell from these change logs, the plan is to
+continue on this path.
+
+Please note that the communication channels for Denote (mailing list,
+mirrors, my personal email) are open to users of all levels.  Do not
+hesitate to contact us/me.
+
+Thanks again to everyone for their contributions, direct or indirect,
+either in the form of code or the discussion of ideas.  Quoting from
+the "Acknowledgements" section of the manual (all my packages have
+such a section):
+
+#+begin_quote
+Denote is meant to be a collective effort.  Every bit of help matters.
+
++ Author/maintainer :: Protesilaos Stavrou.
+
++ Contributions to code or the manual :: Abin Simon, Alan Schmitt,
+  Benjamin Kästner, Clemens Radermacher, Colin McLear, Damien Cassou,
+  Eshel Yaron, Hilde Rhyne, Jack Baty, Jean-Philippe Gagné Guay, Jürgen
+  Hötzel, Kaushal Modi, Kyle Meyer, Marc Fargas, Peter Prevos, Philip
+  Kaludercic, Quiliro Ordóñez, Stefan Monnier.
+
++ Ideas and/or user feedback :: Abin Simon, Alan Schmitt, Alfredo
+  Borrás, Benjamin Kästner, Colin McLear, Damien Cassou, Elias Storms,
+  Frank Ehmsen, Hanspeter Gisler, Jack Baty, Juanjo Presa, Kaushal
+  Modi, M. Hadi Timachi, Paul van Gelder, Peter Prevos, Shreyas
+  Ragavan, Summer Emacs, Sven Seebeck, Taoufik, Yi Liu, Ypot, atanasj,
+  hpgisler, pRot0ta1p, sienic, sundar bp.
+
+Special thanks to Peter Povinec who helped refine the file-naming
+scheme, which is the cornerstone of this project.
+
+Special thanks to Jean-Philippe Gagné Guay for the numerous
+contributions to the code base.
+#+end_quote
+
+* Version 0.6.0 on 2022-08-31
+:PROPERTIES:
+:CUSTOM_ID: h:50aba79a-d702-42b4-a2a5-7fa29033f904
+:END:
+
+Denote is in a stable state.  I consider it feature-complete, without
+prejudice to possible refinements to its existing feature set.  The next
+version shall be =1.0.0=.
+
+** User-facing changes
+:PROPERTIES:
+:CUSTOM_ID: h:566a770b-399e-47a6-9aa4-326fd6ade9a7
+:END:
+
++ The Denote linking facility can now link to any file that has the
+  Denote file-naming scheme.  Before, we limited this feature to what we
+  consider "note" files, else the supported plain text formats (per
+  ~denote-file-type~).  Thanks to Peter Prevos for the discussion on the
+  mailing list: <https://lists.sr.ht/~protesilaos/denote/%3C87fsi1m5ze.fsf%40prevos.net%3E>.
+
++ Date prompts may optionally use the familiar Org date-selection
+  mechanism that leverages the calendar.  This feature is subject to the
+  user option ~denote-date-prompt-use-org-read-date~.  A date prompt is
+  used by the ~denote-date~ command or, optionally, by the ~denote~
+  command when the user option ~denote-prompts~ is configured
+  accordingly.  The manual elaborates on the specificities.  Thanks to
+  Jean-Philippe Gagné Guay for the contribution in pull request 97 at
+  the GitHub mirror: <https://github.com/protesilaos/denote/pull/97>.
+
++ Leading empty spaces at the ~denote~ =TITLE= prompt no longer produce
+  hyphens: they are simply ignored to keep file names consistent.
+  Thanks to Peter Prevos for the contribution in pull request 99 at the
+  GitHub mirror: <https://github.com/protesilaos/denote/pull/99>.
+
+  [ Peter has started the process for copyright assignment to the Free
+    Software Foundation, though the total contributions are still within
+    the permitted boundaries. ]
+
++ When linking to files that have no front matter, the link's anchor
+  text (the human-readable part) is derived from the file name =TITLE=
+  component.  We apply a de-hyphenation and capitalisation of its
+  constituent words.  This is not always perfect, but it is better than
+  something like =this-is-the-title=.  Thanks to Peter Prevos for the
+  original idea in pull request 93 at the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/93>.
+
++ The active region is now used as the default value of the ~denote~
+  command =TITLE= prompt.  The idea behind this Do-What-I-Mean-flavoured
+  patch is to be able to take a note about a subject that appears in a
+  buffer by simply marking it before invoking the ~denote~ command.
+
+  Thanks to Eshel Yaron for the patch: <https://lists.sr.ht/~protesilaos/denote/patches/34870>.
+  It is below the ~15 line threshold that thus requires no copyright
+  assignment to the Free Software Foundation.
+
++ The ~denote-rename-file-using-front-matter~ command now offers to save
+  the buffer if appropriate.  In the past, it would simply produce an
+  error asking the user to save the buffer.  Thanks to Peter Prevos for
+  the contribution in pull request 103 at he GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/103>.
+
++ Fixed the text of the confirmation prompt in the command
+  ~denote-migrate-old-markdown-yaml-tags~.  Thanks to Abin Simon for the
+  patch: <https://lists.sr.ht/~protesilaos/denote/patches/34632>.
+
+  This patchset also fixes (i) how a tag is identified for the purposes
+  of migrating old to new front matter, (ii) the regular expression for
+  Org front matter keywords
+
+  [ The total changes are below the ~15 line threshold and thus do not
+    require copyright assignment to the Free Software Foundation. ]
+
++ Fixed a bug that prevented the creation of new notes.  Thanks to
+  Juergen Hoetzel for the contribution in pull request 84 at the GitHub
+  mirror: <https://github.com/protesilaos/denote/pull/84>.  This was
+  done immediately after the release of version =0.5.0= on 2022-08-10
+  and was provided to users as version =0.5.1=
+
+  [ The change is below the ~15 line threshold. ]
+
+** Internal refinements
+:PROPERTIES:
+:CUSTOM_ID: h:9374b533-faaa-4ab4-b668-f74b5eae7ab5
+:END:
+
+These make the code simpler and more predictable.  As the individual
+changes are not user-facing, I invite interested parties to consult the
+Git log.  Special thanks to Jean-Philippe Gagné Guay for the multiple
+contributions (and relevant discussions) over at the GitHub mirror:
+
+- <https://github.com/protesilaos/denote/pull/88>
+- <https://github.com/protesilaos/denote/pull/89>
+- <https://github.com/protesilaos/denote/pull/91>
+- <https://github.com/protesilaos/denote/pull/94>
+- <https://github.com/protesilaos/denote/pull/101>
+- <https://github.com/protesilaos/denote/pull/102>
+
+[ Jean-Philippe has assigned copyright to the Free Software Foundation.
+  It is required for non-trivial changes. ]
+
+** For advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:c6fc05a2-ff31-4a0c-91a1-f64d2cfd6a16
+:END:
+
+The variable ~denote-file-types~ is an alist of plists which
+substantiates the supported file types (per the user option
+~denote-file-type~).  Properties pertain to the formatting of front
+matter and the retrieval of relevant values.  The doc string of
+~denote-file-types~ explains the details, while the default value uses
+the ancillary functions we define.  Thanks to Jean-Philippe Gagné Guay
+for the relevant contributions in pull request 89 at the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/89>.
+
+
+* Version 0.5.0 on 2022-08-10
+:PROPERTIES:
+:CUSTOM_ID: h:80b9daaa-c3c8-4457-b109-966bb6a99832
+:END:
+
+The general theme of this release is to refine what we already offer.
+As I explained in some discussions, Denote is feature-complete.  We can
+always improve the code or add some ancillary function/command/variable,
+though all the main ideas have already been implemented.  Additional
+functionality can be provided by other packages: I remain at the
+disposal of anyone willing to write such a package.
+
+The present release covers more than 150 commits since version 0.4.0 on
+2022-07-25.
+
+All release notes: <https://protesilaos.com/emacs/denote-changelog>.
+
+** Templates for new notes
+:PROPERTIES:
+:CUSTOM_ID: h:0878125f-8392-48e6-aeff-1469eb1e18fc
+:END:
+
+We now provide the ~denote-templates~ user option.  A "template" is
+arbitrary text that Denote will add to a newly created note right below
+the front matter.
+
+Templates are expressed as a =(KEY . STRING)= association.
+
+- The =KEY= is the name which identifies the template.  It is an
+  arbitrary symbol, such as =report=, =memo=, =statement=.
+
+- The =STRING= is ordinary text that Denote will insert as-is.  It can
+  contain newline characters to add spacing.  The manual of Denote
+  contains examples on how to use the ~concat~ function, beside writing
+  a generic string:
+  <https://protesilaos.com/emacs/denote#h:f635a490-d29e-4608-9372-7bd13b34d56c>.
+
+The user can choose a template either by invoking the new command
+~denote-template~ or by changing the user option ~denote-prompts~ to
+always prompt for a template when calling the ~denote~ command.
+
+Thanks to Jean-Philippe Gagné Guay for refinements to this facility.
+Done in pull request 77 on the GitHub mirror:
+<https://github.com/protesilaos/denote/pull/77>.
+
+[ Jean-Philippe has assigned copyright to the Free Software Foundation. ]
+
+** Revised format for Org =#+filetags= entry
+:PROPERTIES:
+:CUSTOM_ID: h:17688b79-cb1b-4a59-831e-fbf2a81245d3
+:END:
+
+Denote used to format tags in Org files by separating them with two
+spaces:
+
+#+begin_example
+#+filetags:  tag1  tag2
+#+end_example
+
+While this worked for some obvious use-cases, it is not supported by
+Org.  The Org documentation stipulates that tags be separated by the
+colon sign.  The above would then be written thus:
+
+#+begin_example
+#+filetags:  :tag1:tag2:
+#+end_example
+
+Denote now conforms with Org's specifications.  To help users update
+their existing notes, we provide the ~denote-migrate-old-org-filetags~
+command.  It will perform the conversion in all Org files that had the
+old notation.  As with all Denote operations that rewrite file contents,
+it DOES NOT SAVE BUFFERS.  The user is expected to review the changes,
+such as by using ~diff-buffer-with-file~.  Multiple buffers can be saved
+with ~save-some-buffers~ (check its doc string).
+
+This command is provided for the convenience of the user.  It shall be
+deprecated and eventually removed from future versions of Denote.
+
+If you need help with any of this, please do not hesitate to contact me
+either in private or in one of Denote's official channels (mailing list,
+GitHub/GitLab mirror).
+
+Thanks to Alan Schmitt for bringing this matter to my attention:
+<https://lists.sr.ht/~protesilaos/denote/%3C871qu0jw5l.fsf%40protesilaos.com%3E>.
+Also thanks to Jean-Philippe Gagné Guay for commenting on it as it
+helped me decide to include the command in =denote.el=:
+<https://github.com/protesilaos/denote/pull/83#issuecomment-1210167133>.
+
+** Revised format for Markdown+YAML =tags:= entry
+:PROPERTIES:
+:CUSTOM_ID: h:205a09cf-0159-425e-a6b3-41700fa3ad31
+:END:
+
+This is the same idea as above.  Before, we were making the mistake of
+using incorrect YAML notation:
+
+#+begin_src yaml
+tags:  tag1  tag2
+#+end_src
+
+Now we do:
+
+#+begin_src yaml
+tags:  ["tag1", "tag2"]
+#+end_src
+
+This is how the TOML variant always worked.
+
+For the user's convenience, we provide a command to migrate from the old
+to the new syntax: ~denote-migrate-old-markdown-yaml-tags~.
+
+** Changes to file renaming and front matter rewriting
+:PROPERTIES:
+:CUSTOM_ID: h:15ecb4e8-d1ce-4e42-b74d-a3a046d93220
+:END:
+
+Denote adds "front matter" to newly created notes which includes data
+such as the title and keywords/tags of the document.  Strictly speaking,
+the front matter is not required by Denote.  It is provided for the
+user's convenience, such as for readability or if they want to use the
+note with other programs (e.g. Org export, a blog with Hugo/Jekyll,
+...).
+
+Denote provides commands which help the user rename their notes, by
+changing the file name's =TITLE= and/or =KEYWORDS= components (per
+Denote's file-naming scheme).  These commands also operate on the front
+matter to keep the data between file name and file contents in sync
+(again, for the user's convenience).
+
+For this release we have consolidated and refined our offerings in order
+to improve their ergonomics.  All changes are the result of fruitful
+discussions on the mailing list and the issue tracker of the GitHub
+mirror:
+
+- <https://lists.sr.ht/~protesilaos/denote/%3C87k081l6vw.fsf%40silverstone.mail-host-address-is-not-set%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C878rogw5kk.fsf%40protesilaos.com%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C87fsiljv1s.fsf%40hu.mail-host-address-is-not-set%3E>
+- <https://lists.sr.ht/~protesilaos/denote/%3C87r122afe3.fsf%40hu.mail-host-address-is-not-set%3E>
+- <https://github.com/protesilaos/denote/issues/74>
+
+Thanks to (A-Z) Hanspeter Gisler, Jean-Philippe Gagné Guay, and Peter
+Prevos for their participation.
+
+Also thanks to Jean-Philippe Gagné Guay for relevant code contributions
+(please consult the Git log for the minutiae):
+
+- <https://github.com/protesilaos/denote/pull/66>
+- <https://github.com/protesilaos/denote/pull/67>
+- <https://github.com/protesilaos/denote/pull/69>
+- <https://github.com/protesilaos/denote/pull/75>
+- <https://github.com/protesilaos/denote/pull/76>
+
+*** Renaming a single file
+:PROPERTIES:
+:CUSTOM_ID: h:1d695e54-1481-42dd-916b-c0542c48aa6f
+:END:
+
+The commands ~denote-dired-rename-file-and-add-front-matter~ and
+~denote-dired-rename-file~ are deprecated and superseded by the new
+~denote-rename-file~.  Please update any key bindings in your setup.
+
+The difference between the old commands and the new ~denote-rename-file~
+is that the latter will now insert front matter to supported file types
+(per ~denote-file-type~) if they have none.  This basically means that,
+e.g., renaming a generic Org/Markdown/Plain text file with
+~denote-rename-file~ will update its file name to comply with Denote's
+file-naming scheme and also add the appropriate front matter (it
+"converts" it to a Denote note).  If front matter exists, this command
+will rewrite it to reflect the changes to the file name's =TITLE= and/or
+=KEYWORDS=.
+
+Consult the manual for the details:
+<https://protesilaos.com/emacs/denote#h:7cc9e000-806a-48da-945c-711bbc7426b0>.
+
+Or, if the new version of the GNU ELPA package is installed, evaluate:
+
+#+begin_src emacs-lisp
+(info "(denote) Rename a single file")
+#+end_src
+
+The user option ~denote-dired-rename-expert~ is obsolete.  Denote always
+asks for confirmation when renaming a single file.  This is because the
+user can rely on batch-renaming commands which ask for confirmation only
+once per batch.
+
+*** Renaming multiple files at once
+:PROPERTIES:
+:CUSTOM_ID: h:82455fb4-576b-4753-af66-ac48fd158327
+:END:
+
+The command ~denote-dired-rename-marked-files-and-add-front-matter~ is
+deprecated and its functionality is absorbed by the existing
+~denote-dired-rename-marked-files~ command.  The deprecated command was
+used to insert front matter to supported file types (per
+~denote-file-type~) that had none.  We now handle this internally, thus
+streamlining the experience for the user.
+
+Refer to the manual for the details:
+<https://protesilaos.com/emacs/denote#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde>
+
+Assuming the latest Info manual is installed, evaluate:
+
+#+begin_src emacs-lisp
+(info "(denote) Rename multiple files at once")
+#+end_src
+
+*** Renaming a single file based on its front matter
+:PROPERTIES:
+:CUSTOM_ID: h:d913e369-9325-46c4-985b-cf5b3e35372b
+:END:
+
+Introduced the ~denote-rename-file-using-front-matter~ command.  This is
+new functionality we provide which uses the front matter as input to
+perform a rename of the file.  The aforementioned offerings prompt for
+input via the minibuffer and propagate the changes firstly to the file
+name and subsequently to the front matter.  Whereas with the command
+~denote-rename-file-using-front-matter~, the user can edit the front
+matter manually and then invoke the command to pass the changes to the
+file name, subject to a confirmation.  Relevant entries are the title
+and tags/filetags (depending on the file type).  The date and the
+identifier are not pertinent.  Identifiers in file names are NEVER
+rewritten by Denote.
+
+Consult the manual:
+<https://protesilaos.com/emacs/denote#h:3ab08ff4-81fa-4d24-99cb-79f97c13a373>.
+
+With the latest package, evaluate:
+
+#+begin_src emacs-lisp
+(info "(denote) Rename a single file based on its front matter")
+#+end_src
+
+*** Renaming multiple files based on their front matter
+:PROPERTIES:
+:CUSTOM_ID: h:4efc6c14-fd71-4bd8-8bb1-e8e720b98eff
+:END:
+
+The command ~denote-dired-rename-marked-files-using-front-matter~
+completes the set of features we provide for syncing between file name
+and front matter.  It applies to all marked files in a Dired buffer.
+
+Read the manual to understand how the command works and what it does
+exactly: <https://protesilaos.com/emacs/denote#h:ea5673cd-e6ca-4c42-a066-07dc6c9d57f8>.
+
+Or evaluate:
+
+#+begin_src emacs-lisp
+(info "(denote) Rename multiple files based on their front matter")
+#+end_src
+
+*** Add missing front matter on demand
+:PROPERTIES:
+:CUSTOM_ID: h:32a103be-71a2-48e4-a18e-7727c04545ed
+:END:
+
+Sometimes the user may have incomplete front matter, perhaps due to a
+mistake that was saved on disk.  The command ~denote-add-front-matter~
+appends a new front matter block to the current note.
+
+Read:
+<https://protesilaos.com/emacs/denote#h:54b48277-e0e5-4188-ad54-ef3db3b7e772>
+
+Or evaluate:
+
+#+begin_src emacs-lisp
+(info "(denote) Regenerate front matter")
+#+end_src
+
+** Faces for Denote links
+:PROPERTIES:
+:CUSTOM_ID: h:507fb46c-a2e9-48a7-8cd2-53c5fc73394d
+:END:
+
+We provide the ~denote-faces-link~ and the ~denote-faces-broken-link~.
+The latter is only relevant for Org, as Emacs' standard button mechanism
+does not have a way to apply a face dynamically.
+
+This is a change for themes/tinkerers who need to differentiate
+=denote:= links from other links.  Otherwise, the presentation is the
+same as before.
+
+Thanks to Peter Prevos for asking about it on the mailing list:
+<https://lists.sr.ht/~protesilaos/denote/%3C03618bb20d3eaba78c32cd0cb63bfc71%40prevos.net%3E>.
+
+** Use of XDG path in ~denote-directory~
+:PROPERTIES:
+:CUSTOM_ID: h:efa3049e-f1fa-48ff-af7d-d16edc677704
+:END:
+
+The default value of the ~denote-directory~ user option used to be
+=~/Documents/notes= (subject to some conversion via Elisp).  Denote now
+conforms with the freedesktop.org specifications by using the =XDG=
+directory for =DOCUMENTS= instead of =~/Documents=:
+<https://www.freedesktop.org/wiki/Software/xdg-user-dirs/>.
+
+Users who already bind the ~denote-directory~ are not affected by this
+change.  Same for those who do not tinker with =XDG= environment
+variables and/or do not use some exotic setup.
+
+Thanks to Philip Kaludercic for the patch:
+<https://lists.sr.ht/~protesilaos/denote/patches/34561#%3C20220809115824.43089-1-philipk@posteo.net%3E>
+
+** Bespoke major-mode for the backlinks' buffer
+:PROPERTIES:
+:CUSTOM_ID: h:feb9a0ed-ba15-486e-ae11-5b222b00bc31
+:END:
+
+The backlinks' buffer now uses the ~denote-backlink-mode~ instead of the
+generic ~special-mode~.  The former derives from the latter.  It binds
+keys to move between links with =n= (next) and =p= (previous).  These
+are stored in the ~denote-backlink-mode-map~ (use =M-x describe-mode=
+(=C-h m=) in an unfamiliar buffer to learn more about it).
+
+Thanks to Philip Kaludercic for the patch:
+<https://lists.sr.ht/~protesilaos/denote/patches/34561#%3C20220809115824.43089-2-philipk@posteo.net%3E>
+
+** Changes to the manual
+:PROPERTIES:
+:CUSTOM_ID: h:80217a39-86b8-4310-b7c4-dcc14e0b98fd
+:END:
+
++ Documented all of the aforementioned.  Improved how information is
+  presented and, generally, iterated on an already comprehensive
+  document.
+
++ Introduced a node which explains how to tweak the front matter:
+  <https://protesilaos.com/emacs/denote#h:7f918854-5ed4-4139-821f-8ee9ba06ad15>.
+  Or evaluate:
+
+  #+begin_src emacs-lisp
+  (info "(denote) Change the front matter format")
+  #+end_src
+
++ Updated the reference to =consult-notes=.  This is a package that uses
+  the =consult= interface to provide access and search facilities for
+  notes.  It can integrate with Denote.  Thanks to Colin McLear for the
+  change in pull request 70 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/70>.
+
+  [ The change is below the ~15 line threshold and thus does not require
+    copyright assignment to the Free Software Foundation. ]
+
+** Internal restructuring
+:PROPERTIES:
+:CUSTOM_ID: h:5d09d0af-3c25-4419-8448-90b8e1adab0d
+:END:
+
++ All Denote code is consolidated in =denote.el=.  We no longer maintain
+  separate files like =denote-link.el=, =denote-dired.el=, etc.  Users
+  who had ~require~ calls to such libraries must remove them and only
+  keep:
+
+  #+begin_src emacs-lisp
+  (require 'denote)
+  #+end_src
+
++ User options that have an entry in the manual will now provide a link
+  to it via their Help buffer and/or the Custom UI.  This is done by
+  adding the =:link= attribute to their declaration.
+
+  Furthermore, user options and faces now specify the version of Denote
+  that last affected their value (e.g. ~denote-directory~, which was
+  mentioned above for the XDG spec, now informs the user that it changed
+  for version =0.5.0=).
+
+  [ I learnt these by developing the =modus-themes=. ]
+
++ The variables ~denote-last-title~, ~denote-last-keywords~,
+  ~denote-last-buffer~, and ~denote-last-front-matter~ are all obsolete.
+  These were used prior to version =0.1.0= to help with development but
+  are now deemed surplus to requirements.
+
++ Lots of changes were made to private functions, variables, doc
+  strings, and comments, in the interest of simplifying the code and/or
+  ensuring consistency in how operations are carried out.  Though
+  everything is the same for the end-user.
+
+Thanks to Jean-Philippe Gagné Guay for the numerous contributions on the
+GitHub mirror.  They are important for Denote, though the user does not
+need to know what is happening internally (consult the Git log for the
+details):
+
+- <https://github.com/protesilaos/denote/pull/65>
+- <https://github.com/protesilaos/denote/pull/72>
+- <https://github.com/protesilaos/denote/pull/73>
+- <https://github.com/protesilaos/denote/pull/78>
+- <https://github.com/protesilaos/denote/pull/80>
+- <https://github.com/protesilaos/denote/pull/81>
+- <https://github.com/protesilaos/denote/pull/82>
+- <https://github.com/protesilaos/denote/pull/83>
+
+** Discussions
+:PROPERTIES:
+:CUSTOM_ID: h:79089c06-9e0c-49cc-9d53-a1a2fd72fb65
+:END:
+
+*** Encrypting Denote notes
+:PROPERTIES:
+:CUSTOM_ID: h:87e4556a-4864-4955-a98c-62b2e6a509c3
+:END:
+
+Paul van Gelder asked about this on the mailing list.  I provided
+guidelines on what can be done, though did not record anything in the
+manual: I prefer to elicit more feedback from users.  The gist is that
+Emacs already has all the requisite functionality, though encryption per
+se is outside the scope of Denote:
+<https://lists.sr.ht/~protesilaos/denote/%3C1123434736.64290.1658954014673%40kpc.webmail.kpnmail.nl%3E>.
+
+Denote's relevant internal mechanisms will recognise files ending in
+=.gpg= (e.g. for fontification in Dired).
+
+*** Visualise usage of Denote keywords
+:PROPERTIES:
+:CUSTOM_ID: h:d94ee5e3-0a54-404c-b44b-34edc3703fbc
+:END:
+
+Peter Prevos shared a proof-of-concept way to visualise keywords in the
+~denote-directory~ and show usage statistics:
+<https://lists.sr.ht/~protesilaos/denote/%3Ce9e5d6ae85984b51067b47f4d8e134fa%40prevos.net%3E>.
+
+We do not include this information in the manual, as we wait for the
+fully fledged code.  Though do give it a try if you are interested and,
+perhaps, share your thoughts for Peter's consideration.
+
+*** Conflict between ~denote-dired-mode~ and ~diredfl-mode~
+:PROPERTIES:
+:CUSTOM_ID: h:0cbf504c-676c-436e-8ae8-e7115368e691
+:END:
+
+Hilde Rhyne shared a workaround they have to disable ~diredfl-mode~ in
+the buffers where ~denote-dired-mode~ is enabled.  The conflict between
+the two is a known issue that is acknowledged in the manual:
+<https://lists.sr.ht/~protesilaos/denote/%3Cm0tu6q6bg0.fsf%40disroot.org%3E>.
+
+I think we need a proper solution in the code we provide, so this
+workaround is not mentioned in the manual.
+
+*** Why doesn't Denote provide a search facility?
+:PROPERTIES:
+:CUSTOM_ID: h:068108f4-a4fa-4ff8-be49-f1f10a862451
+:END:
+
+There was a discussion started by Fourchaux, with the participation of
+basaran and Andre0991 on the GitHub mirror:
+<https://github.com/protesilaos/denote/issues/71>.
+
+The gist of my answer is that Denote does not need to provide such a
+facility because notes are ordinary files: whatever the user already has
+for them should apply to Denote.  If the user has nothing to search
+through files, they anyhow need something that works outside the
+confines of Denote: a =denote-SEARCH= command is not an adequate
+solution.
+
+Emacs has numerous built-in commands, such as ~grep~ (~lgrep~ and
+~rgrep~), ~project-find-regexp~, ~find-grep-dired~, ~ibuffer-do-occur~,
+...  Furthermore, there are lots of high quality packages that have
+their own wrappers or extensions for searching file contents, such as
+the =ivy= and =helm= completion frameworks, as well as =consult= (the
+commands ~consult-grep~ and ~consult-ripgrep~), =consult-notes=, =rg=,
+=deadgrep=, =deft=, and probably plenty more that do not come to mind
+right now.
+
+I strongly encourage the user to find a universal search solution to the
+problem of searching file contents.
+
+* Version 0.4.0 on 2022-07-25
+:PROPERTIES:
+:CUSTOM_ID: h:1c8098ee-089c-4511-bc6a-4140aab01321
+:END:
+
++ Defined the ~denote-link-dired-marked-notes~ command.  It lets the
+  user produce a typographic list of links to the note files that are
+  marked in Dired.  The list is written at point.  If there are multiple
+  buffers which visit Denote notes, the command first prompts with
+  minibuffer completion for one among them.
+
+  In terms of workflow, ~denote-link-dired-marked-notes~ complements the
+  ~denote-link-add-links~ command for those cases where it is easier to
+  select files than write an elegant regular expression.
+
++ Implemented the ~denote-dired-rename-marked-files~ command.  This
+  provides a much-requested facility to perform the familiar renaming
+  operation on a set of files.  In particular:
+
+  - the file's existing file name is retained and becomes the =TITLE=
+    field, per Denote's file-naming scheme;
+
+  - the =TITLE= is sluggified and downcased, per our conventions;
+
+  - an identifier is prepended to the =TITLE=;
+
+  - the file's extension is retained;
+
+  - a prompt is asked once for the =KEYWORDS= field and the input is
+    applied to all file names;
+
+  - if the file is recognised as a Denote note, the command rewrites its
+    front matter to include the new keywords.  A confirmation to carry
+    out this step is performed once at the outset.  Note that the
+    affected buffers are not saved.  The user can thus check them to
+    confirm that the new front matter does not cause any problems
+    (e.g. with the command ~diff-buffer-with-file~).  Multiple buffers
+    can be saved with ~save-some-buffers~ (read its doc string).
+
+  Parts of ~denote-dired-rename-marked-files~ were added or refined over
+  a series of commits.  Consult the Git log for the minutia.  Thanks to
+  Jean-Philippe Gagné Guay for the relevant additions in pull requests
+  51 and 52 on the GitHub mirror:
+
+  - <https://github.com/protesilaos/denote/pull/51>
+  - <https://github.com/protesilaos/denote/pull/52>
+
+  Jean-Philippe has assigned copyright to the Free Software Foundation.
+
++ Improved how the ~denote-dired-rename-file~ command rewrites front
+  matter.  Before, it would perform a replacement of the whole block,
+  which had the adverse effect of overwriting custom front matter
+  entries.  Now, it only targets the lines which hold the title and
+  keywords, leaving everything else intact.  Thanks to Peter Prevos for
+  reporting the problem and testing the solution to it in issue 60 on
+  the GitHub mirror: <https://github.com/protesilaos/denote/issues/60>.
+
++ Introduced the ~denote-dired-rename-file-and-add-front-matter~ command
+  that always prepends front matter to a file whose extension is among
+  the supported ones (per the user option ~denote-file-type~).  This
+  differs from the standard ~denote-dired-rename-file~ command which
+  only rewrites the front matter's title and keywords if they exist.
+
+  In practice, ~denote-dired-rename-file-and-add-front-matter~ empowers
+  the user to convert a generic text file to a Denote note.
+
+  This command was originally added by Jean-Philippe Gagné Guay in pull
+  request 49 on the GitHub mirror and refined in subsequent commits:
+  <https://github.com/protesilaos/denote/pull/49>.  Also read issue 48
+  where this idea was originally discussed:
+  <https://github.com/protesilaos/denote/issues/48>.
+
++ Added the ~denote-dired-rename-marked-files-and-add-front-matters~
+  command, which is like the ~denote-dired-rename-marked-files~ but adds
+  front matter instead of rewriting existing one, just how the command
+  ~denote-dired-rename-file-and-add-front-matter~ does it (both are
+  mentioned above).  Thanks to Jean-Philippe Gagné Guay for the
+  refinements to it in pull request 53 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/53>.
+
++ Wrote an interactive spec for ~denote-link-buttonize-buffer~.  It can
+  now be invoked with =M-x= or a key binding, should the need arise.
+  This function is normally called via a hook and takes effect in plain
+  text as well as Markdown files.
+
++ Extended the fontification rules so that file names with non-ASCII
+  characters are styled properly.  This issue was brought up on the
+  mailing list by Frank Ehmsen and was discussed with the participation
+  of Peter Prevos:
+  <https://lists.sr.ht/~protesilaos/denote/%3C2273b3b1-344c-6c6e-3ab6-a227b6bc3721%40eh-is.de%3E>.
+
+  The same topic was raised at the same time on the GitHub mirror by
+  user hpgisler in issue 61:
+  <https://github.com/protesilaos/denote/issues/61>.
+
+  After some discussion, we agreed on the right approach, which was
+  formalised by Peter Prevos as pull request 64 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/pull/64>.  The change is below
+  the ~15 line threshold and thus does not require copyright assignment
+  to the Free Software Foundation.
+
++ Made the registration of the =denote:= custom Org hyperlink type
+  conditional on the availability of the ~org~ feature.  In other words,
+  those who do not use Org will not be loading this part of the code.
+  Thanks to Abin Simon for reporting the problem and for showing how
+  Elfeed handles this case.  This was done in issue 47 on the GitHub
+  mirror: <https://github.com/protesilaos/denote/issues/47>.
+
++ Ensured that duplicate keywords are not produced by the relevant
+  prompt.  Thanks to user Taoufik for the contribution in pull request
+  50 on the GitHub mirror: <https://github.com/protesilaos/denote/pull/50>.
+  The change is below the ~15 line threshold and thus does not require
+  copyright assignment to the Free Software Foundation.
+
++ Fixed a typo in the reference to the ~crm-separator~ in the manual.
+  David Wilson (System Crafters channel) spotted the error in a recent
+  live stream whose main topic was about Denote (thanks, by the way!):
+  <https://www.youtube.com/watch?v=QcRY_rsX0yY>.
+
++ Addressed an inconsistency in the command ~denote-link-find-file~
+  where it would not recognise links without a title in their format
+  (those can be inserted by passing a prefix argument (=C-u= by default)
+  to the commands that insert links, such as ~denote-link~).
+
++ Attached conditionality to the ~denote~ command's =SUBDIRECTORY=
+  argument, so that it does not create new file paths.  This is only
+  relevant for those who call ~denote~ from Lisp.  Interactive use is
+  the same as before.
+
++ Clarified that the user option ~denote-org-capture-specifiers~ can
+  accept arbitrary text in addition to the formatting specifiers that
+  Org's capture mechanism introduces.
+
++ Explained in the manual why ~denote-org-capture-specifiers~ is needed
+  instead of writing the capture template directly the way one normally
+  does.  The gist is that because our file names are derived dynamically
+  based on user input, we need to account for the sequence in which the
+  value of arguments is reified by ~org-capture~.
+
++ Refactored how notes are prepared internally.  Thanks to Jean-Philippe
+  Gagné Guay for the contribution in pull request 55 on the GitHub
+  mirror: <https://github.com/protesilaos/denote/pull/55>.
+
++ Declared the ~denote-punctuation-excluded-extra-regexp~ variable which
+  is, for the time being, targeted at experienced users.  Its purpose is
+  to extend what we consider "illegal" punctuation for the file name.
+  Thanks to pRot0ta1p for the feedback in issue 57 over at the GitHub
+  mirror: <https://github.com/protesilaos/denote/issues/57>.  Example
+  based on the input of pRot0ta1p:
+
+  #+begin_src emacs-lisp
+  (setq denote-punctuation-excluded-extra-regexp
+        "[『』〖〗{}「」【】〔〕[]()《》〈〉«»!#¥%…&"'*,。;:、?—]*")
+  #+end_src
+
+  The ideal is to make ~denote--punctuation-regexp~ work for all
+  scripts, but that may be unrealistic.
+
++ Clarified what the manual means by "attachments" to notes.  Those are
+  for Org, if the user resorts to the relevant Org mechanisms.  Denote
+  does not do any of that.
+
++ Revised the parsing of a date input as used in the ~denote-date~
+  command or related.  The idea is to turn =2020-01-15= into something
+  like =2020-01-15 16:19= by using the current time, so that the hour
+  and minute component is not left to =00:00= when the user does not
+  specify it explicitly.
+
+  This reduces the burden on the user who would otherwise need to input
+  the time value in order to avoid the error of duplicate identifiers in
+  the scenario where the same date is used more than once.
+
+  The change also addresses a difference between Emacs 28 and Emacs 29
+  where the former does not read dates without a time component.
+
+  Thanks to Peter Prevos for the feedback in issue 58 over at the GitHub
+  mirror: <https://github.com/protesilaos/denote/issues/58>.
+
++ Fixed compilation warnings in Emacs 29 about the format of doc strings
+  that need to output a literal single quote.  Thanks to Kyle Meyer for
+  the patch, which was sent on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/patches/34117>.
+
++ Fixed typo in the user option ~denote-prompts~ about the
+  ~crm-separator~.  Thanks to Kyle Meyer for the patch, which was sent
+  on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/patches/34116>.
+
++ Made the built-in =subr-x= library a runtime dependency, due to
+  complications with the ~when-let*~ form.  The problem was made
+  manifest in a renaming operation, though it was not about renaming per
+  se.  Thanks to hpgisler for reporting the problem in issue 62 and for
+  testing the proposed solution:
+  <https://github.com/protesilaos/denote/issues/62>.
+
++ Streamlined the use of the =seq= library instead of =cl-lib=, as we
+  were already using the former more heavily and there was no need for
+  the latter.  Thanks to Philip Kaludercic for pointing this out on the
+  emacs-devel mailing list:
+  <https://lists.gnu.org/archive/html/emacs-devel/2022-07/msg00838.html>.
+
++ Added a generic =README.md= file to placate the Git forges.  Neither
+  SourceHut nor GitHub/GitLab are fully compliant with the Org markup we
+  use in =README.org= (we use Org because it is easy to generate the
+  Info manual and HTML pages out of it).  SourceHut will not render the
+  file at all, while the others render it but do not parse it properly.
+
++ Made several other internal tweaks and refinements in the interest of
+  robustness and/or clarity.
+
++ Rewrote all relevant documentation.
+
+** Non-changes
+:PROPERTIES:
+:CUSTOM_ID: h:0ac79968-a575-4380-addc-d58cc2b5f627
+:END:
+
+The following are not part of any changes that were made during this
+release cycle, though they provide potentially interesting insight into
+the workings of the project.
+
++ Identifiers with milliseconds :: Denote's identifier format extends up
+  to seconds.  This is the product of years of experimentation and is,
+  in my opinion, the best compromise between usability/readability and
+  precision.  If a user produces two notes within a fraction of a
+  second, then yes they will have duplicate identifiers.  In principle,
+  there is no reason not to address this potential problem, provided we
+  do not compromise on Denote's file-naming scheme (making the
+  identifier less readable is a compromise).  We shall see what the best
+  course of action is.  Thanks to Felipe Balbi and Jean-Philippe Gagné
+  Guay for the discussion thus far in issue 54 on the GitHub mirror:
+  <https://github.com/protesilaos/denote/issues/54>.
+
++ Denote and evil-mode :: Users of evil-mode do not have to worry about
+  Denote, as we do not define any key bindings.  The manual includes
+  sample configuration, which proposes some key bindings, but that is
+  the user's prerogative.  Thanks to Saša Janiška and Alan Schmitt for
+  their participation on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C87czdxf1dz.fsf%40atmarama.ddns.net%3E>.
+
++ Denote and Citar :: Peter Prevos started developing a package that
+  connects Denote with Citar: <https://github.com/pprevos/denote-citar>.
+  The idea is to use notes as part of one's bibliography.  Discussions
+  which include sample code on how to leverage ~denote~ from Lisp:
+
+  - <https://lists.sr.ht/~protesilaos/denote/%3C6add8bc63cab0a557fa4b9919e025afc%40prevos.net%3E>
+  - <https://lists.sr.ht/~protesilaos/denote/%3C87r12d2w96.fsf%40protesilaos.com%3E>
+  - <https://lists.sr.ht/~protesilaos/denote/%3C87a69060q6.fsf%40protesilaos.com%3E>
+
++ Denote and graph of connections :: Saša Janiška asked whether Denote
+  will provide some way to visualise links between notes.  The answer is
+  negative.  Denote's scope is clearly delineated and its feature set is
+  largely complete (notwithstanding refinements to what we already
+  provide).  Peter Prevos is experimenting with some code that uses the
+  R language.  Any such facility will have to be implemented as a
+  separate package.  I remain at the disposal of anyone who needs help
+  with Denote's internals.  Thanks to the aforementioned fellows for
+  their participation on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C878roleze1.fsf%40atmarama.ddns.net%3E>.
+
++ Denote's scalability :: There was a discussion whether Denote will
+  work well with very large sets of files.  The short answer is that it
+  will work the same way Emacs and/or standard Unix tools do: good
+  enough!  If there are improvements to be made, which do not jeopardise
+  the principles of the project, we shall implement them without
+  hesitation.  Thanks to Saša Janiška and Peter Prevos for their
+  participation on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C87sfmtf7im.fsf%40atmarama.ddns.net%3E>.
+
++ Denote's minimum requirement of Emacs 27.2 :: We cannot depend on
+  Emacs 27.1 due to this message from the byte compiler:
+
+  : You should depend on (emacs "27.2") or the (org "9.3") package if you need `org-link-open-as-file'.
+
+  Depending on Org is not an option because Denote optionally works
+  without Org, so Emacs 27.2 is what we have to opt for.  If your
+  operating system does not provide this version in package format,
+  please petition its maintainers/providers to do so.  Thanks to
+  Alexander for asking about it on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C9ec818e6a7979efbb2f8b1f5a497665b%40purelymail.com%3E>.
+
+Finally, a mildly interesting piece of trivia: we have exceeded 600
+commits since the first day of the project's Git history on 2022-06-04
+(the actual history is much longer).  That averages to more than 10 per
+day!  I think things will slow down eventually.
+
+* Version 0.3.0 on 2022-07-11
+:PROPERTIES:
+:CUSTOM_ID: h:6864cfd4-d0be-4c89-b313-39ba6e892a03
+:END:
+
++ Fixed how references are analysed to produce the backlinks' buffer.
+  This should resolve the issue that some users faced where the
+  backlinks would not be produced.
+
+  The previous implementation would not yield the appropriate results if
+  (i) the value of the user option ~denote-directory~ was a "project"
+  per the built-in project.el and (ii) the link to the given entry was
+  from a subdirectory.  In short, the references were sometimes returned
+  as relative file paths, whereas they should always be absolute.
+  Thanks to Jean-Philippe Gagné Guay for the feedback in issue 42 over
+  at the GitHub mirror: <https://github.com/protesilaos/denote/pull/42>.
+
+  [ Jean-Philippe has assigned copyright to the Free Software
+    Foundation.  It is a prerequisite for contributing to core Emacs
+    and/or any package distributed via the official GNU ELPA. ]
+
++ Addressed a regression in the function ~denote-directory~ (this is the
+  function that normalises the variable of the same name) which
+  prevented it from returning an expanded file path.  This too
+  contributed to problems with the backlinking facility.  Thanks to
+  Jean-Philippe Gagné Guay for the contribution in pull request 44 over
+  at the GitHub mirror: <https://github.com/protesilaos/denote/pull/44>.
+
+  Also thanks to user pRot0ta1p for the relevant feedback in issue 43
+  (also on the mirror): <https://github.com/protesilaos/denote/issues/43>.
+  More thanks to Alfredo Borrás, Benjamin Kästner, and Sven Seebeck for
+  their comments in a related thread on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3CCA73E705-1194-4324-9962-70708C4C72E5%40zoho.eu%3E>.
+  These discussions showed we had a problem, which we managed to
+  identify.
+
++ Introduced the user option ~denote-prompts~ (read its doc string or
+  the relevant entry in the manual).  It governs how the standard
+  ~denote~ command for creating new notes will behave in interactive
+  usage.  By default, ~denote~ prompts for a title and keywords.  With
+  ~denote-prompts~, the command can also ask for a file type (per
+  ~denote-file-type~), subdirectory of the ~denote-directory~, and a
+  specific date+time.  Prompts occur in the order they are specified.
+  Furthermore, the ~denote-prompts~ can be set to values which do not
+  include the title and keywords.  This means that the resulting file
+  names can be any of those permutations:
+
+  : DATE.EXT
+  : DATE--TITLE.EXT
+  : DATE__KEYWORDS.EXT
+
+  Recall that Denote's standard file-naming scheme is defined as follows
+  (read the manual for the details):
+
+  : DATE--TITLE__KEYWORDS.EXT
+
+  For our purposes, Denote will work perfectly fine for linking and
+  backlinking, even if file names do not include the =TITLE= and
+  =KEYWORDS= fields.  However, the user is advised to consider the
+  implications on usability: notes without a descriptive title and/or
+  useful keywords may be hard to filter and practically impossible to
+  manage at scale.  File names without such information should at least
+  be added to subdirectories which themselves have a descriptive name.
+
+  At any rate, Denote does not have strong opinions about one's
+  workflow.  The standard file name is the culmination of years of
+  experience.
+
+  Consider the ~denote-prompts~ the affirmative answer to the question
+  "Can keywords be optional?" as posed by Jack Baty on the mailing list:
+  <https://lists.sr.ht/~protesilaos/denote/%3C8D392BC3-980A-4E5B-9480-D6A00BE8279F%40baty.net%3E>.
+
+  Thanks to Jean-Philippe Gagné Guay for the original contribution in
+  commit 9b981a2.  It was originally part of a pull request, but due to
+  some internal changes I had to merge it as a patch and technically the
+  web UI did not count the PR as "merged" (though it was in terms of
+  substance).
+
++ Refactored the ~denote~ command to (i) accommodate the new user option
+  ~denote-prompts~ via its interactive specification and (ii) be more
+  flexible when called from Lisp.  The latter scenario is for advanced
+  users or, generally, those who can maintain some custom code in their
+  configuration.  A case in point is one of the examples we show in the
+  manual for a programmatic way to create notes that automatically get
+  the =journal= tag:
+
+  #+begin_src emacs-lisp
+  (defun my-denote-journal ()
+    "Create an entry tagged 'journal', while prompting for a title."
+    (interactive)
+    (denote
+     (denote--title-prompt)
+     '("journal")))
+  #+end_src
+
+  Notice that the ='("journal")= is a list of strings even for a single
+  keyword.  Whereas before a single one was a plain string.  This is a
+  breaking change.
+
+  Please consult the doc string of the ~denote~ command for the
+  technicalities.
+
++ Refashioned the interactive convenience functions of ~denote-type~,
+  ~denote-date~, ~denote-subdirectory~ to leverage the ~denote-prompts~
+  user option while calling ~denote~ interactively.  In practical terms,
+  they no longer accept any arguments when called from Lisp.  Users who
+  need a programmatic approach are advised to either call ~denote~
+  directly, or check how these commands ~let~ bind the ~denote-prompts~
+  to carry out their operations.  The doc string of each command
+  explains how it works.  Or evaluate this to check the manual:
+
+  #+begin_src emacs-lisp
+  (info "(denote) Convenience commands for note creation")
+  #+end_src
+
+  Else visit:
+  <https://protesilaos.com/emacs/denote#h:887bdced-9686-4e80-906f-789e407f2e8f>
+
++ Documented how the user option ~denote-directory~ can accept a local
+  value.  This is pertinent to scenaria where the user needs to maintain
+  separate directories of notes.  By "separate" we mean sets of notes
+  that do not communicate with each other, cannot create links between
+  them, etc.  The manual delves into the technicalities.  If you have
+  the Info entry installed, evaluate:
+
+  #+begin_src emacs-lisp
+  (info "(denote) Maintain separate directories for notes")
+  #+end_src
+
+  Else visit:
+  <https://protesilaos.com/emacs/denote#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5>.
+
+  Thanks to user "Summer Emacs" for starting the discussion on the
+  mailing list, and Benjamin Kästner for their participation:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cm25yk5e856.fsf@gmail.com%3E>.
+
++ Added an entry to the manual's Frequently Asked Questions about a
+  failed search for backlinks.  It includes sample code that users of
+  Windows can apply, if necessary.  (The error is not Denote's fault.)
+  Thanks to Benjamin Kästner for the patch, which is below the ~15 line
+  threshold and thus does not require copyright assignment to the Free
+  Software Foundation:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cce117b14-55cf-622e-6cd8-0af698091ae3%40gmail.com%3E>.
+
++ Removed duplicate entries from the list of file paths that the =xref=
+  library returns for the purposes of backlinking.  Thanks to
+  Jean-Philippe Gagné Guay for the contribution in pull request 44 on
+  the GitHub mirror: <https://github.com/protesilaos/denote/issues/44>.
+
++ Applied an appropriate face to the backlinks' button to mitigate an
+  error.  Thanks to Jean-Philippe Gagné Guay for the contribution in
+  pull request 45 on the GitHub mirror and for later testing a
+  subsequent tweak: <https://github.com/protesilaos/denote/issues/45>.
+
++ Simplfied all the faces we define to make them work with all themes.
+  The previous colours were consistent with the =modus-themes=:
+  <https://protesilaos.com/emacs/modus-themes>.
+
++ Refined how strings are sluggified under all circumstances.  Before, a
+  nil value for the user option ~denote-allow-multi-word-keywords~ would
+  have the adverse effect of joining all the strings in the title field
+  of the file name.  The intent always was to do that only for
+  multi-word keywords, not the title.  This change was part of a hotfix,
+  formalised as version =0.2.1= a day after the release of =0.2.0=.
+
++ Made the fontification rules more robust, while avoiding any false
+  positives.  This was done over a series of commits as it had
+  implications for the file name permutations that were mentioned
+  earlier.  Thanks to Jean-Philippe Gagné Guay for the patches and/or
+  discussion about the merits of each change and concomitant
+  considerations:
+
+  - https://github.com/protesilaos/denote/pull/36
+  - https://github.com/protesilaos/denote/pull/38
+  - https://github.com/protesilaos/denote/pull/40
+  - https://github.com/protesilaos/denote/pull/42
+
++ Rewrote all relevant entries in the manual to reflect all the
+  user-facing aspects of the aforementioned.
+
++ Discussed a use-case of rewriting old journal entries as Denote-style
+  files.  As of this writing, we do not support migration of files in
+  bulk.  It might happen at some point, though it is no mean task.
+  Thanks to Summer Emacs and Alan Schmitt for their participation:
+  <https://lists.sr.ht/~protesilaos/denote/%3Cm27d4mbktj.fsf%40gmail.com%3E>.
+
+  An aside here as this topic was brought up: my packages are open to
+  users of all skill levels and is why I maintain a mailing list as well
+  as mirrors of the official git repository on SourceHut.  Do not
+  hesitate to ask a question.  If, for whatever reason, those
+  communication channels are not appropriate, you are welcome to contact
+  me in private: <https://protesilaos.com/contact>.
+
+Thanks again to Jean-Philippe Gagné Guay for the numerous contributions.
+Please read the commit log for the minutia, as this change log entry
+omitted some of the finer yet important details.
+
+* Version 0.2.0 on 2022-07-04
+:PROPERTIES:
+:CUSTOM_ID: h:2002fee6-3f0c-48be-9727-6d4e20f34856
+:END:
+
++ Version =0.1.0= (from 2022-06-27) was never built as a package.  The
+  reason is that the GNU ELPA machinery reads the =Version:= header of
+  the main file, not the git tag.  As the original commit in =denote.el=
+  included =Version: 0.1.0=, GNU ELPA rightly tries to build the package
+  using that reference.  But because at that time I had not yet updated
+  the Copyright header to name the Free Software Foundation, the package
+  could not be prepared.  As such, please consider this release to be
+  the "first formal stable version".  My apologies for the delay,
+  contrary to what was promised in the last change log entry.
+
+  - Prospective users are advised to read the manual:
+    <https://protesilaos.com/emacs/denote>.  For a video demonstration:
+    <https://protesilaos.com/codelog/2022-06-18-denote-demo/>.
+
+  - Thanks to Benjamin Kästner for reporting the issue with the GNU ELPA
+    package on the mailing list:
+    <https://lists.sr.ht/~protesilaos/denote/%3C9d600ff0-4fed-2ad7-5dbc-5a194639a045@gmail.com%3E>.
+
++ Originally, Denote was designed to only work with notes in a flat
+  directory.  With code contributions from Jean-Philippe Gagné Guay,
+  support for subdirectories of the user option ~denote-directory~ is
+  now available.  This covers the case of creating links between notes,
+  following them, and viewing the backlinks' buffer of the current
+  entry.
+
+  - Thanks to Jean-Philippe for the contributions which took place on
+    the GitHub mirror:
+
+    + <https://github.com/protesilaos/denote/pull/24>
+    + <https://github.com/protesilaos/denote/pull/25>
+    + <https://github.com/protesilaos/denote/pull/26>
+
+  - Jean-Philippe Gagné Guay has assigned copyright to the Free Software
+    Foundation.  This is a prerequisite to contribute code to any
+    package on the official GNU ELPA archive (and to emacs.git for that
+    matter).
+
++ The new ~denote-subdirectory~ command lets the user select a directory
+  to place the new note in.  Available candidates are the value of the
+  ~denote-directory~ as well as all of its subdirectories, minus =.git=.
+  In future versions, we will consider how to provide a blocklist or a
+  regexp filter for the user to specify which subdirectories should be
+  omitted from minibuffer completion.  Please consider providing your
+  feedback on the technicalities.
+
+  - Thanks to Jean-Philippe Gagné Guay and Shreyas Ragavan for the
+    feedback in issue 31 on the GitHub mirror:
+    <https://github.com/protesilaos/denote/issues/31>.
+
+  - Thanks to Jean-Philippe Gagné Guay for fixing a potential problem in
+    how directories are represented when commands enter the directory
+    instead of selecting it (again, at the GitHub mirror):
+    <https://github.com/protesilaos/denote/pull/35>.
+
++ From 2022-06-24 to 2022-07-03, Denote provided support for links
+  between Org notes that leveraged the =id:= hyperlink type.
+  Discussions on the mailing list and the GitHub mirror revealed the
+  longer-term problems in our implementation.  In the Annex below, I
+  provide my detailed opinion on the matter.  The gist is that Denote
+  does not---and will not---create =id:= links between its notes, but
+  shall use the =denote:= hyperlink type instead (which works like the
+  standard =file:= type).  As the Annex explains, Denote is not org-roam
+  lite and we try not to engender such false expectations.
+
+  - Despite the fact that the relevant patches are no longer applicable,
+    I wish to thank Kaushal Modi and Jean-Philippe Gagné Guay for their
+    contributions over at the GitHub mirror:
+
+    + <https://github.com/protesilaos/denote/pull/20>
+    + <https://github.com/protesilaos/denote/pull/28>
+
++ The user option ~denote-date-format~ controls how the date and time is
+  recorded in the file's contents (what we call "front matter").  When
+  nil (the default value), we use a file-type-specific format (also
+  check the user option ~denote-file-type~):
+
+  - For Org, an inactive timestamp is used, such as =[2022-06-30 Wed 15:31]=.
+
+  - For Markdown, the RFC3339 standard is applied: =2022-06-30T15:48:00+03:00=.
+
+  - For plain text, the format is that of ISO 8601: =2022-06-30=.
+
+  If the value is a string, ignore the above and use it instead.  The
+  string must include format specifiers for the date.  These are described
+  in the doc string of ~format-time-string~.
+
+  The ~denote-date-format~ supersedes the now obsolete
+  ~denote-front-matter-date-format~.
+
+  Thanks to Peter Prevos and Kaushal Modi for their feedback in issue 27
+  on the GitHub mirror: <https://github.com/protesilaos/denote/issues/27>.
+
++ All the faces we define are now declared in the =denote-faces.el=
+  file.  The fontification rules are shared by ~denote-dired-mode~ and
+  the backlinks' buffer (invoked by ~denote-link-backlinks~ and
+  controlled by the user option ~denote-link-fontify-backlinks~).  The
+  current list of faces:
+
+  - ~denote-faces-date~
+  - ~denote-faces-delimiter~
+  - ~denote-faces-extension~
+  - ~denote-faces-keywords~
+  - ~denote-faces-subdirectory~
+  - ~denote-faces-time~
+  - ~denote-faces-title~
+
++ Named the mailing list address as the =Maintainer:= of Denote.
+  Together with the other package headers, they help the user find our
+  primary sources and/or communication channels.  This change conforms
+  with work being done upstream in package.el by Philip Kaludercic.  I
+  was informed about it here:
+  <https://lists.sr.ht/~protesilaos/general-issues/%3C875ykl84yi.fsf%40posteo.net%3E>.
+
++ Fixed how keywords are inferred and combined.  The previous code did not
+  work properly when the user option =denote-infer-keywords= was nil.
+  It would return a list of symbols, with the parentheses, whereas the
+  file name needs a string where each keyword is delimited by an
+  underscore.
+
++ Simplified how information in the front matter is retrieved.  It fixes
+  cases where, for example, a special character at the end of the title
+  was ignored.  Thanks to Jean-Philippe Gagné Guay for the patch over at
+  the GitHub mirror: <https://github.com/protesilaos/denote/pull/21>.
+
++ Rewrote parts of the manual in the interest of clarity.
+
+** Annex about discontinuing support for org-id
+:PROPERTIES:
+:CUSTOM_ID: h:647d6155-1ac3-4ecb-bd4c-06d09fecd3ba
+:END:
+
+My thanks for their participation in the discussions go to Jean-Philippe
+Gagné Guay, Kaushal Modi, and Shreyas Ragavan.
+
+#+begin_example
+commit f35ef05cb451f265213c3aafc1e62c425b1ff043
+Author: Protesilaos Stavrou <info@protesilaos.com>
+Date:   Sun Jul 3 17:34:38 2022 +0300
+
+    REMOVE support for 'id:' hyperlink types
+
+    The original idea was to support the 'org-id' library on the premise
+    that it makes Denote a good Emacs citizen.  However, discussions on the
+    mailing list[0] and the GitHub mirror[1] have made it clear to me that
+    'org-id' is not consistent with Denote's emphasis on simplicity.
+
+    To support the way 'org-id' works, we will eventually have to develop
+    some caching mechanism, just how the org-roam package does it.  This is
+    because the variable 'org-id-extra-files' needs to be kept up-to-date
+    whenever an operation on a file is performed.  At scale, this sort of
+    monitoring requires specialised software.  Such a mechanism is outside
+    the scope of Denote---if you need a db, use org-roam which is already
+    great.
+
+    [0] <https://lists.sr.ht/~protesilaos/denote/%3C8735fk4y1w.fsf%40hallac.net%3E#%3C877d4un73c.fsf@protesilaos.com%3E>
+
+    [1] <https://github.com/protesilaos/denote/issues/29>
+
+    Quote of what I wrote on the GitHub mirror issue 29:
+
+            [ggjp] This is what I was implying.  That we are, in fact,
+            providing an option that is not viable long-term, but keeping
+            the option for expert users who will be able to handle this.
+            And we should warn about this clearly in the doc of that option.
+
+        [protesilaos] What you write here @ggjp and what @shrysr explained
+        tells me that those expert users will need to be real experts.  To
+        put it concretely, I am an experienced Emacs user with no
+        programming background, who has written several Emacs
+        packages (including the modus-themes which are built into Emacs),
+        but I have zero knowledge of using a db or of handling things with
+        python and the like.  So if I opt in to 'denote-link-use-org-id' I
+        will eventually run into problems that my non-existent skills will
+        prevent me from solving.  At that point, I will just use org-roam
+        which already handles this use-case in a competent way (and has a
+        massive community to rely on in case I need further support).
+
+        If each package needs to write its own optimisations and maintain
+        its own cache, to me this shows that 'org-id' is not good enough for
+        the time being: more work needs to be done in org.git to provide a
+        universal solution.
+
+        I wanted to support 'org-id' by default on the premise that Denote
+        must be a good Emacs citizen which interoperates with the rest of
+        the wider ecosystem.  But if 'org-id' leaves something to be
+        desired, then that goal is not worth pursuing: we add complexity to
+        our code, offer an option that we cannot genuinely/adequately
+        support, and make usage of it contingent on reading the docs and
+        having a high level of expertise.
+
+        I think being a good Emacs citizen is a laudable principle.  In this
+        case, the right thing to do is to recommend the use of org-roam
+        instead of trying to accommodate 'org-id'.  As such, I have now
+        changed my mind and think we should remove what we previously added.
+
+        For some context here: the reason I never used org-roam is
+        because (i) it is Org-specific whereas I write notes in different
+        file types and (ii) I did not want to ever rely on a db or
+        equivalent dependency.
+
+        <https://github.com/protesilaos/denote/issues/29#issuecomment-1173036924>
+
+ README.org         | 226 ++++++++---------------------------------------------
+ denote-link.el     |  99 ++++++-----------------
+ denote-retrieve.el |   2 +-
+ denote.el          |  14 +---
+ 4 files changed, 63 insertions(+), 278 deletions(-)
+#+end_example
+
+Followed up by my explanation:
+
+#+begin_src text
+> can we not have denote style links to be default for (de)notes - and
+> explicitly supported, while if they need to, users can still link
+> denote org files via org-id to any other notes/files (and vice versa)
+> -- in which case performance + testing for org-id driven linking is
+> not within Denote's purview at all?
+
+The formal support for `id:` links was added shortly before the release
+of version `0.1.0`.  In the days prior, we supported what you describe
+via the manual.  The user could change the `denote-org-front-matter`
+variable to include a `PROPERTIES` drawer.  This possibility still
+exists, though yesterday I removed the relevant entry from the manual.
+This way only the real do-it-yourself experts will go down that path.
+
+My concern here is with managing expectations.  If our Org notes are
+superficially the same as org-roam's, an unsuspecting user may think
+that Denote is an org-roam lite.  We will thus get issues/requests, such
+as those already mentioned in this GitHub repo, about migrating from
+org-roam to Denote.  While there are similarities, Denote is not a
+minimalist org-roam and I would not like to encourage the idea of
+treating the two as interchangeable.
+
+Doing things half-way-through is a way to create false expectations.  A
+package on GNU ELPA must be usable by users of all skill levels.  If the
+functionality we provide is incomplete and needs to be covered by
+user-level tweaks, we are excluding a portion of the user base while
+still assuming the maintenance burden.  If someone trusts Denote to,
+say, write a 1000 notes, we do not want to surprise them after the fact.
+Imagine if the reported issues that triggered this change happened 6
+months into one's daily usage of Denote: it wouldn't be nice.
+
+Setting the right expectations is a matter of responsibility: we let the
+user make a more informed choice and show respect for their time.  It
+also makes it easier for me to keep Denote's scope in check by not
+supporting every little extra that Org implements.  The premier Org
+extension is org-roam: we do not need another one (or, if we do, I am
+not the one to implement it).
+
+,* * *
+
+Some comments on the `denote:` hyperlink type for Org as they may be
+relevant in this context:
+
+,* It is meant to work like the standard `file:` type.  This means that
+  it links to a file, while it can also have additional search
+  parameters, as explained in the Org manual.  Evaluate:
+
+      (info "(org) Search Options")
+
+,* It does not read the front matter, but only the file name.  You can
+  create a note as usual, delete all its contents, save it, and try to
+  link to it from another note.  It works.
+
+,* Exporting now works like the `file:` type for HTML, LaTeX, Texinfo,
+  and Markdown.  Technically, it also supports the ASCII backend but the
+  format of the output could be tweaked further.
+
+There may be refinements to be made, which is okay as that is part of a
+maintainer's duties.
+#+end_src
+
+* Version 0.1.0 on 2022-06-27
+:PROPERTIES:
+:CUSTOM_ID: h:33939747-ad60-4913-a170-4b2f48f139cc
+:END:
+
+The present entry is intended for early adopters of Denote who may have
+not caught up with the latest developments.  Prospective users are
+advised to read the manual: <https://protesilaos.com/emacs/denote>.  For
+a video demonstration: <https://protesilaos.com/codelog/2022-06-18-denote-demo/>.
+
++ The =denote= package on GNU ELPA will be available a few hours after
+  this release.  GNU ELPA provides the latest stable release.  To use a
+  development snapshot, read:
+  <https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/>.
+
++ Remember that any significant contribution (above ~15 lines) requires
+  copyright assignment to the Free Software Foundation.  A form with
+  instructions is included in the manual's "Contributing" section:
+  <https://protesilaos.com/emacs/denote#h:1ebe4865-c001-4747-a6f2-0fe45aad71cd>.
+
++ The front matter of notes in Org has changed to be compliant with the
+  standard =org-id= infrastructure.  A =PROPERTIES= drawer is added to
+  the top of the file, which includes an =ID= property with the value of
+  the Denote identifier.  Sample:
+
+  #+begin_src org
+  :PROPERTIES:
+  :ID:          20220610T202537
+  :END:
+  ,#+title:      Sample Org front matter
+  ,#+date:       2022-06-10
+  ,#+filetags:   denote  testing
+  #+end_src
+
++ The front matter of Markdown (YAML or TOML) and plain text files
+  remains constant.  For completeness, this is how they look:
+
+   #+begin_src md
+   ---
+   title:      "Sample with Markdown and YAML"
+   date:       2022-06-10
+   tags:       denote  testing
+   identifier: "20220610T202021"
+   ---
+   #+end_src
+
+  #+begin_src md
+  +++
+  title      = "Sample with Markdown and TOML"
+  date       = 2022-06-10
+  tags       = ["denote", "testing"]
+  identifier = "20220610T201510"
+  +++
+  #+end_src
+
+  #+begin_example
+  title:      Sample plain text
+  date:       2022-06-10
+  tags:       denote  testing
+  identifier: 20220610T202232
+  ---------------------------
+  #+end_example
+
++ The integration with =org-id= extends to how linking works.  By
+  default, Denote uses its own custom hyperlink type which starts with
+  the =denote:= prefix.  In Org, it works like the =file:= type.  When
+  the user option ~denote-link-use-org-id~ is non-nil, links from Org
+  notes to other Org notes will use the standard =id:= type instead.  As
+  this is an Org-specific feature, Denote takes care to use the
+  major-mode-agnostic =denote:= type when the link targets a non-Org
+  note.
+
++ In Org files the links created by Denote are buttonized automatically.
+  For Markdown and plain text, we use our own methods.  When a link is
+  inserted it is buttonized outright.  To buttonize links in existing
+  notes while visiting them in a buffer, add/evaluate this (it excludes
+  Org on its own):
+
+  #+begin_src emacs-lisp
+  (add-hook 'find-file-hook #'denote-link-buttonize-buffer)
+  #+end_src
+
++ The generation of the backlinks' buffer now uses the built-in =xref=
+  library instead of relying on a hardcoded call to the =find=
+  executable.  This means that the ~denote-link-backlinks~ command will,
+  in principle, work properly with all Emacs builds.
+
++ Users of Emacs 28 or higher can configure ~xref-search-program~ to
+  change from the default =grep= to =ripgrep=, =ugrep=, or a
+  user-defined alternative.
+
++ This is the first stable release of Denote.  It covers close to 400
+  commits starting from 2022-06-04.  Denote is the successor to a toy
+  package of mine, USLS, whose first public version was made available
+  in early November 2020: <https://gitlab.com/protesilaos/usls>.
+
++ Thanks to everyone involved in the development of Denote.  Code
+  contributions, bug reports, discussion of ideas, are all valuable.
+  From A-Z the names mentioned in the manual's "Acknowledgements"
+  section: Colin McLear, Damien Cassou, Frank Ehmsen, Jack Baty, Kaushal
+  Modi, Peter Povinec, Sven Seebeck, Ypot.
+
++ Sources of Denote:
+
+  + Package name (GNU ELPA): =denote=
+  + Official manual: <https://protesilaos.com/emacs/denote>
+  + Change log: <https://protesilaos.com/emacs/denote-changelog>
+  + Git repo on SourceHut: <https://git.sr.ht/~protesilaos/denote>
+    - Mirrors:
+      + GitHub: <https://github.com/protesilaos/denote>
+      + GitLab: <https://gitlab.com/protesilaos/denote>
+  + Mailing list: <https://lists.sr.ht/~protesilaos/denote>
blob - /dev/null
blob + 60c3b58af49708709570ca120a7154ed079f17d7 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/README-elpa
@@ -0,0 +1,6985 @@
+           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+                 DENOTE: SIMPLE NOTES WITH AN EFFICIENT
+                           FILE-NAMING SCHEME
+
+                          Protesilaos Stavrou
+                          info@protesilaos.com
+           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+
+This manual, written by Protesilaos Stavrou, describes the customization
+options for the Emacs package called `denote' (or `denote.el'), and
+provides every other piece of information pertinent to it.
+
+The documentation furnished herein corresponds to stable version 4.0.0,
+released on 2025-04-15.  Any reference to a newer feature which does not
+yet form part of the latest tagged commit, is explicitly marked as such.
+
+Current development target is 4.1.0-dev.
+
+⁃ Package name (GNU ELPA): `denote'
+⁃ Official manual: <https://protesilaos.com/emacs/denote>
+⁃ Change log: <https://protesilaos.com/emacs/denote-changelog>
+⁃ Git repositories:
+  ⁃ GitHub: <https://github.com/protesilaos/denote>
+  ⁃ GitLab: <https://gitlab.com/protesilaos/denote>
+⁃ Video demo: <https://protesilaos.com/codelog/2022-06-18-denote-demo/>
+⁃ Backronyms: Denote Everything Neatly; Omit The Excesses.  Don’t Ever
+  Note Only The Epiphenomenal.
+
+If you are viewing the README.org version of this file, please note that
+the GNU ELPA machinery automatically generates an Info manual out of it.
+
+Table of Contents
+─────────────────
+
+1. COPYING
+2. Installation
+.. 1. GNU ELPA package
+.. 2. Manual installation
+3. Sample configuration
+.. 1. Get started with this sample configuration
+.. 2. More comprehensive sample configuration
+4. Overview
+5. Points of entry
+.. 1. Standard note creation
+..... 1. The `denote-prompts' option
+..... 2. The `denote-history-completion-in-prompts' option
+..... 3. The `denote-templates' option
+..... 4. Convenience commands for note creation
+..... 5. The `denote-save-buffers' option
+..... 6. The `denote-kill-buffers' option
+..... 7. The `denote-date-prompt-use-org-read-date' option
+.. 2. Create note using Org capture
+.. 3. Create note with specific prompts using Org capture
+.. 4. Create note with specific values using Org capture
+.. 5. Create a note with the region’s contents
+..... 1. A custom `denote-region' that references the source
+.. 6. Open an existing note or create it if missing
+.. 7. Maintain separate directory silos for notes
+..... 1. Make Org export work with silos
+.. 8. Exclude certain files from file prompts
+.. 9. Exclude certain directories from all operations
+.. 10. Exclude certain keywords from being inferred
+.. 11. Create a controlled vocabulary for keywords
+.. 12. Use Denote commands from the menu bar or context menu
+6. Renaming files
+.. 1. Rename a single file
+..... 1. The `denote-rename-confirmations' option
+.. 2. Rename a single file based on its front matter
+.. 3. Rename multiple files interactively
+.. 4. Rename multiple files at once by asking only for keywords
+.. 5. Rename multiple files based on their front matter
+.. 6. Rename a file by changing only its file type
+.. 7. Rename a file by adding or removing a title interactively
+.. 8. Rename a file by adding or removing keywords interactively
+.. 9. Rename a file by adding or removing a signature interactively
+.. 10. Find duplicate identifiers and put them in a Dired buffer
+.. 11. Faces used by rename commands
+7. The file-naming scheme
+.. 1. Change the order of file name components
+.. 2. Sluggification of file name components
+.. 3. User-defined sluggification of file name components
+..... 1. Custom sluggification to remove non-ASCII characters
+.. 4. Features of the file-naming scheme for searching or filtering
+8. Front matter
+.. 1. Change the front matter format
+.. 2. Regenerate front matter
+9. Linking notes
+.. 1. Add a single direct link using a file name prompt
+.. 2. Add a direct link to a file whose contents include the given query
+.. 3. Add a query link
+.. 4. Insert links to all files matching a query in their file name
+.. 5. Insert links to all files matching a query in their contents
+.. 6. The `denote-open-link-function' user option
+.. 7. The `denote-org-store-link-to-heading' user option
+.. 8. Adding direct links to files matching contents
+.. 9. Insert links from marked files in Dired
+.. 10. Link to an existing note or create a new one
+.. 11. The backlinks’ buffer
+.. 12. Writing metanotes
+.. 13. Visiting linked files via the minibuffer
+.. 14. Fontify links in non-Org buffers
+.. 15. The `denote-link-description-format' to format link descriptions
+10. Choose which commands to prompt for
+11. Fontification in Dired
+12. Automatically rename Denote buffers
+.. 1. The `denote-rename-buffer-format' option
+13. Use Org dynamic blocks
+14. Display filtered and sorted files with `denote-sort-dired' or `denote-dired'
+.. 1. Configure what extra prompts `denote-sort-dired' issues
+.. 2. Define a sorting function per component
+..... 1. Sort signatures that include Luhmann-style sequences
+15. Use `denote-grep' to search inside files
+16. Interact with the links buffer
+17. Minibuffer histories
+18. Packages that build on Denote
+.. 1. Use the `consult-denote' package for enhanced minibuffer interactions
+.. 2. Sequence notes
+.. 3. Use the `denote-markdown' package to better integrate Markdown with Denote
+.. 4. Use the `denote-journal' package which was formerly `denote-journal-extras.el'
+.. 5. Use the `denote-silo' package which formerly was `denote-silo-extras.el'
+.. 6. Use the `denote-search' package as a search interface
+.. 7. Use the `denote-explore' package to explore your notes
+.. 8. Use the `citar-denote' package for bibliography notes
+.. 9. Use the `consult-notes' package
+.. 10. Use the `denote-menu' package
+.. 11. Use the `denote-zettel-interface' package
+19. Extending Denote
+.. 1. Access the data of the latest note
+.. 2. Create a new note in any directory
+.. 3. Find empty notes and put them in a Dired buffer
+.. 4. Automatically rename the note after saving it
+.. 5. Narrow the list of files in Dired
+.. 6. Use `dired-virtual-mode' for arbitrary file listings
+.. 7. Use Embark to collect minibuffer candidates
+.. 8. Search file contents
+.. 9. Bookmark the directory with the notes
+.. 10. Treat your notes as a project
+.. 11. Use the tree-based file prompt for select commands
+.. 12. Rename files with Denote in the Image Dired thumbnails buffer
+.. 13. Rename files with Denote using `dired-preview'
+.. 14. Avoid duplicate identifiers when exporting Denote notes
+..... 1. Export Denote notes with Org Mode
+..... 2. Export Denote notes with Markdown
+.. 15. Set up your workflow for daily or weekly meeting notes
+20. For developers or advanced users
+.. 1. Common building blocks for developers or advanced users
+.. 2. File path interface for developers or advanced users
+.. 3. Data retrieval interface for developers or advanced users
+.. 4. Prompt interface for developers or advanced users
+.. 5. Front matter interface for developers or advanced users
+.. 6. Link interface for developers or advanced users
+.. 7. Xref interface for developers or advanced users
+.. 8. Renaming files interface for developers or advanced users
+21. Troubleshoot Denote in a pristine environment
+22. Contributing
+.. 1. Wishlist of what we can do to extend Denote
+23. Publications about Denote
+24. Alternatives to Denote
+.. 1. Alternative implementations and further reading
+25. Frequently Asked Questions
+.. 1. Why develop Denote when PACKAGE already exists?
+.. 2. Why not rely exclusively on Org?
+.. 3. Why care about Unix tools when you use Emacs?
+.. 4. Why many small files instead of few large ones?
+.. 5. Does Denote perform well at scale?
+.. 6. I add TODOs to my notes; will many files slow down the Org agenda?
+.. 7. I want to sort by last modified in Dired, why won’t Denote let me?
+.. 8. How do you handle the last modified case?
+.. 9. Why are some Org links opening outside Emacs?
+.. 10. Speed up backlinks’ or query links’ buffer creation?
+.. 11. Why do I get “Search failed with status 1” when I search for backlinks?
+.. 12. Why do I get a double `#+title' in Doom Emacs?
+26. Acknowledgements
+27. GNU Free Documentation License
+28. Indices
+.. 1. Function index
+.. 2. Variable index
+.. 3. Concept index
+
+
+1 COPYING
+═════════
+
+  Copyright (C) 2022-2025 Free Software Foundation, Inc.
+
+        Permission is granted to copy, distribute and/or modify
+        this document under the terms of the GNU Free
+        Documentation License, Version 1.3 or any later version
+        published by the Free Software Foundation; with no
+        Invariant Sections, with the Front-Cover Texts being “A
+        GNU Manual,” and with the Back-Cover Texts as in (a)
+        below.  A copy of the license is included in the section
+        entitled “GNU Free Documentation License.”
+
+        (a) The FSF’s Back-Cover Text is: “You have the freedom to
+        copy and modify this GNU manual.”
+
+
+2 Installation
+══════════════
+
+
+
+
+2.1 GNU ELPA package
+────────────────────
+
+  The package is available as `denote'.  Simply do:
+
+  ┌────
+  │ M-x package-refresh-contents
+  │ M-x package-install
+  └────
+
+
+  And search for it.
+
+  GNU ELPA provides the latest stable release.  Those who prefer to
+  follow the development process in order to report bugs or suggest
+  changes, can use the version of the package from the GNU-devel ELPA
+  archive.  Read:
+  <https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/>.
+
+
+2.2 Manual installation
+───────────────────────
+
+  Assuming your Emacs files are found in `~/.emacs.d/', execute the
+  following commands in a shell prompt:
+
+  ┌────
+  │ cd ~/.emacs.d
+  │ 
+  │ # Create a directory for manually-installed packages
+  │ mkdir manual-packages
+  │ 
+  │ # Go to the new directory
+  │ cd manual-packages
+  │ 
+  │ # Clone this repo, naming it "denote"
+  │ git clone https://github.com/protesilaos/denote denote
+  └────
+
+  Finally, in your `init.el' (or equivalent) evaluate this:
+
+  ┌────
+  │ ;; Make Elisp files in that directory available to the user.
+  │ (add-to-list 'load-path "~/.emacs.d/manual-packages/denote")
+  └────
+
+  Everything is in place to set up the package.
+
+
+3 Sample configuration
+══════════════════════
+
+  Denote is immediately useful for beginners and power users alike. This
+  manual covers everything in detail, though do not let the numerous
+  possibilities distract you from the fact that a basic configuration is
+  enough to be highly productive ([Get started with this sample
+  configuration]).
+
+
+[Get started with this sample configuration] See section 3.1
+
+3.1 Get started with this sample configuration
+──────────────────────────────────────────────
+
+  If you are new to Denote, this a good place to start. Then work your
+  way through the manual and expand your configuration accordingly. Only
+  include commands/variables that are useful to you. We provide another
+  code sample if you need some ideas ([More comprehensive sample
+  configuration]).
+
+  ┌────
+  │ ;; Remember that the website version of this manual shows the latest
+  │ ;; developments, which may not be available in the package you are
+  │ ;; using.  Instead of copying from the web site, refer to the version
+  │ ;; of the documentation that comes with your package.  Evaluate:
+  │ ;;
+  │ ;;     (info "(denote) Sample configuration")
+  │ (use-package denote
+  │   :ensure t
+  │   :hook (dired-mode . denote-dired-mode)
+  │   :bind
+  │   (("C-c n n" . denote)
+  │    ("C-c n r" . denote-rename-file)
+  │    ("C-c n l" . denote-link)
+  │    ("C-c n b" . denote-backlinks)
+  │    ("C-c n d" . denote-dired)
+  │    ("C-c n g" . denote-grep))
+  │   :config
+  │   (setq denote-directory (expand-file-name "~/Documents/notes/"))
+  │ 
+  │   ;; Automatically rename Denote buffers when opening them so that
+  │   ;; instead of their long file name they have, for example, a literal
+  │   ;; "[D]" followed by the file's title.  Read the doc string of
+  │   ;; `denote-rename-buffer-format' for how to modify this.
+  │   (denote-rename-buffer-mode 1))
+  └────
+
+
+[More comprehensive sample configuration] See section 3.2
+
+
+3.2 More comprehensive sample configuration
+───────────────────────────────────────────
+
+  Here we include more of what you can configure with Denote ([Get
+  started with this sample configuration]).
+
+  ┌────
+  │ ;; Remember that the website version of this manual shows the latest
+  │ ;; developments, which may not be available in the package you are
+  │ ;; using.  Instead of copying from the web site, refer to the version
+  │ ;; of the documentation that comes with your package.  Evaluate:
+  │ ;;
+  │ ;;     (info "(denote) Sample configuration")
+  │ (use-package denote
+  │   :ensure t
+  │   :hook
+  │   ( ;; If you use Markdown or plain text files, then you want to make
+  │    ;; the Denote links clickable (Org renders links as buttons right
+  │    ;; away)
+  │    (text-mode . denote-fontify-links-mode-maybe)
+  │    ;; Apply colours to Denote names in Dired.  This applies to all
+  │    ;; directories.  Check `denote-dired-directories' for the specific
+  │    ;; directories you may prefer instead.  Then, instead of
+  │    ;; `denote-dired-mode', use `denote-dired-mode-in-directories'.
+  │    (dired-mode . denote-dired-mode))
+  │   :bind
+  │   ;; Denote DOES NOT define any key bindings.  This is for the user to
+  │   ;; decide.  For example:
+  │   ( :map global-map
+  │     ("C-c n n" . denote)
+  │     ("C-c n d" . denote-dired)
+  │     ("C-c n g" . denote-grep)
+  │     ;; If you intend to use Denote with a variety of file types, it is
+  │     ;; easier to bind the link-related commands to the `global-map', as
+  │     ;; shown here.  Otherwise follow the same pattern for `org-mode-map',
+  │     ;; `markdown-mode-map', and/or `text-mode-map'.
+  │     ("C-c n l" . denote-link)
+  │     ("C-c n L" . denote-add-links)
+  │     ("C-c n b" . denote-backlinks)
+  │     ("C-c n q c" . denote-query-contents-link) ; create link that triggers a grep
+  │     ("C-c n q f" . denote-query-filenames-link) ; create link that triggers a dired
+  │     ;; Note that `denote-rename-file' can work from any context, not just
+  │     ;; Dired bufffers.  That is why we bind it here to the `global-map'.
+  │     ("C-c n r" . denote-rename-file)
+  │     ("C-c n R" . denote-rename-file-using-front-matter)
+  │ 
+  │     ;; Key bindings specifically for Dired.
+  │     :map dired-mode-map
+  │     ("C-c C-d C-i" . denote-dired-link-marked-notes)
+  │     ("C-c C-d C-r" . denote-dired-rename-files)
+  │     ("C-c C-d C-k" . denote-dired-rename-marked-files-with-keywords)
+  │     ("C-c C-d C-R" . denote-dired-rename-marked-files-using-front-matter))
+  │ 
+  │   :config
+  │   ;; Remember to check the doc string of each of those variables.
+  │   (setq denote-directory (expand-file-name "~/Documents/notes/"))
+  │   (setq denote-save-buffers nil)
+  │   (setq denote-known-keywords '("emacs" "philosophy" "politics" "economics"))
+  │   (setq denote-infer-keywords t)
+  │   (setq denote-sort-keywords t)
+  │   (setq denote-prompts '(title keywords))
+  │   (setq denote-excluded-directories-regexp nil)
+  │   (setq denote-excluded-keywords-regexp nil)
+  │   (setq denote-rename-confirmations '(rewrite-front-matter modify-file-name))
+  │ 
+  │   ;; Pick dates, where relevant, with Org's advanced interface:
+  │   (setq denote-date-prompt-use-org-read-date t)
+  │ 
+  │   ;; Automatically rename Denote buffers using the `denote-rename-buffer-format'.
+  │   (denote-rename-buffer-mode 1))
+  └────
+
+
+[Get started with this sample configuration] See section 3.1
+
+
+4 Overview
+══════════
+
+  Denote aims to be a simple-to-use, focused-in-scope, and effective
+  note-taking and file-naming tool for Emacs.
+
+  Denote is based on the idea that files should follow a predictable and
+  descriptive file-naming scheme.  The file name must offer a clear
+  indication of what the contents are about, without reference to any
+  other metadata.  Denote basically streamlines the creation of such
+  files or file names while providing facilities to link between them
+  (where those files are editable).
+
+  Denote’s file-naming scheme is not limited to “notes”.  It can be used
+  for all types of file, including those that are not editable in Emacs,
+  such as videos.  Naming files in a consistent way makes their
+  filtering and retrieval considerably easier.  Denote provides relevant
+  facilities to rename files, regardless of file type.
+
+  Denote is based on the following core design principles:
+
+  Predictability
+        File names must follow a consistent and descriptive naming
+        convention ([The file-naming scheme]).  The file name alone
+        should offer a clear indication of what the contents are,
+        without reference to any other metadatum.  This convention is
+        not specific to note-taking, as it is pertinent to any form of
+        file that is part of the user’s long-term storage ([Renaming
+        files]).
+
+  Composability
+        Be a good Emacs citizen, by integrating with other packages or
+        built-in functionality instead of re-inventing functions such as
+        for filtering or greping.  The author of Denote (Protesilaos,
+        aka “Prot”) writes ordinary notes in plain text (`.txt'),
+        switching on demand to an Org file only when its expanded set of
+        functionality is required for the task at hand ([Points of
+        entry]).
+
+  Portability
+        Notes are plain text and should remain portable.  The way Denote
+        writes file names, the front matter it includes in the note’s
+        header, and the links it establishes must all be adequately
+        usable with standard Unix tools.  No need for a database or some
+        specialised software.  As Denote develops and this manual is
+        fully fleshed out, there will be concrete examples on how to do
+        the Denote-equivalent on the command-line.
+
+  Flexibility
+        Do not assume the user’s preference for a note-taking
+        methodology.  Denote is conceptually similar to the Zettelkasten
+        Method, which you can learn more about in this detailed
+        introduction: <https://zettelkasten.de/introduction/>.  Notes
+        are atomic (one file per note) and have a unique identifier.
+        However, Denote does not enforce a particular methodology for
+        knowledge management, such as a restricted vocabulary or
+        mutually exclusive sets of keywords.  Denote also does not check
+        if the user writes thematically atomic notes.  It is up to the
+        user to apply the requisite rigor and/or creativity in pursuit
+        of their preferred workflow ([Writing metanotes]).
+
+  Hackability
+        Denote’s code base consists of small and reusable functions.
+        They all have documentation strings.  The idea is to make it
+        easier for users of varying levels of expertise to understand
+        what is going on and make surgical interventions where necessary
+        (e.g. to tweak some formatting).  In this manual, we provide
+        concrete examples on such user-level configurations ([Keep a
+        journal or diary]).
+
+  Now the important part…  “Denote” is the familiar word, though it also
+  is a play on the “note” concept.  Plus, we can come up with acronyms,
+  recursive or otherwise, of increasingly dubious utility like:
+
+  ⁃ Don’t Ever Note Only The Epiphenomenal
+  ⁃ Denote Everything Neatly; Omit The Excesses
+
+  But we’ll let you get back to work.  Don’t Eschew or Neglect your
+  Obligations, Tasks, and Engagements.
+
+
+[The file-naming scheme] See section 7
+
+[Renaming files] See section 6
+
+[Points of entry] See section 5
+
+[Writing metanotes] See section 9.12
+
+[Keep a journal or diary] See section 18.4
+
+
+5 Points of entry
+═════════════════
+
+  There are seven main ways to write a note with Denote: invoke the
+  `denote', `denote-type', `denote-date', `denote-subdirectory',
+  `denote-template', `denote-signature' commands, or leverage the
+  `org-capture-templates' by setting up a template which calls the
+  function `denote-org-capture'.  We explain all of those in the
+  subsequent sections.  Other more specialised commands exist as well,
+  which one shall learn about as they read through this manual.  We do
+  not want to overwhelm the user with options at this stage.
+
+  All these commands construct the file name in accordance with the user
+  option `denote-file-name-components-order' ([Change the order of file
+  name components]).
+
+
+[Change the order of file name components] See section 7.1
+
+5.1 Standard note creation
+──────────────────────────
+
+  The `denote' command will prompt for a title.  If a region is active,
+  the text of the region becomes the default at the minibuffer prompt
+  (meaning that typing `RET' without any input will use the default
+  value).  Once the title is supplied, the `denote' command will then
+  ask for keywords.  The resulting note will have a file name as already
+  explained: [The file naming scheme]
+
+  The `denote' command runs the hook `denote-after-new-note-hook' after
+  creating the new note ([Access the data of the latest note]). When
+  called from Lisp, it returns the path it generates. Before returning
+  the path, it decides what to do with the buffer of the note, in
+  accordance with the user option `denote-kill-buffers' ([The
+  `denote-kill-buffers' option]).
+
+  The file type of the new note is determined by the user option
+  `denote-file-type' ([Front matter]).
+
+  The keywords’ prompt supports minibuffer completion.  Available
+  candidates are those defined in the user option
+  `denote-known-keywords'.  More candidates can be inferred from the
+  names of existing notes, by setting `denote-infer-keywords' to non-nil
+  (which is the case by default) ([Create a controlled vocabulary for
+  keywords]).
+
+  Multiple keywords can be inserted by separating them with a comma (or
+  whatever the value of the `crm-separator' is—which should be a comma).
+  When the user option `denote-sort-keywords' is non-nil (the default),
+  keywords are sorted alphabetically (technically, the sorting is done
+  with `string-lessp').
+
+  The interactive behaviour of the `denote' command is influenced by the
+  user option `denote-prompts' ([The denote-prompts option]).
+
+  The `denote' command can also be called from Lisp.  Read its doc
+  string for the technicalities.
+
+  In the interest of discoverability, `denote' is also available under
+  the alias `denote-create-note'.
+
+
+[The file naming scheme] See section 7
+
+[Access the data of the latest note] See section 19.1
+
+[The `denote-kill-buffers' option] See section 5.1.6
+
+[Front matter] See section 8
+
+[Create a controlled vocabulary for keywords] See section 5.11
+
+[The denote-prompts option] See section 5.1.1
+
+5.1.1 The `denote-prompts' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The user option `denote-prompts' determines how the `denote' command
+  will behave interactively ([Standard note creation]).
+
+  Commands that prompt for user input to construct a Denote file name
+  include, but are not limited to: `denote', `denote-signature',
+  `denote-type', `denote-date', `denote-subdirectory',
+  `denote-rename-file', `denote-dired-rename-files'.
+
+  • [Convenience commands for note creation].
+  • [Renaming files].
+
+  The value of this user option is a list of symbols, which includes any
+  of the following:
+
+  • `title': Prompt for the title of the new note ([The
+    `denote-history-completion-in-prompts' option]).
+
+  • `keywords': Prompts with completion for the keywords of the new
+    note.  Available candidates are those specified in the user option
+    `denote-known-keywords'.  If the user option `denote-infer-keywords'
+    is non-nil, keywords in existing note file names are included in the
+    list of candidates.  The `keywords' prompt uses
+    `completing-read-multiple', meaning that it can accept multiple
+    keywords separated by a comma (or whatever the value of
+    `crm-separator' is).
+
+  • `file-type': Prompts with completion for the file type of the new
+    note.  Available candidates are those specified in the user option
+    `denote-file-type'.  Without this prompt, `denote' uses the value of
+    `denote-file-type'.
+
+  • `subdirectory': Prompts with completion for a subdirectory in which
+    to create the note.  Available candidates are the value of the user
+    option `denote-directory' and all of its subdirectories.  Any
+    subdirectory must already exist: Denote will not create it.
+
+  • `date': Prompts for the date of the new note.  It will expect an
+    input like 2022-06-16 or a date plus time: 2022-06-16 14:30.
+    Without the `date' prompt, the `denote' command uses the
+    `current-time'.
+
+    [The denote-date-prompt-use-org-read-date option].
+
+  • `template': Prompts for a KEY among the `denote-templates'.  The
+    value of that KEY is used to populate the new note with content,
+    which is added after the front matter ([The denote-templates
+    option]).
+
+  • `signature': - Prompts for an arbitrary string that can be used for
+    any kind of workflow, such as a special tag to label the `part1' and
+    `part2' of a large file that is split in half, or to add special
+    contexts like `home' and `work', or even priorities like `a', `b',
+    `c'. One other use-case is to implement a sequencing scheme that
+    makes notes have hierarchical relationships. This is handled by our
+    optional extension `denote-sequence.el', which is part of the
+    `denote' package ([Write sequence notes or “folgezettel”]).
+
+  The prompts occur in the given order.
+
+  If the value of this user option is nil, no prompts are used.  The
+  resulting file name will consist of an identifier (i.e. the date and
+  time) and a supported file type extension (per `denote-file-type').
+
+  Recall that Denote’s standard file-naming scheme is defined as follows
+  ([The file-naming scheme]):
+
+  ┌────
+  │ DATE--TITLE__KEYWORDS.EXT
+  └────
+
+
+  If either or both of the `title' and `keywords' prompts are not
+  included in the value of this variable, file names will be any of
+  those permutations:
+
+  ┌────
+  │ DATE.EXT
+  │ DATE--TITLE.EXT
+  │ DATE__KEYWORDS.EXT
+  └────
+
+
+  When in doubt, always include the `title' and `keywords' prompts.
+
+  Finally, this user option only affects the interactive use of the
+  `denote' or other relevant commands (advanced users can call it from
+  Lisp). In Lisp usage, the behaviour is always what the caller
+  specifies, based on the supplied arguments.
+
+
+[Standard note creation] See section 5.1
+
+[Convenience commands for note creation] See section 5.1.4
+
+[Renaming files] See section 6
+
+[The `denote-history-completion-in-prompts' option] See section 5.1.2
+
+[The denote-date-prompt-use-org-read-date option] See section 5.1.7
+
+[The denote-templates option] See section 5.1.3
+
+[Write sequence notes or “folgezettel”] See section 18.2
+
+[The file-naming scheme] See section 7
+
+
+5.1.2 The `denote-history-completion-in-prompts' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The user option `denote-history-completion-in-prompts' toggles history
+  completion in all `denote-prompts-with-history-as-completion'.
+
+  When this user option is set to a non-nil value, Denote will use
+  minibuffer history entries as completion candidates in all of the
+  `denote-prompts-with-history-as-completion'. Those will show previous
+  inputs from their respective history as possible values to select,
+  either to (i) re-insert them verbatim or (ii) with the intent to edit
+  them further (depending on the minibuffer user interface, one can
+  select a candidate with `TAB' without exiting the minibuffer, as
+  opposed to what `RET' normally does by selecting and exiting).
+
+  When this user option is set to a nil value, all of the
+  `denote-prompts-with-history-as-completion' will not use minibuffer
+  completion: they will just prompt for a string of characters. Their
+  history is still available through all the standard ways of retrieving
+  minibuffer history, such as with the command
+  `previous-history-element'.
+
+  History completion still allows arbitrary values to be provided as
+  input: they do not have to match the available minibuffer completion
+  candidates.
+
+  Note that some prompts, like `denote-keywords-prompt', always use
+  minibuffer completion, due to the specifics of their data.
+
+  [ Consider enabling the built-in `savehist-mode' to persist minibuffer
+    histories between sessions.]
+
+
+5.1.3 The `denote-templates' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The user option `denote-templates' is an alist of content templates
+  for new notes.  A template is arbitrary text that Denote will add to a
+  newly created note right below the front matter.
+
+  Templates are expressed as a `(KEY . VALUE)' association.
+
+  • The `KEY' is the name which identifies the template.  It is an
+    arbitrary symbol, such as `report', `memo', `statement'.
+
+  • The `VALUE' is either a string or the symbol of a function.
+
+    • If it is a string, it is ordinary text that Denote will insert
+      as-is.  It can contain newline characters to add spacing.  The
+      manual of Denote contains examples on how to use the `concat'
+      function, beside writing a generic string.
+
+    • If it is a function, it is called without arguments and is
+      expected to return a string.  Denote will call the function and
+      insert the result in the buffer.
+
+  The user can choose a template either by invoking the command
+  `denote-template' or by changing the user option `denote-prompts' to
+  always prompt for a template when calling the `denote' command.
+
+  [The denote-prompts option].
+
+  [Convenience commands for note creation].
+
+  Templates can be written directly as one large string.  For example
+  (the `\n' character is read as a newline):
+
+  ┌────
+  │ (setq denote-templates
+  │       '((report . "* Some heading\n\n* Another heading")
+  │ 	(memo . "* Some heading
+  │ 
+  │ * Another heading
+  │ 
+  │ ")))
+  └────
+
+  Long strings may be easier to type but interpret indentation
+  literally.  Also, they do not scale well.  A better way is to use some
+  Elisp code to construct the string.  This would typically be the
+  `concat' function, which joins multiple strings into one.  The
+  following is the same as the previous example:
+
+  ┌────
+  │ (setq denote-templates
+  │       `((report . "* Some heading\n\n* Another heading")
+  │ 	(memo . ,(concat "* Some heading"
+  │ 			 "\n\n"
+  │ 			 "* Another heading"
+  │ 			 "\n\n"))))
+  └────
+
+  Notice that to evaluate a function inside of an alist we use the
+  backtick to quote the alist (NOT the straight quote) and then prepend
+  a comma to the expression that should be evaluated.  The `concat' form
+  here is not sensitive to indentation, so it is easier to adjust for
+  legibility.
+
+  For when the `VALUE' is a function, we have this:
+
+  ┌────
+  │ (setq denote-templates
+  │       `((report . "* Some heading\n\n* Another heading")
+  │ 	(blog . my-denote-template-function-for-blog) ; a function to return a string
+  │ 	(memo . ,(concat "* Some heading"
+  │ 			 "\n\n"
+  │ 			 "* Another heading"
+  │ 			 "\n\n"))))
+  └────
+
+  In this example, `my-denote-template-function-for-blog' is a function
+  that returns a string. Denote will take care to insert it in the
+  buffer.
+
+  DEV NOTE: We do not provide more examples at this point, though feel
+  welcome to ask for help if the information provided herein is not
+  sufficient.  We shall expand the manual accordingly.
+
+
+[The denote-prompts option] See section 5.1.1
+
+[Convenience commands for note creation] See section 5.1.4
+
+
+5.1.4 Convenience commands for note creation
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  Sometimes the user needs to create a note that has different
+  requirements from those of `denote' ([Standard note creation]).  While
+  this can be achieved globally by changing the `denote-prompts' user
+  option, there are cases where an ad-hoc method is the appropriate one
+  ([The denote-prompts option]).
+
+  To this end, Denote provides the following interactive convenience
+  commands for note creation. They all work by appending a new prompt to
+  the existing `denote-prompts'.
+
+  Create note by specifying file type
+        The `denote-type' command creates a note while prompting for a
+        file type.
+
+        This is the equivalent of calling `denote' when `denote-prompts'
+        has the `file-type' prompt appended to its existing prompts. In
+        practical terms, this lets you produce, say, a note in Markdown
+        even though you normally write in Org ([Standard note
+        creation]).
+
+        The `denote-create-note-using-type' is an alias of
+        `denote-type'.
+
+  Create note using a date
+        Normally, Denote reads the current date and time to construct
+        the unique identifier of a newly created note ([Standard note
+        creation]).  Sometimes, however, the user needs to set an
+        explicit date+time value.
+
+        This is where the `denote-date' command comes in.  It creates a
+        note while prompting for a date.  The date can be in
+        YEAR-MONTH-DAY notation like `2022-06-30' or that plus the time:
+        `2022-06-16 14:30'.
+
+        [The denote-date-prompt-use-org-read-date option].
+
+        This is the equivalent of calling `denote' when `denote-prompts'
+        has the `date' prompt appended to its existing prompts.
+
+        The `denote-create-note-using-date' is an alias of
+        `denote-date'.
+
+  Create note in a specific directory
+        The `denote-subdirectory' command creates a note while prompting
+        for a subdirectory.  Available candidates include the value of
+        the variable `denote-directory' and any subdirectory thereof
+        (Denote does not create subdirectories).
+
+        This is the equivalent of calling `denote' when `denote-prompts'
+        has the `subdirectory' prompt appended to its existing prompts.
+
+        The `denote-create-note-in-subdirectory' is a more descriptive
+        alias of `denote-subdirectory'.
+
+  Create note and add a template
+        The `denote-template' command creates a new note and inserts the
+        specified template below the front matter ([The denote-templates
+        option]).  Available candidates for templates are specified in
+        the user option `denote-templates'.
+
+        This is the equivalent of calling `denote' when `denote-prompts'
+        has the `template' prompt appended to its existing prompts.
+
+        The `denote-create-note-with-template' is an alias of the
+        command `denote-template', meant to help with discoverability.
+
+  Create note with a signature
+        The `denote-signature' command first prompts for an arbitrary
+        string to use in the optional `SIGNATURE' field of the file name
+        and then asks for a title and keywords.  Signatures are
+        arbitrary strings of alphanumeric characters which can be used
+        to establish sequential relations between file at the level of
+        their file name (e.g. 1, 1a, 1b, 1b1, 1b2, …).
+
+        This is the equivalent of calling `denote' when `denote-prompts'
+        has the `signature' prompt appended to its existing prompts.
+
+        The `denote-create-note-using-signature' is an alias of the
+        command `denote-signature' intended to make the functionality
+        more discoverable.
+
+
+[Standard note creation] See section 5.1
+
+[The denote-prompts option] See section 5.1.1
+
+[The denote-date-prompt-use-org-read-date option] See section 5.1.7
+
+[The denote-templates option] See section 5.1.3
+
+◊ 5.1.4.1 Write your own convenience commands
+
+  The convenience commands we provide only cover some basic use-cases
+  ([Convenience commands for note creation]). The user may require
+  combinations that are not covered, such as to prompt for a template
+  and for a subdirectory, instead of only one of the two. To this end,
+  we show how to follow the code we use in Denote to write your own
+  variants of those commands.
+
+  First let’s take a look at the definition of one of those commands.
+  They all look the same, but we use `denote-subdirectory' for this
+  example:
+
+  ┌────
+  │ (defun denote-subdirectory ()
+  │   "Create note while prompting for a subdirectory.
+  │ 
+  │ Available candidates include the value of the variable
+  │ `denote-directory' and any subdirectory thereof.
+  │ 
+  │ This is the equivalent of calling `denote' when `denote-prompts'
+  │ has the `subdirectory' prompt appended to its existing prompts."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let ((denote-prompts (denote-add-prompts '(subdirectory))))
+  │     (call-interactively #'denote)))
+  └────
+
+  The hyphenated word after `defun' is the name of the function. It has
+  to be unique. Then we have the documentation string (or “doc string”)
+  which is for the user’s convenience.
+
+  This function is `interactive', meaning that it can be called via
+  `M-x' or be assigned to a key binding. Then we have the local binding
+  of the `denote-prompts' to the desired combination (“local” means
+  specific to this function without affecting other contexts). Lastly,
+  it calls the standard `denote' command interactively, so it uses all
+  the prompts in their specified order.
+
+  The function call `(denote-add-prompts '(subdirectory))' will append
+  the subdirectory prompt to the existing value of the `denote-prompts'.
+  If, for example, the default value is `'(title keywords)' (to prompt
+  for a title and then for keywords), it will become `'(subdirectory
+  title keywords)' inside the context of this `let'. Remember that this
+  is “local”, so the global value of `denote-prompts' remains
+  unaffected.
+
+  Now let’s say we want to have a command that (i) asks for a template
+  (ii) for a subdirectory ([The denote-templates option]), and (iii)
+  then goes through the remaining `denote-prompts'. All we need to do is
+  tweak the `let' bound value of `denote-prompts' and give our command a
+  unique name:
+
+  ┌────
+  │ ;; Like `denote-subdirectory' but also ask for a template
+  │ (defun my-denote-subdirectory-with-template ()
+  │   "Create note while also prompting for a template and subdirectory.
+  │ 
+  │ This is the equivalent of calling `denote' when `denote-prompts' has the
+  │ `subdirectory' and `template' prompts appended to its existing prompts."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let ((denote-prompts (denote-add-prompts '(subdirectory template))))
+  │     (call-interactively #'denote)))
+  └────
+
+  The tweaks to `denote-prompts' determine how the command will behave
+  ([The denote-prompts option]). Use this paradigm to write your own
+  variants which you can then assign to keys, invoke with `M-x', or add
+  to the list of commands available at the `denote-command-prompt'
+  ([Choose which commands to prompt for]).
+
+  In the above scenario, we are using the `denote-add-prompts' function,
+  which appends whatever prompts we want to the existing value of
+  `denote-prompts'. If the user prefers to completely override the
+  `denote-prompts', they can set the value outright:
+
+  ┌────
+  │ (defun my-denote-subdirectory-with-template-title-and-keywords ()
+  │   "Create a note while prompting for subdirectory, template, title, and keywords.
+  │ 
+  │ This is the equivalent of calling `denote' when `denote-prompts' has the
+  │ value '(template subdirectory title keywords)."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let ((denote-prompts '(subdirectory template title keywords)))
+  │     (call-interactively #'denote)))
+  └────
+
+
+  [Convenience commands for note creation] See section 5.1.4
+
+  [The denote-templates option] See section 5.1.3
+
+  [The denote-prompts option] See section 5.1.1
+
+  [Choose which commands to prompt for] See section 10
+
+
+5.1.5 The `denote-save-buffers' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The user option `denote-save-buffer-after-creation' controls whether
+  commands that create new notes save their buffer outright.
+
+  The default behaviour of commands such as `denote' (or related) is to
+  not save the buffer they create ([Points of entry]). This gives the
+  user the chance to review the text before writing it to a file. The
+  user may choose to delete the unsaved buffer, thus not creating a new
+  note ([The `denote-save-buffer-after-creation' option]).
+
+  This option also applies to notes affected by the renaming commands
+  (`denote-rename-file' and related).
+
+  If this user option is set to a non-nil value, such buffers are saved
+  automatically. The assumption is that the user who opts in to this
+  feature is familiar with the `denote-rename-file' operation (or
+  related) and knows it is reliable ([Renaming files]).
+
+  [The `denote-kill-buffers' option].
+
+
+[Points of entry] See section 5
+
+[The `denote-save-buffer-after-creation' option] See section 5.1.5
+
+[Renaming files] See section 6
+
+[The `denote-kill-buffers' option] See section 5.1.6
+
+
+5.1.6 The `denote-kill-buffers' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The user option `denote-kill-buffers' controls whether to kill a
+  buffer that was generated by a Denote command. This can happen when
+  creating a new file or renaming an existing one.
+
+  • [Points of entry].
+  • [Renaming files].
+
+  The default behaviour of creation or renaming commands such as
+  `denote' or `denote-rename-file' is to not kill the buffer they create
+  or modify at the end of their operation. The idea is to give the user
+  the chance to confirm that everything is in order.
+
+  If this user option is nil (the default), buffers affected by a
+  creation or renaming command are not automatically killed.
+
+  If set to the symbol `on-creation', new notes are automatically
+  killed.
+
+  If set to the symbol `on-rename', renamed notes are automatically
+  killed.
+
+  If set to t, new and renamed notes are killed.
+
+  If a buffer is killed, it is also saved, as if `denote-save-buffers'
+  were t ([The `denote-save-buffers' option]).
+
+  In all cases, if the buffer already existed before the Denote
+  operation it is NOT automatically killed.
+
+
+[Points of entry] See section 5
+
+[Renaming files] See section 6
+
+[The `denote-save-buffers' option] See section 5.1.5
+
+
+5.1.7 The `denote-date-prompt-use-org-read-date' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  By default, Denote uses its own simple prompt for date or date+time
+  input ([The denote-prompts option]).  This is done when the
+  `denote-prompts' option includes a `date' symbol and/or when the user
+  invokes the `denote-date' command.
+
+  Users who want to benefit from the more advanced date selection method
+  that is common in interactions with Org mode, can set the user option
+  `denote-date-prompt-use-org-read-date' to a non-nil value.
+
+
+[The denote-prompts option] See section 5.1.1
+
+
+5.2 Create note using Org capture
+─────────────────────────────────
+
+  For integration with `org-capture', the user must first add the
+  relevant template.  Such as:
+
+  ┌────
+  │ (with-eval-after-load 'org-capture
+  │   (add-to-list 'org-capture-templates
+  │ 	       '("n" "New note (with Denote)" plain
+  │ 		 (file denote-last-path)
+  │ 		 #'denote-org-capture
+  │ 		 :no-save t
+  │ 		 :immediate-finish nil
+  │ 		 :kill-buffer t
+  │ 		 :jump-to-captured t)))
+  └────
+
+  Once the template is added, it is accessed from the specified key. If,
+  for instance, `org-capture' is bound to `C-c c', then the note
+  creation is initiated with `C-c c n', per the above snippet. After
+  that, the process is the same as with invoking `denote' directly,
+  namely: a prompt for a title followed by a prompt for keywords,
+  assuming the default settings ([Standard note creation]). Concretely,
+  this method always respects the value of the user option
+  `denote-prompts' ([The `denote-prompts' option]).
+
+  It is also possible to define templates that have specific prompts or
+  certain values set, for which there is no prompt:
+
+  • [Create note with specific values using Org capture]
+  • [Create note with specific prompts using Org capture]
+
+  Users may prefer to leverage `org-capture' in order to extend file
+  creation with the specifiers described in the `org-capture-templates'
+  documentation (such as to capture the active region and/or create a
+  hyperlink pointing to the given context).
+
+  IMPORTANT.  Due to the particular file-naming scheme of Denote, which
+  is derived dynamically, such specifiers or other arbitrary text cannot
+  be written directly in the template.  Instead, they have to be
+  assigned to the user option `denote-org-capture-specifiers', which is
+  interpreted by the function `denote-org-capture'.  Example with our
+  default value:
+
+  ┌────
+  │ (setq denote-org-capture-specifiers "%l\n%i\n%?")
+  └────
+
+  Note that `denote-org-capture' ignores the `denote-file-type': it
+  always sets the Org file extension for the created note to ensure that
+  the capture process works as intended, especially for the desired
+  output of the `denote-org-capture-specifiers'.
+
+  [ You may not need `org-capture' to do what you want ([Write your own
+  convenience commands]). ]
+
+
+[Standard note creation] See section 5.1
+
+[The `denote-prompts' option] See section 5.1.1
+
+[Create note with specific values using Org capture] See section 5.4
+
+[Create note with specific prompts using Org capture] See section 5.3
+
+[Write your own convenience commands] See section 5.1.4.1
+
+
+5.3 Create note with specific prompts using Org capture
+───────────────────────────────────────────────────────
+
+  This section assumes knowledge of how Denote+org-capture work, as
+  explained in the previous section ([Create note using Org capture]).
+
+  The previous section shows how to define an Org capture template that
+  always prompts for whatever is set in the user option `denote-prompts'
+  (title and keywords, by default). There are, however, cases where the
+  user wants more control over what kind of input Denote will prompt
+  for. To this end, we provide the function
+  `denote-org-capture-with-prompts'.  Below we explain it and then show
+  some examples of how to use it.
+
+  The `denote-org-capture-with-prompts' is like `denote-org-capture' but
+  with optional prompt parameters.
+
+  When called without arguments, it does not prompt for anything.  It
+  just returns the front matter with title and keyword fields empty and
+  the date and identifier fields specified.  It also makes the file name
+  consist of only the identifier plus the Org file name extension ([The
+  file-naming scheme]).
+
+  Otherwise, it produces a minibuffer prompt for every non-nil value
+  that corresponds to the `TITLE', `KEYWORDS', `SUBDIRECTORY', `DATE',
+  and `TEMPLATE' arguments.  The prompts are those used by the standard
+  `denote' command and all of its utility commands ([Points of entry]).
+
+  When returning the contents that fill in the Org capture template, the
+  sequence is as follows: front matter, `TEMPLATE', and then the value
+  of the user option `denote-org-capture-specifiers'.
+
+  Important note: in the case of `SUBDIRECTORY' actual subdirectories
+  must exist—Denote does not create them.  Same principle for `TEMPLATE'
+  as templates must exist and are specified in the user option
+  `denote-templates'.
+
+  This is how one can incorporate `denote-org-capture-with-prompts' in
+  their Org capture templates.  Instead of passing a generic `t' which
+  makes it hard to remember what the argument means, we use semantic
+  keywords like `:title' for our convenience (internally this does not
+  matter as the value still counts as non-nil, so `:foo' for `TITLE' is
+  treated the same as `:title' or `t').
+
+  ┌────
+  │ ;; This prompts for TITLE, KEYWORDS, and SUBDIRECTORY
+  │ (add-to-list 'org-capture-templates
+  │ 	     '("N" "New note with prompts (with denote.el)" plain
+  │ 	       (file denote-last-path)
+  │ 	       (function
+  │ 		(lambda ()
+  │ 		  (denote-org-capture-with-prompts :title :keywords :subdirectory)))
+  │ 	       :no-save t
+  │ 	       :immediate-finish nil
+  │ 	       :kill-buffer t
+  │ 	       :jump-to-captured t))
+  │ 
+  │ ;; This prompts only for SUBDIRECTORY
+  │ (add-to-list 'org-capture-templates
+  │ 	     '("N" "New note with prompts (with denote.el)" plain
+  │ 	       (file denote-last-path)
+  │ 	       (function
+  │ 		(lambda ()
+  │ 		  (denote-org-capture-with-prompts nil nil :subdirectory)))
+  │ 	       :no-save t
+  │ 	       :immediate-finish nil
+  │ 	       :kill-buffer t
+  │ 	       :jump-to-captured t))
+  │ 
+  │ ;; This prompts for TITLE and SUBDIRECTORY
+  │ (add-to-list 'org-capture-templates
+  │ 	     '("N" "New note with prompts (with denote.el)" plain
+  │ 	       (file denote-last-path)
+  │ 	       (function
+  │ 		(lambda ()
+  │ 		  (denote-org-capture-with-prompts :title nil :subdirectory)))
+  │ 	       :no-save t
+  │ 	       :immediate-finish nil
+  │ 	       :kill-buffer t
+  │ 	       :jump-to-captured t))
+  └────
+
+  [ You may not need `org-capture' to do what you want ([Write your own
+  convenience commands]). ]
+
+
+[Create note using Org capture] See section 5.2
+
+[The file-naming scheme] See section 7
+
+[Points of entry] See section 5
+
+[Write your own convenience commands] See section 5.1.4.1
+
+
+5.4 Create note with specific values using Org capture
+──────────────────────────────────────────────────────
+
+  The ordinary procedure to create a note with `org-capture' respects
+  the value of the user option `denote-prompts' ([Create note using Org
+  capture]): the user is prompted for all the values they have
+  configured (title and keywords, by default). Sometimes, there is no
+  need to have a certain prompt because the value of it will be
+  constant. For example, the user wants to have a template that (i)
+  respects the `denote-prompts' but (ii) puts the new note in an
+  existing subdirectory of the `denote-directory'. The following code
+  block does exactly that.
+
+  [ It also is possible to have a template that deviates from
+    `denote-prompts' and prompts for specific values ([Create note with
+    specific prompts using Org capture]). ]
+
+  ┌────
+  │ (with-eval-after-load 'org-capture
+  │   (add-to-list 'org-capture-templates
+  │ 	       '("r" "New reference (with Denote)" plain
+  │ 		 (file denote-last-path)
+  │ 		 (function
+  │ 		  (lambda ()
+  │ 		    (let ((denote-use-directory (expand-file-name "reference" (denote-directory))))
+  │ 		      (denote-org-capture))))
+  │ 		 :no-save t
+  │ 		 :immediate-finish nil
+  │ 		 :kill-buffer t
+  │ 		 :jump-to-captured t)))
+  └────
+
+  The values one may predefine in this way are via these variables ([For
+  developers or advanced users]):
+
+  ⁃ `denote-use-date'
+
+  ⁃ `denote-use-directory'
+
+  ⁃ `denote-use-file-type'
+
+  ⁃ `denote-use-keywords'
+
+  ⁃ `denote-use-signature'
+
+  ⁃ `denote-use-template'
+
+  ⁃ `denote-use-title'
+
+  When there exists a binding for the aforementioned variables, the
+  corresponding prompt is always skipped. It is thus paramount to never
+  set those variables outside the scope of a `let' (or equivalent).
+
+  With those granted, here is another example scenario where the user
+  wants to have a constant value for the subdirectory but also be
+  prompted for a date.
+
+  ┌────
+  │ (with-eval-after-load 'org-capture
+  │   (add-to-list 'org-capture-templates
+  │ 	       '("j" "New journal (with Denote)" plain
+  │ 		 (file denote-last-path)
+  │ 		 (function
+  │ 		  (lambda ()
+  │ 		    ;; The "journal" subdirectory of the `denote-directory'---this must exist!
+  │ 		    (let* ((denote-use-directory (expand-file-name "journal" (denote-directory)))
+  │ 			   ;; Use the existing `denote-prompts' as well as the one for a date.
+  │ 			   (denote-prompts (denote-add-prompts '(date))))
+  │ 		      (denote-org-capture))))
+  │ 		 :no-save t
+  │ 		 :immediate-finish nil
+  │ 		 :kill-buffer t
+  │ 		 :jump-to-captured t)))
+  └────
+
+  The above highlights the hackability of the Denote code base, namely,
+  how we can affect the behaviour of the underlying `denote' command by
+  `let' binding variables that affect every aspect of its behaviour
+  ([Write your own convenience commands]).
+
+
+[Create note using Org capture] See section 5.2
+
+[Create note with specific prompts using Org capture] See section 5.3
+
+[For developers or advanced users] See section 20
+
+[Write your own convenience commands] See section 5.1.4.1
+
+
+5.5 Create a note with the region’s contents
+────────────────────────────────────────────
+
+  The command `denote-region' takes the contents of the active region
+  and then calls the `denote' command.  Once a new note is created, it
+  inserts the contents of the region therein.  This is useful to quickly
+  elaborate on some snippet of text or capture it for future reference.
+
+  When the `denote-region' command is called with an active region, it
+  finalises its work by calling
+  `denote-region-after-new-note-functions'.  This is an abnormal hook,
+  meaning that the functions added to it are called with arguments.  The
+  arguments are two, representing the beginning and end positions of the
+  newly inserted text.
+
+  A common use-case for Org mode users is to call the command
+  `org-insert-structure-template' after a region is inserted.  Emacs
+  will thus prompt for a structure template, such as the one
+  corresponding to a source block.  In this case the function added to
+  `denote-region-after-new-note-functions' does not actually need
+  aforementioned arguments: it can simply declare those as ignored by
+  prefixing the argument names with an underscore (an underscore is
+  enough, but it is better to include a name for clarity).  For example,
+  the following will prompt for a structure template as soon as
+  `denote-region' is done:
+
+  ┌────
+  │ (defun my-denote-region-org-structure-template (_beg _end)
+  │   (when (derived-mode-p 'org-mode)
+  │     (activate-mark)
+  │     (call-interactively 'org-insert-structure-template)))
+  │ 
+  │ (add-hook 'denote-region-after-new-note-functions #'my-denote-region-org-structure-template)
+  └────
+
+  Remember that `denote-region-after-new-note-functions' are not called
+  if `denote-region' is used without an active region.
+
+
+5.5.1 A custom `denote-region' that references the source
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The `denote-region' command simply creates a new note and includes the
+  highlighted region’s contents as the initial text of the note ([Create
+  a note with the region’s contents]).  However, users may want a more
+  streamlined workflow where the command is always used to capture
+  quotes from other sources. In this example, we consider “other
+  sources” to come from Emacs EWW buffers (with `M-x eww') or regular
+  files outside the `denote-directory'.
+
+  [ This is a proof-of-concept that does not cover all cases. If anyone
+    wants to use a variation of this, just let me know. ]
+
+  ┌────
+  │ ;; Variant of `my-denote-region' to reference the source
+  │ 
+  │ (defun my-denote-region-get-source-reference ()
+  │   "Get a reference to the source for use with `my-denote-region'.
+  │ The reference is a URL or an Org-formatted link to a file."
+  │   ;; We use a `cond' here because we can extend it to cover move
+  │   ;; cases.
+  │   (cond
+  │    ((derived-mode-p 'eww-mode)
+  │     (plist-get eww-data :url))
+  │    ;; Here we are just assuming an Org format.  We can make this more
+  │    ;; involved, if needed.
+  │    (buffer-file-name
+  │     (format "[[file:%s][%s]]" buffer-file-name (buffer-name)))))
+  │ 
+  │ (defun my-denote-region ()
+  │   "Like `denote-region', but add the context afterwards.
+  │ For how the context is retrieved, see `my-denote-region-get-source-reference'."
+  │   (interactive)
+  │   (let ((context (my-denote-region-get-source-reference)))
+  │     (call-interactively 'denote-region)
+  │     (when context
+  │       (goto-char (point-max))
+  │       (insert "\n")
+  │       (insert context))))
+  │ 
+  │ ;; Add quotes around snippets of text captured with `denote-region' or `my-denote-region'.
+  │ 
+  │ (defun my-denote-region-org-structure-template (beg end)
+  │   "Automatically quote (with Org syntax) the contents of `denote-region'."
+  │   (when (derived-mode-p 'org-mode)
+  │     (goto-char end)
+  │     (insert "#+end_quote\n")
+  │     (goto-char beg)
+  │     (insert "#+begin_quote\n")))
+  │ 
+  │ (add-hook 'denote-region-after-new-note-functions #'my-denote-region-org-structure-template)
+  └────
+
+  With the above in place, calling the `my-denote-region' command does
+  the following:
+
+  • It creates a new note as usual, prompting for the relevant data.
+  • Inserts the contents of the region below the front matter of the new
+    note.
+  • Adds Org-style quotation block markers around the inserted region.
+  • Adds a link to the URL or file from where `my-denote-region' was
+    called.
+
+
+[Create a note with the region’s contents] See section 5.5
+
+
+5.6 Open an existing note or create it if missing
+─────────────────────────────────────────────────
+
+  Sometimes it is necessary to briefly interrupt the ongoing writing
+  session to open an existing note or, if that is missing, to create it.
+  This happens when a new tangential thought occurs and the user wants
+  to confirm that an entry for it is in place.  To this end, Denote
+  provides the command `denote-open-or-create' as well as its more
+  flexible counterpart `denote-open-or-create-with-command'.
+
+  The `denote-open-or-create' prompts to visit a file in the
+  `denote-directory'.  At this point, the user must type in search terms
+  that match a file name.  If the input does not return any matches and
+  the user confirms their choice to proceed (usually by typing RET
+  twice, depending on the minibuffer settings), `denote-open-or-create'
+  will call the `denote' command interactively to create a new note.  It
+  will then use whatever prompts `denote' normally has, per the user
+  option `denote-prompts' ([Standard note creation]).  If the title
+  prompt is involved (the default behaviour), the
+  `denote-open-or-create' sets up this prompt to have the previous input
+  as the default title of the note to-be-created.  This means that the
+  user can type RET at the empty prompt to re-use what they typed in
+  previously.  Commands to use previous inputs from the history are also
+  available (`M-p' or `M-n' in the minibuffer, which call
+  `previous-history-element' and `next-history-element' by default).
+  Accessing the history is helpful to, for example, make further edits
+  to the available text.
+
+  The `denote-open-or-create-with-command' is like the above, except
+  when it is about to create the new note it first prompts for the
+  specific file-creating command to use ([Points of entry]).  For
+  example, the user may want to specify a signature for this new file,
+  so they can select the `denote-signature' command.
+
+  Denote provides similar functionality for linking to an existing note
+  or creating a new one ([Link to a note or create it if missing]).
+
+
+[Standard note creation] See section 5.1
+
+[Points of entry] See section 5
+
+[Link to a note or create it if missing] See section 9.10
+
+
+5.7 Maintain separate directory silos for notes
+───────────────────────────────────────────────
+
+  The user option `denote-directory' accepts a value that represents the
+  path to a directory, such as `~/Documents/notes'. Normally, the user
+  will have one place where they store all their notes, in which case
+  this arrangement shall suffice.
+
+  There is, however, the possibility to maintain separate directories of
+  notes. By “separate”, we mean that they do not communicate with each
+  other: no linking between them, no common keywords, nothing. Think of
+  the scenario where one set of notes is for private use and another is
+  for an employer. We call these separate directories “silos”.
+
+  To create silos, the user must specify a local variable at the root of
+  the desired directory. This is done by creating a `.dir-locals.el'
+  file, with the following contents:
+
+  ┌────
+  │ ;;; Directory Local Variables.  For more information evaluate:
+  │ ;;;
+  │ ;;;     (info "(emacs) Directory Variables")
+  │ 
+  │ ((nil . ((denote-directory . "/path/to/silo/"))))
+  └────
+
+  When inside the directory that contains this `.dir-locals.el' file,
+  all Denote commands/functions for note creation, linking, the
+  inference of available keywords, et cetera will use the silo as their
+  point of reference ([The `denote-silo' package which formerly was
+  `denote-silo-extras.el']).  They will not read the global value of
+  `denote-directory'. The global value of `denote-directory' is read
+  everywhere else except the silos.
+
+  In concrete terms, this is a representation of the directory
+  structures (notice the `.dir-locals.el' file is needed only for the
+  silos):
+
+  ┌────
+  │ ;; This is the global value of 'denote-directory' (no need for a .dir-locals.el)
+  │ ~/Documents/notes
+  │ |-- 20210303T120534--this-is-a-test__journal_philosophy.txt
+  │ |-- 20220303T120534--another-sample__journal_testing.md
+  │ `-- 20220620T181255--the-third-test__keyword.org
+  │ 
+  │ ;; A silo with notes for the employer
+  │ ~/different/path/to/notes-for-employer
+  │ |-- .dir-locals.el
+  │ |-- 20210303T120534--this-is-a-test__conference.txt
+  │ |-- 20220303T120534--another-sample__meeting.md
+  │ `-- 20220620T181255--the-third-test__keyword.org
+  │ 
+  │ ;; Another silo with notes for my volunteering
+  │ ~/different/path/to/notes-for-volunteering
+  │ |-- .dir-locals.el
+  │ |-- 20210303T120534--this-is-a-test__activism.txt
+  │ |-- 20220303T120534--another-sample__teambuilding.md
+  │ `-- 20220620T181255--the-third-test__keyword.org
+  └────
+
+  It is possible to configure other user options of Denote to have a
+  silo-specific value.  For example, this one changes the
+  `denote-known-keywords' only for this particular silo:
+
+  ┌────
+  │ ;;; Directory Local Variables.  For more information evaluate:
+  │ ;;;
+  │ ;;;     (info "(emacs) Directory Variables")
+  │ 
+  │ ((nil . ((denote-directory . "/path/to/silo/")
+  │ 	 (denote-known-keywords . ("food" "drink")))))
+  └────
+
+  This one is like the above, but also disables `denote-infer-keywords':
+
+  ┌────
+  │ ;;; Directory Local Variables.  For more information evaluate:
+  │ ;;;
+  │ ;;;     (info "(emacs) Directory Variables")
+  │ 
+  │ ((nil . ((denote-directory . "/path/to/silo/")
+  │ 	 (denote-known-keywords . ("food" "drink"))
+  │ 	 (denote-infer-keywords . nil))))
+  └────
+
+  To expand the list of local variables to, say, cover specific major
+  modes, we can do something like this:
+
+  ┌────
+  │ ;;; Directory Local Variables.  For more information evaluate:
+  │ ;;;
+  │ ;;;     (info "(emacs) Directory Variables")
+  │ 
+  │ ((nil . ((denote-directory . "/path/to/silo/")
+  │ 	 (denote-known-keywords . ("food" "drink"))
+  │ 	 (denote-infer-keywords . nil)))
+  │  (org-mode . ((org-hide-emphasis-markers . t)
+  │ 	      (org-hide-macro-markers . t)
+  │ 	      (org-hide-leading-stars . t))))
+  └────
+
+  As not all user options have a “safe” local value, Emacs will ask the
+  user to confirm their choice and to store it in the Custom code
+  snippet that is normally appended to init file (or added to the file
+  specified by the user option `custom-file').
+
+  Finally, it is possible to have a `.dir-locals.el' for subdirectories
+  of any `denote-directory'.  Perhaps to specify a different set of
+  known keywords, while not making the subdirectory a silo in its own
+  right.  We shall not expand on such an example, as we trust the user
+  to experiment with the best setup for their workflow.
+
+  Feel welcome to ask for help if the information provided herein is not
+  sufficient.  The manual shall be expanded accordingly.
+
+
+[The `denote-silo' package which formerly was `denote-silo-extras.el']
+See section 18.5
+
+5.7.1 Make Org export work with silos
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The Org export infrastructure is designed to ignore directory-local
+  variables. This means that Denote silos, which depend on setting the
+  local value of the variable `denote-directory', do not work as
+  intended ([Maintain separate directory silos for notes]). More
+  specifically, the Denote links do not resolve to the right file,
+  because their path is changed during the export process.
+
+  I brought this to the attention of the Org maintainer. The guidance
+  from their side is to use the `#+bind' keyword to specify a local
+  value for the `denote-directory':
+  <https://lists.gnu.org/archive/html/emacs-orgmode/2024-06/msg00206.html>.
+  The prerequisite is to set `org-export-allow-bind-keywords' to a
+  non-nil value:
+
+  ┌────
+  │ (setq org-export-allow-bind-keywords t)
+  └────
+
+  I do not think this is an elegant solution, but here are two possible
+  ways to go about it, anyway:
+
+  1. Manually add the `#+bind' keyword to each file you want to export.
+     It has to be like this:
+
+     ┌────
+     │ #+bind: denote-directory "/path/to/silo/"
+     └────
+
+  2. Alternatively, you can make the Org front matter that Denote uses
+     for new files automatically include the `#+bind' keyword with its
+     desired value. Here is a complete `.dir-locals.el' which (i)
+     defines the silo and (ii) modifies the `denote-org-front-matter'
+     accordingly:
+
+     ┌────
+     │    ;;; Directory Local Variables.  For more information evaluate:
+     │    ;;;
+     │    ;;;     (info "(emacs) Directory Variables")
+     │ 
+     │    ((nil . ((denote-directory . "/path/to/silo/")
+     │ 	    (denote-org-front-matter .
+     │ 	     "#+title:      %s
+     │ #+date:       %s
+     │ #+filetags:   %s
+     │ #+identifier: %s
+     │ #+bind:       denote-directory \"/path/to/silo/\"
+     │ \n"))))
+     └────
+
+     [ Note that if you are reading the Org source of this manual, you
+       need to use the command `org-edit-special' on the above code
+       blocks before copying the code. This is because Org automatically
+       prepends a comma to disambiguate those entries from actual
+       keywords of the current file. ]
+
+
+[Maintain separate directory silos for notes] See section 5.7
+
+
+5.8 Exclude certain files from file prompts
+───────────────────────────────────────────
+
+  The user option `denote-excluded-files-regexp' is a regular expression
+  that matches files names which should be excluded from all Denote file
+  prompts. Such prompts are present when linking to a file with one of
+  the many commands, like `denote-link' ([Linking notes]), or when
+  trying to open a file that may or may not exist ([Open an existing
+  note or create it if missing]).
+
+  Functions that check for files include `denote-directory-files' and
+  `denote-file-prompt'.
+
+  The match is performed with `string-match-p'.
+
+  [For developers or advanced users].
+
+
+[Linking notes] See section 9
+
+[Open an existing note or create it if missing] See section 5.6
+
+[For developers or advanced users] See section 20
+
+
+5.9 Exclude certain directories from all operations
+───────────────────────────────────────────────────
+
+  The user option `denote-excluded-directories-regexp' instructs all
+  Denote functions that read or check file/directory names to omit
+  directories that match the given regular expression.  The regexp needs
+  to match only the name of the directory, not its full path.
+
+  Affected operations include file prompts and functions that return the
+  available files in the value of the user option `denote-directory'
+  ([Maintain separate directory silos for notes]).
+
+  File prompts are used by several commands, such as `denote-link' and
+  `denote-subdirectory'.
+
+  Functions that check for files include `denote-directory-files' and
+  `denote-directory-subdirectories'.
+
+  The match is performed with `string-match-p'.
+
+  [For developers or advanced users].
+
+
+[Maintain separate directory silos for notes] See section 5.7
+
+[For developers or advanced users] See section 20
+
+
+5.10 Exclude certain keywords from being inferred
+─────────────────────────────────────────────────
+
+  The user option `denote-excluded-keywords-regexp' omits keywords that
+  match a regular expression from the list of inferred keywords.
+
+  Keywords are inferred from file names and provided at relevant prompts
+  as completion candidates when the user option `denote-infer-keywords'
+  is non-nil.
+
+  The match is performed with `string-match-p'.
+
+
+5.11 Create a controlled vocabulary for keywords
+────────────────────────────────────────────────
+
+  Denote has two ways to know about keywords: the predefined list of
+  strings specified in the user option `denote-known-keywords' as well
+  as all the keywords it finds in the files of the `denote-directory'
+  when the user option `denote-infer-keywords' is set to a non-nil value
+  ([Exclude certain keywords from being inferred]).
+
+  While this is a viable setup, users may prefer to implement a
+  “controlled vocabulary”. This is a predefined set of keywords whose
+  purpose is to avoid the creation of overly specific or inconsistent
+  keywords.
+
+  To establish such a controlled vocabulary, users need only have
+  something like this in their configuration:
+
+  ┌────
+  │ ;; Do not read keywords from files.  The only source is the `denote-known-keywords'.
+  │ (setq denote-infer-keywords nil)
+  │ 
+  │ ;; Define the list of keywords.  Each keyword is a string.
+  │ (setq denote-known-keywords (list "politics" "economics" "emacs" "philosophy"))
+  └────
+
+
+[Exclude certain keywords from being inferred] See section 5.10
+
+
+5.12 Use Denote commands from the menu bar or context menu
+──────────────────────────────────────────────────────────
+
+  Denote registers a submenu for the `menu-bar-mode'.  Users will find
+  the entry called “Denote”.  From there they can use their pointer to
+  select a command.  For a sample of how this looks, read the
+  development log:
+  <https://protesilaos.com/codelog/2023-03-31-emacs-denote-menu/>.
+
+  The command `denote-menu-bar-mode' toggles the presentation of the
+  menu. It is enabled by default.
+
+  Emacs also provides support for operations through a context menu.
+  This is typically the set of actions that are made available via a
+  right mouse click.  Users who enable `context-menu-mode' can register
+  the Denote entry for it by adding the following to their configuration
+  file:
+
+  ┌────
+  │ (add-hook 'context-menu-functions #'denote-context-menu)
+  └────
+
+
+6 Renaming files
+════════════════
+
+  Denote provides commands to rename files and update their front matter
+  where relevant.  For Denote to work, only the file name needs to be in
+  order, by following our naming conventions ([The file-naming scheme]).
+  The linking mechanism, in particular, needs just the identifier in the
+  file name ([Linking notes]).
+
+  We write front matter in notes for the user’s convenience and for
+  other tools to make use of that information (e.g. Org’s export
+  mechanism).  The renaming mechanism takes care to keep this data in
+  sync with the file name, when the user performs a change.
+
+  Renaming is useful for managing existing files created with Denote,
+  but also for converting older text files to Denote notes.  Denote’s
+  file-naming scheme is not specific to notes or text files: it is
+  relevant for all sorts of items, such as multimedia and PDFs that form
+  part of the user’s longer-term storage.  While Denote does not manage
+  such files (e.g. doesn’t create links to them), it already has all the
+  mechanisms to facilitate the task of renaming them.
+
+  All renaming commands run the `denote-after-rename-file-hook' after a
+  succesful operation ([Access the data of the latest note]). They also
+  construct the file name in accordance with the user option
+  `denote-file-name-components-order' ([Change the order of file name
+  components]).
+
+  Apart from renaming files, Denote can also rename only the buffer.
+  The idea is that the underlying file name is correct but it can be
+  easier to use shorter buffer names when displaying them on the mode
+  line or switching between then with commands like `switch-to-buffer'.
+
+  [Automatically rename Denote buffers].
+
+  [Find duplicate identifiers and put them in a Dired buffer].
+
+
+[The file-naming scheme] See section 7
+
+[Linking notes] See section 9
+
+[Access the data of the latest note] See section 19.1
+
+[Change the order of file name components] See section 7.1
+
+[Automatically rename Denote buffers] See section 12
+
+[Find duplicate identifiers and put them in a Dired buffer] See section
+6.10
+
+6.1 Rename a single file
+────────────────────────
+
+  The `denote-rename-file' command renames a file and updates existing
+  front matter if appropriate. It is possible to do the same with
+  multiple files ([Rename multiple files interactively]).
+
+  It always renames the file where it is located in the file system: it
+  never moves it to another directory.
+
+  If in Dired, it considers `FILE' to be the one at point, else it
+  prompts with minibuffer completion for one. When called from Lisp,
+  `FILE' is a file system path represented as a string.
+
+  If `FILE' has a Denote-compliant identifier, it retains it while
+  updating components of the file name referenced by the user option
+  `denote-prompts' ([The `denote-prompts' option]). By default, these
+  are the `TITLE' and `KEYWORDS'. The `SIGNATURE' is another one. When
+  called from Lisp, `TITLE' and `SIGNATURE' are strings, while
+  `KEYWORDS' is a list of strings.
+
+  If there is no identifier, `denote-rename-file' creates an identifier
+  based on the following conditions:
+
+  1. If the `denote-prompts' includes an entry for date prompts, then it
+     prompts for `DATE' and takes its input to produce a new
+     identifier. For use in Lisp, `DATE' must conform with
+     `denote-valid-date-p'.
+
+  2. If `DATE' is nil (e.g. when `denote-prompts' does not include a
+     date entry), it uses the file attributes to determine the last
+     modified date of `FILE' and formats it as an identifier.
+
+  3. As a fallback, it derives an identifier from the current date and
+     time.
+
+  4. At any rate, if the resulting identifier is not unique among the
+     files in the variable `denote-directory', it increments it such
+     that it becomes unique.
+
+  In interactive use, and assuming `denote-prompts' includes a title
+  entry, the `denote-rename-file' makes the `TITLE' prompt have
+  prefilled text in the minibuffer that consists of the current title of
+  `FILE'. The current title is either retrieved from the front matter
+  (such as the `#+title' in Org) or from the file name.
+
+  The command does the same for the `SIGNATURE' prompt, subject to
+  `denote-prompts', by prefilling the minibuffer with the current
+  signature of `FILE', if any.
+
+  Same principle for the `KEYWORDS' prompt: it converts the keywords in
+  the file name into a comma-separated string and prefills the
+  minibuffer with it (the `KEYWORDS' prompt accepts more than one
+  keywords, each separated by a comma, else the `crm-separator').
+
+  For all prompts, the `denote-rename-file' interprets an empty input as
+  an instruction to remove that file name component. For example, if a
+  `TITLE' prompt is available and `FILE' is
+  `20240211T093531--some-title__keyword1.org' then it renames `FILE' to
+  `20240211T093531__keyword1.org'.
+
+  In interactive use, if there is no entry for a file name component in
+  `denote-prompts', keep it as-is ([The `denote-prompts' option]).
+
+  When called from Lisp, the special symbol `keep-current’ can be used
+  for the TITLE, KEYWORDS, SIGNATURE and DATE parameters to keep them
+  as-is.
+
+  [ NOTE: Please check with your minibuffer user interface how to
+    provide an empty input. The Emacs default setup accepts the empty
+    minibuffer contents as they are, though popular packages like
+    `vertico' use the first available completion candidate instead. For
+    `vertico', the user must either move one up to select the prompt and
+    then type `RET' there with empty contents, or use the command
+    `vertico-exit-input' with empty contents. That Vertico command is
+    bound to `M-RET' as of this writing on 2024-02-13 08:08 +0200. ]
+
+  When renaming `FILE', the command reads its file type extension (like
+  `.org') and preserves it through the renaming process. Files that have
+  no extension are left without one.
+
+  As a final step, ask for confirmation, showing the difference between
+  old and new file names.  Do not ask for confirmation if the user
+  option `denote-rename-confirmations' does not contain the symbol
+  `modify-file-name' ([The `denote-rename-confirmations' option]).
+
+  If `FILE' has front matter for `TITLE' and `KEYWORDS', ask to rewrite
+  their values in order to reflect the new input, unless
+  `denote-rename-confirmations' lacks `rewrite-front-matter'. When the
+  `denote-save-buffers' is nil (the default), do not save the underlying
+  buffer, thus giving the user the option to double-check the result,
+  such as by invoking the command `diff-buffer-with-file'. The rewrite
+  of the `TITLE' and `KEYWORDS' in the front matter should not affect
+  the rest of the front matter.
+
+  If the file does not have front matter but is among the supported file
+  types (per `denote-file-type'), add front matter to the top of it and
+  leave the buffer unsaved for further inspection ([Front matter]). Save
+  the buffer if `denote-save-buffers' is non-nil ([The
+  `denote-save-buffers' option]).
+
+  Construct the file name in accordance with the user option
+  `denote-file-name-components-order' ([Change the order of file name
+  components]).
+
+  Run the `denote-after-rename-file-hook' after renaming `FILE' ([Access
+  the data of the latest note]).
+
+  This command is intended to (i) rename Denote files, (ii) convert
+  existing supported file types to Denote notes, and (ii) rename
+  non-note files (e.g. `PDF') that can benefit from Denote’s file-naming
+  scheme.
+
+  For a version of this command that works with multiple files
+  one-by-one, use `denote-dired-rename-files' ([Rename multiple files
+  interactively]).
+
+
+[Rename multiple files interactively] See section 6.3
+
+[The `denote-prompts' option] See section 5.1.1
+
+[The `denote-rename-confirmations' option] See section 6.1.1
+
+[Front matter] See section 8
+
+[The `denote-save-buffers' option] See section 5.1.5
+
+[Change the order of file name components] See section 7.1
+
+[Access the data of the latest note] See section 19.1
+
+6.1.1 The `denote-rename-confirmations' option
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  The user option `denote-rename-confirmations' controls what kind of
+  confirmation renaming commands ask for ([Renaming files]).  Its value
+  is a list of symbols.
+
+  The value is either nil, in which case no confirmation is ever
+  requested, or a list of symbols among the following:
+
+  • `modify-file-name' means that renaming commands will ask for
+    confirmation before modifying the file name.
+
+  • `rewrite-front-matter' means that renaming commands will ask for
+    confirmation before rewritting the front matter.
+
+  • `add-front-matter' means that renaming commands will ask for
+    confirmation before adding new front matter to the file.
+
+  The default behaviour of the `denote-rename-file' command (and others
+  like it) is to ask for an affirmative answer as a final step before
+  changing the file name and, where relevant, inserting or updating the
+  corresponding front matter.
+
+  Specialized commands that build on top of `denote-rename-file' (or
+  related) may internally bind this user option to a non-nil value in
+  order to perform their operation (e.g. `denote-dired-rename-files'
+  goes through each marked Dired file, prompting for the information to
+  use, but carries out the renaming without asking for confirmation
+  ([Rename multiple files interactively])).
+
+
+[Renaming files] See section 6
+
+[Rename multiple files interactively] See section 6.3
+
+
+6.2 Rename a single file based on its front matter
+──────────────────────────────────────────────────
+
+  In the previous section, we covered the more general mechanism of the
+  command `denote-rename-file' ([Rename a single file]).  There is also
+  a way to have the same outcome by making Denote read the data in the
+  current file’s front matter and use it to construct/update the file
+  name.  The command for this is
+  `denote-rename-file-using-front-matter'.  It is only relevant for
+  files that (i) are among the supported file types, per
+  `denote-file-type', and (ii) have the requisite front matter in place.
+
+  Suppose you have an `.org' file with this front matter ([Front
+  matter]):
+
+  ┌────
+  │ #+title:      My sample note file
+  │ #+date:       [2022-08-05 Fri 13:10]
+  │ #+filetags:   :testing:
+  │ #+identifier: 20220805T131044
+  └────
+
+  Its file name reflects this information:
+
+  ┌────
+  │ 20220805T131044--my-sample-note-file__testing.org
+  └────
+
+
+  You want to change its title and keywords manually, so you modify it
+  thus:
+
+  ┌────
+  │ #+title:      My modified sample note file
+  │ #+date:       [2022-08-05 Fri 13:10]
+  │ #+filetags:   :testing:denote:emacs:
+  │ #+identifier: 20220805T131044
+  └────
+
+  At this stage, the file name still shows the old title and keywords.
+  You now invoke `denote-rename-file-using-front-matter' and it updates
+  the file name to:
+
+  ┌────
+  │ 20220805T131044--my-modified-sample-note-file__testing_denote_emacs.org
+  └────
+
+
+  By default, the renaming is subject to a “yes or no” prompt that shows
+  the old and new names, just so the user is certain about the change.
+  Though this can be modified ([The `denote-rename-confirmations'
+  option]).
+
+  The identifier of the file, if any, is never modified even if it is
+  edited in the front matter: Denote considers the file name to be the
+  source of truth in this case, to avoid potential breakage with typos
+  and the like.
+
+  This command constructs the file name in accordance with the user
+  option `denote-file-name-components-order' ([Change the order of file
+  name components]).
+
+
+[Rename a single file] See section 6.1
+
+[Front matter] See section 8
+
+[The `denote-rename-confirmations' option] See section 6.1.1
+
+[Change the order of file name components] See section 7.1
+
+
+6.3 Rename multiple files interactively
+───────────────────────────────────────
+
+  The command `denote-dired-rename-files' (alias
+  `denote-dired-rename-marked-files') renames the files that are marked
+  in a Dired buffer. Its behaviour is similar to the
+  `denote-rename-file' in that it prompts for a title, keywords, and
+  signature ([Rename a single file]). It does so over each marked file,
+  renaming one after the other.
+
+  Unlike `denote-rename-file', the command `denote-dired-rename-files'
+  does not ask to confirm the changes made to the files: it performs
+  them outright (same as setting `denote-rename-confirmations' to a nil
+  value). This is done to make it easier to rename multiple files
+  without having to confirm each step. For an even more direct approach,
+  check the command `denote-dired-rename-marked-files-with-keywords'.
+
+  • [Rename by writing only keywords]
+  • [Rename multiple files based on their front matter]
+
+
+[Rename a single file] See section 6.1
+
+[Rename by writing only keywords] See section 6.4
+
+[Rename multiple files based on their front matter] See section 6.5
+
+
+6.4 Rename multiple files at once by asking only for keywords
+─────────────────────────────────────────────────────────────
+
+  The `denote-dired-rename-marked-files-with-keywords' command renames
+  marked files in Dired to conform with our file-naming scheme. It does
+  so by writing keywords to them. Specifically, it does the following:
+
+  • retains the file’s existing name and makes it the `TITLE' field, per
+    Denote’s file-naming scheme;
+
+  • sluggifies the `TITLE' and adjusts its letter casing, according to
+    our conventions;
+
+  • prepends an identifier to the `TITLE', if one is missing;
+
+  • preserves the file’s extension, if any;
+
+  • prompts once for `KEYWORDS' and applies the user’s input to the
+    corresponding field in the file name, rewriting any keywords that
+    may exist while removing keywords that do exist if `KEYWORDS' is
+    empty;
+
+  • adds or rewrites existing front matter to the underlying file, if it
+    is recognized as a Denote note (per the `denote-file-type' user
+    option), such that it includes the new keywords.
+
+  [ Note that the affected buffers are not saved, unless the user option
+    `denote-rename-no-confirm' is non-nil. Users can thus check them to
+    confirm that the new front matter does not cause any problems (e.g.
+    with the `diff-buffer-with-file' command). Multiple buffers can be
+    saved in one go with the command `save-some-buffers' (read its doc
+    string). ]
+
+  Construct the file name in accordance with the user option
+  `denote-file-name-components-order' ([Change the order of file name
+  components]).
+
+  Run the `denote-after-rename-file-hook' after the renaming is done.
+
+  For more specialized versions of this command that only add or remove
+  keywords, use `denote-dired-rename-marked-files-add-keywords' and
+  `denote-dired-rename-marked-files-remove-keywords', respectively.
+
+
+[Change the order of file name components] See section 7.1
+
+
+6.5 Rename multiple files based on their front matter
+─────────────────────────────────────────────────────
+
+  As already noted, Denote can rename a file based on the data in its
+  front matter ([Rename a single file based on its front matter]).  The
+  command `denote-dired-rename-marked-files-using-front-matter' extends
+  this principle to a batch operation which applies to all marked files
+  in Dired.
+
+  Marked files must count as notes for the purposes of Denote, which
+  means that they at least have an identifier in their file name and use
+  a supported file type, per `denote-file-type'. Files that do not meet
+  this criterion are ignored, because Denote cannot know if they have
+  front matter and what that may be. For such files, it is still
+  possible to rename them interactively ([Rename multiple files
+  interactively]).
+
+
+[Rename a single file based on its front matter] See section 6.2
+
+[Rename multiple files interactively] See section 6.3
+
+
+6.6 Rename a file by changing only its file type
+────────────────────────────────────────────────
+
+  The command `denote-change-file-type-and-front-matter' provides the
+  convenience of converting a note taken in one file type, say, `.txt'
+  into another like `.org'. It presents a choice among the
+  `denote-file-type' options.
+
+  The conversion does NOT modify the existing front matter.  Instead, it
+  prepends new front matter to the top of the file.  We do this as a
+  safety precaution since the user can, in principle, add arbitrary
+  extras to their front matter that we would not want to touch.
+
+  If in Dired, `denote-change-file-type-and-front-matter' operates on
+  the file at point, else the current file, else it prompts with
+  minibuffer completion for one.
+
+  The title of the file is retrieved from a line starting with a title
+  field in the file’s front matter, depending on the previous file type
+  (e.g.  `#+title' for Org).  The same process applies for keywords.
+
+  As a final step, the command asks for confirmation, showing the
+  difference between old and new file names.
+
+  This command constructs the file name in accordance with the user
+  option `denote-file-name-components-order' ([Change the order of file
+  name components]).
+
+
+[Change the order of file name components] See section 7.1
+
+
+6.7 Rename a file by adding or removing a title interactively
+─────────────────────────────────────────────────────────────
+
+  The command `denote-rename-file-title' streamlines the process of
+  interactively adding or removing a title to/from a file, while
+  changing its file name accordingly. It asks for a title using the
+  familiar minibuffer prompt ([Standard note creation]). It then renames
+  the file. The command respect the values of
+  `denote-rename-confirmations' and `denote-save-buffers':
+
+  • [The `denote-rename-confirmations' option].
+  • [The `denote-save-buffers' option].
+
+  Technically, `denote-rename-file-title' is a wrapper for
+  `denote-rename-file', doing all the things that does ([Rename a single
+  file]).
+
+  Concretely, this command can add or remove a title in one go. It does
+  it by prepopulating the minibuffer prompt with the existing
+  title. Users can then modify it. An empty input means to remove the
+  title altogether ([The file-naming scheme]).
+
+  [ NOTE: Please check with your minibuffer user interface how to
+    provide an empty input. The Emacs default setup accepts the empty
+    minibuffer contents as they are, though popular packages like
+    `vertico' use the first available completion candidate instead. For
+    `vertico', the user must either move one up to select the prompt and
+    then type `RET' there with empty contents, or use the command
+    `vertico-exit-input' with empty contents. That Vertico command is
+    bound to `M-RET' as of this writing on 2024-06-30 10:37 +0300. ]
+
+
+[Standard note creation] See section 5.1
+
+[The `denote-rename-confirmations' option] See section 6.1.1
+
+[The `denote-save-buffers' option] See section 5.1.5
+
+[Rename a single file] See section 6.1
+
+[The file-naming scheme] See section 7
+
+
+6.8 Rename a file by adding or removing keywords interactively
+──────────────────────────────────────────────────────────────
+
+  The command `denote-rename-file-keywords' streamlines the process of
+  interactively adding or removing keywords to a file, while changing
+  its file name and front matter accordingly. It asks for keywords using
+  the familiar minibuffer prompt ([Standard note creation]). It then
+  renames the file ([Rename a single file based on its front matter]).
+  The command respect the values of `denote-rename-confirmations' and
+  `denote-save-buffers':
+
+  • [The `denote-rename-confirmations' option].
+  • [The `denote-save-buffers' option].
+
+  Technically, `denote-rename-file-keywords' is a wrapper for
+  `denote-rename-file', doing all the things that does ([Rename a single
+  file]).
+
+  Concretely, this command can add or remove keywords in one go. It does
+  it by prepopulating the minibuffer prompt with the existing keywords.
+  Users can then use the `crm-separator' (normally a comma), to write
+  new keywords or edit what is in the prompt to rewrite them
+  accordingly. An empty input means to remove all keywords ([The
+  file-naming scheme]).
+
+  [ NOTE: Please check with your minibuffer user interface how to
+    provide an empty input. The Emacs default setup accepts the empty
+    minibuffer contents as they are, though popular packages like
+    `vertico' use the first available completion candidate instead. For
+    `vertico', the user must either move one up to select the prompt and
+    then type `RET' there with empty contents, or use the command
+    `vertico-exit-input' with empty contents. That Vertico command is
+    bound to `M-RET' as of this writing on 2024-06-30 10:37 +0300. ]
+
+
+[Standard note creation] See section 5.1
+
+[Rename a single file based on its front matter] See section 6.2
+
+[The `denote-rename-confirmations' option] See section 6.1.1
+
+[The `denote-save-buffers' option] See section 5.1.5
+
+[Rename a single file] See section 6.1
+
+[The file-naming scheme] See section 7
+
+
+6.9 Rename a file by adding or removing a signature interactively
+─────────────────────────────────────────────────────────────────
+
+  The command `denote-rename-file-signature' streamlines the process of
+  interactively adding or removing a signature to/from a file, while
+  changing its file name accordingly. It asks for a signature using the
+  familiar minibuffer prompt ([Standard note creation]). It then renames
+  the file. The command respect the values of
+  `denote-rename-confirmations' and `denote-save-buffers':
+
+  • [The `denote-rename-confirmations' option].
+  • [The `denote-save-buffers' option].
+
+  Technically, `denote-rename-file-signature' is a wrapper for
+  `denote-rename-file', doing all the things that does ([Rename a single
+  file]).
+
+  Concretely, this command can add or remove a signature in one go. It
+  does it by prepopulating the minibuffer prompt with the existing
+  signature. Users can then modify it. An empty input means to remove
+  the signature altogether ([The file-naming scheme]).
+
+  [ NOTE: Please check with your minibuffer user interface how to
+    provide an empty input. The Emacs default setup accepts the empty
+    minibuffer contents as they are, though popular packages like
+    `vertico' use the first available completion candidate instead. For
+    `vertico', the user must either move one up to select the prompt and
+    then type `RET' there with empty contents, or use the command
+    `vertico-exit-input' with empty contents. That Vertico command is
+    bound to `M-RET' as of this writing on 2024-06-30 10:37 +0300. ]
+
+
+[Standard note creation] See section 5.1
+
+[The `denote-rename-confirmations' option] See section 6.1.1
+
+[The `denote-save-buffers' option] See section 5.1.5
+
+[Rename a single file] See section 6.1
+
+[The file-naming scheme] See section 7
+
+
+6.10 Find duplicate identifiers and put them in a Dired buffer
+──────────────────────────────────────────────────────────────
+
+  Denote takes care to create unique identifiers, though its mechanism
+  relies on reading the existing identifiers in the `denote-directory'
+  or the current directory. When we are renaming files across different
+  directories, there is a small chance that some files have the same
+  attributes and are thus assigned identical identifiers. If those files
+  ever make it into a consolidated `denote-directory', we will have
+  duplicates, which break the linking mechanism.
+
+  As this is an edge case, we do not include any code to address it in
+  the Denote code base. Though here is a way to find duplicate
+  identifiers inside the current directory:
+
+  ┌────
+  │ (defun my-denote--get-files-in-dir (directory)
+  │   "Return file names in DIRECTORY."
+  │   (directory-files directory :full-paths directory-files-no-dot-files-regexp))
+  │ 
+  │ (defun my-denote--same-identifier-p (file1 file2)
+  │   "Return non-nil if FILE1 and FILE2 have the same identifier."
+  │   (let ((id1 (denote-retrieve-filename-identifier file1))
+  │ 	(id2 (denote-retrieve-filename-identifier file2)))
+  │     (equal id1 id2)))
+  │ 
+  │ (defun my-denote-find-duplicate-identifiers (directory)
+  │   "Find all files in DIRECTORY that need a new identifier."
+  │   (let* ((ids (my-denote--get-files-in-dir directory))
+  │ 	 (unique-ids (seq-uniq ids #'my-denote--same-identifier-p)))
+  │     (seq-difference ids unique-ids #'equal)))
+  │ 
+  │ (defun my-denote-dired-show-duplicate-identifiers (directory)
+  │   "Put duplicate identifiers from DIRECTORY in a dedicated Dired buffer."
+  │   (interactive
+  │    (list
+  │     (read-directory-name "Select DIRECTORY to check for duplicate identifiers: " default-directory)))
+  │   (if-let* ((duplicates (my-denote-find-duplicate-identifiers directory)))
+  │       (dired (cons (format "Denote duplicate identifiers" directory) duplicates))
+  │     (message "No duplicates identifiers in `%s'" directory)))
+  └────
+
+  Evaluate this code and then call the command
+  `my-denote-dired-show-duplicate-identifiers'.  If there are
+  duplicates, it will put them in a dedicated Dired buffer.  From there,
+  you can view the file contents as usual, and manually edit the
+  identifiers as you see fit (e.g. edit them one by one, or change to
+  the writable Dired and record a keyboard macro that makes use of a
+  counter to increment by 1—contact me if you need any help).
+
+
+6.11 Faces used by rename commands
+──────────────────────────────────
+
+  These are the faces used by the various Denote rename commands to
+  style or highlight the old/new/current file shown in the relevant
+  minibuffer prompts:
+
+  • `denote-faces-prompt-current-name'
+  • `denote-faces-prompt-new-name'
+  • `denote-faces-prompt-old-name'
+
+
+7 The file-naming scheme
+════════════════════════
+
+  Notes are stored in the `denote-directory'.  The default path is
+  `~/Documents/notes'.  The `denote-directory' can be a flat listing,
+  meaning that it has no subdirectories, or it can be a directory tree.
+  Either way, Denote takes care to only consider “notes” as valid
+  candidates in the relevant operations and will omit other files or
+  directories.
+
+  Every note produced by Denote follows this pattern by default ([Points
+  of entry]):
+
+  ┌────
+  │ DATE==SIGNATURE--TITLE__KEYWORDS.EXTENSION
+  └────
+
+
+  The `DATE' field represents the date in year-month-day format followed
+  by the capital letter `T' (for “time”) and the current time in
+  hour-minute-second notation.  The presentation is compact:
+  `20220531T091625'.  The `DATE' serves as the unique identifier of each
+  note and, as such, is also known as the file’s ID or identifier.
+
+  File names can include an arbitrary string of alphanumeric characters
+  in the `SIGNATURE' field. Signatures have no clearly defined purpose
+  and are up to the user to define. They can serve as special labels,
+  such as `part1' and `part2' of a large file, or as priority indicators
+  like `a', `b', `c', or even context/scope specifiers like `home' and
+  `work'. Another use-case is to write sequences of thoughts, such that
+  notes form a hierarchy, something we support with the optional and
+  comprehensive extension `denote-sequence.el' ([Write sequence notes or
+  “folgezettel”]).  Signatures are an optional extension to Denote’s
+  file-naming scheme.  In the simplest form, they can be added to newly
+  created files on demand, with the command `denote-signature', or by
+  modifying the value of the user option `denote-prompts' ([The
+  `denote-prompts' option]).
+
+  The `TITLE' field is the title of the note, as provided by the user.
+  It automatically gets downcased by default and is also hyphenated
+  ([Sluggification of file name components]).  An entry about “Economics
+  in the Euro Area” produces an `economics-in-the-euro-area' string for
+  the `TITLE' of the file name.
+
+  The `KEYWORDS' field consists of one or more entries demarcated by an
+  underscore (the separator is inserted automatically).  Each keyword is
+  a string provided by the user at the relevant prompt which broadly
+  describes the contents of the entry.
+
+  Each of the keywords is a single word, with multiple keywords
+  providing the multi-dimensionality needed for advanced searches
+  through Denote files.  Users who need to compose a keyword out of
+  multiple words such as camelCase/CamelCase and are encouraged to use
+  the `denote-file-name-slug-functions' user option accordingly
+  ([Sluggification of file name components]).
+
+  The `EXTENSION' is the file type.  By default, it is `.org'
+  (`org-mode') though the user option `denote-file-type' provides
+  support for Markdown with YAML or TOML variants (`.md' which runs
+  `markdown-mode') and plain text (`.txt' via `text-mode').  Consult its
+  doc string for the minutiae.  While files end in the `.org' extension
+  by default, the Denote code base does not actually depend on org.el
+  and/or its accoutrements.
+
+  Examples:
+
+  ┌────
+  │ 20220610T043241--initial-thoughts-on-the-zettelkasten-method__notetaking.org
+  │ 20220610T062201--define-custom-org-hyperlink-type__denote_emacs_package.md
+  │ 20220610T162327--on-hierarchy-and-taxis__notetaking_philosophy.txt
+  └────
+
+
+  The different field separators, namely `--' and `__' introduce an
+  efficient way to anchor searches (such as with Emacs commands like
+  `isearch' or from the command-line with `find' and related).  A query
+  for `_word' always matches a keyword, while a regexp in the form of,
+  say, `"\\([0-9T]+?\\)--\\(.*?\\)_"' captures the date in group `\1'
+  and the title in `\2' (test any regular expression in the current
+  buffer by invoking `M-x re-builder').
+
+  [Features of the file-naming scheme for searching or filtering].
+
+  The `denote-prompts' can be configured in such ways to yield the
+  following file name permutations:
+
+  ┌────
+  │ DATE.EXT
+  │ DATE--TITLE.EXT
+  │ DATE__KEYWORDS.EXT
+  │ DATE==SIGNATURE.EXT
+  │ DATE==SIGNATURE--TITLE.EXT
+  │ DATE==SIGNATURE--TITLE__KEYWORDS.EXT
+  │ DATE==SIGNATURE__KEYWORDS.EXT
+  └────
+
+
+  When in doubt, stick to the default design, which is carefully
+  considered and works well ([Change the order of file name
+  components]).
+
+  While Denote is an Emacs package, notes should work long-term and not
+  depend on the functionality of a specific program.  The file-naming
+  scheme we apply guarantees that a listing is readable in a variety of
+  contexts.  The Denote file-naming scheme is, in essence, an effective,
+  low-tech invention.
+
+
+[Points of entry] See section 5
+
+[Write sequence notes or “folgezettel”] See section 18.2
+
+[The `denote-prompts' option] See section 5.1.1
+
+[Sluggification of file name components] See section 7.2
+
+[Features of the file-naming scheme for searching or filtering] See
+section 7.4
+
+[Change the order of file name components] See section 7.1
+
+7.1 Change the order of file name components
+────────────────────────────────────────────
+
+  Our standard file-naming scheme prescribes a specific order for the
+  file name components ([The file-naming scheme]). Though we provide the
+  user option `denote-file-name-components-order' to let the user
+  reorder them as they see fit.
+
+  The value of this user option is a list of the following symbols:
+
+  • `identifier': This is the combination of the date and time. When it
+    is the first on the list, it looks like `20240519T073456' and does
+    not have a component separator of its own due its unambiguous
+    format. When it is placed anywhere else in the file name, it is
+    prefixed with `@@', so it looks like `@@20240519T073456'.
+
+  • `signature': This is an arbitrary string that can be used to qualify
+    the file in some way, according to the user’s methodology (e.g. to
+    add a sequence to notes). The string is always prefixed with the
+    `==' to remain unambiguous.
+
+  • `title': This is an arbitrary string which describes the file. It is
+    always prefixed with `--' to be unambiguous.
+
+  • `keywords': This is a series of one or more words that succinctly
+    group the file. Multiple keywords are separated by an underscore
+    prefixed to each of them. The file name component is always prefixed
+    with `__'.
+
+  All four symbols must appear exactly once. Duplicates are ignored. Any
+  missing symbol is added automatically.
+
+  Some examples:
+
+  ┌────
+  │ (setq denote-file-name-components-order '(identifier signature title keywords))
+  │ ;; => 20240519T07345==hello--this-is-the-title__denote_testing.org
+  │ 
+  │ (setq denote-file-name-components-order '(signature identifier title keywords))
+  │ ;; => ==hello@@20240519T07345--this-is-the-title__denote_testing.org
+  │ 
+  │ (setq denote-file-name-components-order '(title signature identifier keywords))
+  │ ;; => --this-is-the-title==hello@@20240519T07345__denote_testing.org
+  │ 
+  │ (setq denote-file-name-components-order '(keywords title signature identifier))
+  │ ;; => __denote_testing--this-is-the-title==hello@@20240519T07345.org
+  └────
+
+  Also see how to configure the Denote prompts, which affect which
+  components are actually used in the order specified herein ([The
+  `denote-prompts' option]).
+
+  Before deciding on this, please consider the longer-term implications
+  of file names with varying patterns. Consistency makes things
+  predictable and thus easier to find. So pick one order and never touch
+  it again. When in doubt, leave the default file-naming scheme as-is.
+
+
+[The file-naming scheme] See section 7
+
+[The `denote-prompts' option] See section 5.1.1
+
+
+7.2 Sluggification of file name components
+──────────────────────────────────────────
+
+  Files names can contain any character that the file system
+  permits. Denote imposes a few additional restrictions:
+
+  ⁃ The tokens “`=", =__' and `--' are interpreted by Denote and should
+    appear only once.
+
+  ⁃ The dot character is not allowed in a note’s file name, except to
+    indicate the file type extension. Denote recognises two extensions
+    for encrypted files, like `.txt.gpg'.
+
+  By default, Denote enforces other rules to file names through the user
+  option `denote-file-name-slug-functions'. These rules are applied to
+  file names by default:
+
+  ⁃ What we count as “illegal characters” are removed.
+
+  ⁃ Input for a file title is hyphenated.  The original value is
+    preserved in the note’s contents ([Front matter]).
+
+  ⁃ Spaces or other delimiters are removed from keywords, meaning that
+    `hello-world' becomes `helloworld'.  This is because hyphens in
+    keywords do not work everywhere, such as in Org. Plus, hyphens are
+    word separators in the title and we want to keep distinct separators
+    for each component to make search easier and semantic ([Features of
+    the file-naming scheme for searching or filtering]).
+
+  ⁃ Signatures are like the above, but use the equals sign instead of
+    hyphens as a word separator.
+
+  ⁃ All file name components are downcased. Further down we document how
+    to deviate from these rules, such as to accept input of the form
+    `helloWorld' or `HelloWorld' verbatim.
+
+  Denote imposes these restrictions to enforce uniformity, which is
+  helpful long-term as it keeps all files with the same predictable
+  pattern. Too many permutations make searches more difficult to express
+  accurately and be confident that the matches cover all files.
+  Nevertheless, one of the principles of Denote is its flexibility or
+  hackability and so users can deviate from the aforementioned
+  ([User-defined sluggification of file name components]).
+
+
+[Front matter] See section 8
+
+[Features of the file-naming scheme for searching or filtering] See
+section 7.4
+
+[User-defined sluggification of file name components] See section 7.3
+
+
+7.3 User-defined sluggification of file name components
+───────────────────────────────────────────────────────
+
+  The user option `denote-file-name-slug-functions' controls the
+  sluggification of file name components ([Sluggification of file name
+  components]).  The default method is outlined above and in the
+  previous section ([The file-naming scheme]).
+
+  The value of this user option is an alist where each element is a cons
+  cell of the form `(COMPONENT . METHOD)'. For example, here is the
+  default value:
+
+  ┌────
+  │ '((title . denote-sluggify-title)
+  │   (signature . denote-sluggify-signature)
+  │   (keyword . denote-sluggify-keyword))
+  └────
+
+  • The `COMPONENT' is an unquoted symbol among `title', `signature',
+    `keyword', which refers to the corresponding component of the file
+    name.
+
+  • The `METHOD' is a function to format the given component. This
+    function must take a string as its parameter and return the string
+    formatted for the file name. Note that even in the case of the
+    `keyword' component, the function receives one string representing a
+    single keyword and returns it formatted for the file name. Joining
+    the keywords together is handled internally by Denote.
+
+  One commonly requested deviation from the sluggification rules is to
+  not sluggify individual keywords, such that the user’s input is taken
+  as-is. This can be done as follows:
+
+  ┌────
+  │ (setq denote-file-name-slug-functions
+  │       '((title . denote-sluggify-title)
+  │ 	(keyword . identity)
+  │ 	(signature . denote-sluggify-signature)))
+  └────
+
+  The `identity' function simply returns the string it receives, thus
+  not altering it in any way.
+
+  Another approach is to keep the sluggification but not downcase the
+  string. We can do this by modifying the original functions used by
+  Denote. For example, we have this:
+
+  ┌────
+  │ ;; The original function for reference
+  │ (defun denote-sluggify-title (str)
+  │   "Make STR an appropriate slug for title."
+  │   (downcase
+  │    (denote-slug-hyphenate
+  │     (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" "" str))))
+  │ 
+  │ ;; Our variant of the above, which does the same thing except from
+  │ ;; downcasing the string.
+  │ (defun my-denote-sluggify-title (str)
+  │   "Make STR an appropriate slug for title."
+  │   (denote-slug-hyphenate
+  │    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" "" str)))
+  │ 
+  │ ;; Now we use our function to sluggify titles without affecting their
+  │ ;; letter casing.
+  │ (setq denote-file-name-slug-functions
+  │       '((title . my-denote-sluggify-title) ; our function here
+  │ 	(signature . denote-sluggify-signature)
+  │ 	(keyword . denote-sluggify-keyword)))
+  └────
+
+  Follow this principle for all the sluggification functions ([Custom
+  sluggification to remove non-ASCII characters]).
+
+  To access the source code, use either of the following built-in
+  methods:
+
+  1. Call the command `find-library' and search for `denote'. Then
+     navigate to the symbol you are searching for.
+
+  2. Invoke the command `describe-symbol', search for the symbol you are
+     interested in, and from the resulting Help buffer either click on
+     the first link or do `M-x help-view-source' (bound to `s' in Help
+     buffers, by default).
+
+  Remember that deviating from the default file-naming scheme of Denote
+  will make things harder to use in the future, as files can/will have
+  permutations that create uncertainty. The sluggification scheme and
+  concomitant restrictions we impose by default are there for a very
+  good reason: they are the distillation of years of experience. Here we
+  give you what you wish, but bear in mind it may not be what you need.
+  You have been warned.
+
+
+[Sluggification of file name components] See section 7.2
+
+[The file-naming scheme] See section 7
+
+[Custom sluggification to remove non-ASCII characters] See section 7.3.1
+
+7.3.1 Custom sluggification to remove non-ASCII 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
+  problems with pattern matching, such as when searching through file
+  names.
+
+  By default, Denote does not remove Unicode characters because users
+  may actually want them (e.g. Latin characters with accents). Those who
+  do, however, wish to keep everything limited to the ASCII range can
+  use the following in their Emacs configuration ([User-defined
+  sluggification of file name components]).
+
+  ┌────
+  │ ;; These are the same as the default Denote sluggification functions,
+  │ ;; except they remove all non-ASCII characters.
+  │ (defun my-denote-sluggify-title (str)
+  │   (downcase
+  │    (denote-slug-hyphenate
+  │     (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" ""
+  │ 			      (denote-slug-keep-only-ascii str)))))
+  │ 
+  │ (defun my-denote-sluggify-signature (str)
+  │   (downcase
+  │    (denote-slug-put-equals
+  │     (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/-]*" ""
+  │ 			      (denote-slug-keep-only-ascii str)))))
+  │ 
+  │ (defun my-denote-sluggify-keyword (str)
+  │   (downcase
+  │    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/_ =-]*" ""
+  │ 			     (denote-slug-keep-only-ascii str))))
+  │ 
+  │ (defcustom denote-file-name-slug-functions
+  │   '((title . my-denote-sluggify-title)
+  │     (signature . my-denote-sluggify-signature)
+  │     (keyword . my-denote-sluggify-keyword)))
+  └────
+
+
+[User-defined sluggification of file name components] See section 7.3
+
+
+7.4 Features of the file-naming scheme for searching or filtering
+─────────────────────────────────────────────────────────────────
+
+  By default, file names have three fields and two sets of field
+  delimiters between them:
+
+  ┌────
+  │ DATE--TITLE__KEYWORDS.EXTENSION
+  └────
+
+
+  When a signature is present, this becomes:
+
+  ┌────
+  │ DATE==SIGNATURE--TITLE__KEYWORDS.EXTENSION
+  └────
+
+
+  Field delimiters practically serve as anchors for easier searching.
+  Consider this example:
+
+  ┌────
+  │ 20220621T062327==1a2--introduction-to-denote__denote_emacs.txt
+  └────
+
+
+  You will notice that there are two matches for the word `denote': one
+  in the title field and another in the keywords’ field.  Because of the
+  distinct field delimiters, if we search for `-denote' we only match
+  the first instance while `_denote' targets the second one.  When
+  sorting through your notes, this kind of specificity is invaluable—and
+  you get it for free from the file names alone!  Similarly, a search
+  for `=1' will show all notes that are related to each other by virtue
+  of their signature.
+
+  Users can get a lot of value out of this simple yet effective
+  arrangement, even if they have no knowledge of regular expressions.
+  One thing to consider, for maximum effect, is to avoid using
+  multi-word keywords as those can get hyphenated like the title and
+  will thus interfere with the above: either set the user option
+  `denote-allow-multi-word-keywords' to nil or simply insert single
+  words at the relevant prompts.
+
+
+8 Front matter
+══════════════
+
+  Notes have their own “front matter”.  This is a block of data at the
+  top of the file, with no empty lines between the entries, which is
+  automatically generated at the creation of a new note.  The front
+  matter includes the title and keywords (aka “tags” or “filetags”,
+  depending on the file type) which the user specified at the relevant
+  prompt, as well as the date and unique identifier, which are derived
+  automatically.
+
+  This is how it looks for Org mode (when `denote-file-type' is nil or
+  the `org' symbol):
+
+  ┌────
+  │ #+title:      This is a sample note
+  │ #+date:       [2022-06-30 Thu 16:09]
+  │ #+filetags:   :denote:testing:
+  │ #+identifier: 20220630T160934
+  └────
+
+  For Markdown with YAML (`denote-file-type' has the `markdown-yaml'
+  value), the front matter looks like this:
+
+  ┌────
+  │ ---
+  │ title:      "This is a sample note"
+  │ date:       2022-06-30T16:09:58+03:00
+  │ tags:       ["denote", "testing"]
+  │ identifier: "20220630T160958"
+  │ ---
+  └────
+
+  For Markdown with TOML (`denote-file-type' has the `markdown-toml'
+  value), it is:
+
+  ┌────
+  │ +++
+  │ title      = "This is a sample note"
+  │ date       = 2022-06-30T16:10:13+03:00
+  │ tags       = ["denote", "testing"]
+  │ identifier = "20220630T161013"
+  │ +++
+  └────
+
+  And for plain text (`denote-file-type' has the `text' value), we have
+  the following:
+
+  ┌────
+  │ title:      This is a sample note
+  │ date:       2022-06-30
+  │ tags:       denote  testing
+  │ identifier: 20220630T161028
+  │ ---------------------------
+  └────
+
+  The format of the date in the front matter is controlled by the user
+  option `denote-date-format'.  When nil, Denote uses a
+  file-type-specific format:
+
+  • For Org, an inactive timestamp is used, such as `[2022-06-30 Wed
+    15:31]'.
+
+  • For Markdown, the RFC3339 standard is applied:
+    `2022-06-30T15:48:00+03:00'.
+
+  • For plain text, the format is that of ISO 8601: `2022-06-30'.
+
+  If the value is a string, ignore the above and use it instead.  The
+  string must include format specifiers for the date.  These are
+  described in the doc string of `format-time-string'..
+
+
+8.1 Change the front matter format
+──────────────────────────────────
+
+  Per Denote’s design principles, the code is hackable.  All front
+  matter is stored in variables that are intended for public use.  We do
+  not declare those as “user options” because (i) they expect the user
+  to have some degree of knowledge in Emacs Lisp and (ii) implement
+  custom code.
+
+  [ NOTE for tinkerers: code intended for internal use includes double
+    hyphens in its symbol.  “Internal use” means that it can be changed
+    without warning and with no further reference in the change log.  Do
+    not use any of it without understanding the consequences. ]
+
+  The variables which hold the front matter format are:
+
+  • `denote-org-front-matter'
+
+  • `denote-text-front-matter'
+
+  • `denote-toml-front-matter'
+
+  • `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 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.
+
+  When editing the value, make sure to:
+
+  1. Not use empty lines inside the front matter block.
+
+  2. Insert at least one empty line after the front matter block and do
+     not use any empty line before it.
+
+  These help with consistency and might prove useful if we ever need to
+  operate on the front matter as a whole.
+
+  With those granted, below are some examples.  The approach is the same
+  for all variables.
+
+  ┌────
+  │ ;; Like the default, but upcase the entries
+  │ (setq denote-org-front-matter
+  │   "#+TITLE:      %s
+  │ #+DATE:       %s
+  │ #+FILETAGS:   %s
+  │ #+IDENTIFIER: %s
+  │ \n")
+  │ 
+  │ ;; Change the order (notice the %N$s notation)
+  │ (setq denote-org-front-matter
+  │   "#+title:      %1$s
+  │ #+filetags:   %3$s
+  │ #+date:       %2$s
+  │ #+identifier: %4$s
+  │ \n")
+  │ 
+  │ ;; Remove the date
+  │ (setq denote-org-front-matter
+  │   "#+title:      %1$s
+  │ #+filetags:   %3$s
+  │ #+identifier: %4$s
+  │ \n")
+  │ 
+  │ ;; Remove the date and the identifier
+  │ (setq denote-org-front-matter
+  │   "#+title:      %1$s
+  │ #+filetags:   %3$s
+  │ \n")
+  └────
+
+  Note that `setq' has a global effect: it affects the creation of all
+  new notes.  Depending on the workflow, it may be preferrable to have a
+  custom command which `let' binds the different format.  We shall not
+  provide examples at this point as this is a more advanced feature and
+  we are not yet sure what the user’s needs are.  Please provide
+  feedback and we shall act accordingly.
+
+
+8.2 Regenerate front matter
+───────────────────────────
+
+  As part of version 4.0.0, the command `denote-add-front-matter' is
+  superseded by `denote-rename-file' and related ([Renaming
+  files]). Those commands will add missing front matter or rewrite the
+  modified lines of existing front matter.
+
+
+[Renaming files] See section 6
+
+
+9 Linking notes
+═══════════════
+
+  Denote offers several commands for linking between notes. Those use
+  the `denote:' hyperlink type. There are two types of links supported
+  by Denote:
+
+  Direct links
+        A direct link points to a file inside the
+        `denote-directory'. The link is constructed by using the
+        `denote:' prefix and the target file’s identifier ([The
+        file-naming scheme]).  This looks like
+        `denote:20250328T075526'. The syntax of a link depends on the
+        file type. For example, in Org and plain text links look like
+        `[[denote:20250328T075526][The title of the target file]]',
+        while in Markdown they are written as `[The title of the target
+        file](denote:20250328T075526)'.
+
+  Query links
+        The `denote:' hyperlink type also supports special qualifiers
+        that change how the target of the link is interpreted.  The
+        qualifier is a special token than tells Denote how to treat the
+        target of the link. It is written thus
+        `denote:TOKEN:QUERY'. There are two kinds of tokens:
+        `query-contents' and `query-filenames'.  Those determine how the
+        query terms are used. As their names suggest, these two tokens
+        trigger a search in (i) the file contents of all readable files
+        or (ii) in the file names only. They are, in other words,
+        counterparts of the Unix `grep' and `find' programs,
+        respectively.
+
+  The following sections cover all the details ([Why are some Org links
+  opening outside Emacs?]).
+
+
+[The file-naming scheme] See section 7
+
+[Why are some Org links opening outside Emacs?] See section 25.9
+
+9.1 Add a single direct link using a file name prompt
+─────────────────────────────────────────────────────
+
+  The `denote-link' command (alias `denote-insert-link') inserts a link
+  at point to a file selected at the minibuffer prompt. Links are
+  formatted depending on the file type of the current note. In Org and
+  plain text buffers, links are formatted thus:
+  `[[denote:IDENTIFIER][DESCRIPTION]]'.  While in Markdown they are
+  expressed as `[DESCRIPTION](denote:IDENTIFIER)'.
+
+  When `denote-link' is called with a prefix argument (`C-u' by
+  default), it formats links like `[[denote:IDENTIFIER]]', regardless of
+  file type ([Fontify links in non-Org buffers]). The user might prefer
+  its simplicity.
+
+  By default, the description of the link is determined thus:
+
+  • If the region is active, its text becomes the description of the
+    link. In other words, the region text becomes the link.
+  • If the region is active but has no text, the description is empty
+    and so the link is formatted the same way as if using the `C-u'
+    prefix argument.
+  • If there is no region active, the description consists of the target
+    file’s signature and title, using the former only if it is present.
+    The title is retrieved either from the front matter or the file
+    name.
+  • If the target file has no signature, the title is used.
+
+  To insert multiple such links at once, use the command
+  `denote-add-links' ([Insert links matching a regexp in their file
+  name]).
+
+  If you want to directly link to a single file whose contents match a
+  given query, then use the command `denote-link-to-file-with-contents'
+  ([Adding a direct link to a file whose contents include the given
+  query]).
+
+  Links are styled with the `denote-faces-link' face, which looks
+  exactly like an ordinary link by default.
+
+  [ We optionally support direct links to a file followed by an extra
+    target to an Org headings ([The `denote-org-store-link-to-heading'
+    user option]).  Other file types do not have the features of Org, so
+    we cannot generalise this. ]
+
+
+[Fontify links in non-Org buffers] See section 9.14
+
+[Insert links matching a regexp in their file name] See section 9.4
+
+[Adding a direct link to a file whose contents include the given query]
+See section 9.2
+
+[The `denote-org-store-link-to-heading' user option] See section 9.7
+
+
+9.2 Add a direct link to a file whose contents include the given query
+──────────────────────────────────────────────────────────────────────
+
+  The `denote-link' command that we covered before prompts to select a
+  file among those in the `denote-directory' ([Adding a single direct
+  link using a file name prompt]).  The match is done against the file’s
+  name. Users may, however, be interested to create a link to a file
+  whose contents include some text, regardless of how the file name is
+  called. To this end, the command `denote-link-to-file-with-contents',
+  (i) prompts for a query which is a plain string or regular expression,
+  (ii) if there are matching files, asks to select one among them, and
+  (iii) inserts the direct link at point.
+
+  When called with an optional prefix argument (`C-u' by default), the
+  command `denote-link-to-file-with-contents' creates a link that does
+  not include a description for the target file: it just has the file’s
+  identifier (same as with `denote-link').
+
+  The command `denote-link-to-file-with-contents' is the counterpart of
+  `denote-link-to-all-files-with-contents' ([Insert links to all files
+  matching a query in their contents]).
+
+
+[Adding a single direct link using a file name prompt] See section 9.1
+
+[Insert links to all files matching a query in their contents] See
+section 9.5
+
+
+9.3 Add a query link
+────────────────────
+
+  As noted in the introduction to this section of the manual, the
+  `denote:' hyperlink type supports query links ([Linking
+  notes]). Unlike direct links, they do not point to any given
+  file. Instead, they trigger a search, whose results are displayed in a
+  separate buffer.
+
+  Query links are expressed as `denote:TOKEN:QUERY', where `TOKEN' is
+  either `query-contents' or `query-filenames', while `QUERY' is a
+  string or Emacs regular expression to search for.
+
+  The exact syntax of a query link depends on the file type. In Org and
+  plain text buffers, links are of the form
+  `[[denote:TOKEN:QUERY][QUERY]]'.  In Markdown, they are formatted as
+  `[QUERY](denote:TOKEN:QUERY)'. In all cases, the description of the
+  link is the query text itself.
+
+  The command `denote-query-contents-link' inserts a link at point that
+  triggers a search in the file contents of all readable documents in
+  the `denote-directory' ([Interact with the links buffer]). This is the
+  equivalent of the Unix `grep' command and uses the built-in Emacs Xref
+  interface ([Speed up backlinks’ or query links’ buffer creation?]).
+  Matches are displayed in a separate buffer, highlighting the exact
+  text while showing its context.
+
+  The command `denote-query-filenames-link' creates a link at point that
+  initiates a search across file names in the `denote-directory'. This
+  is the equivalent of the Unix `find' command. Results are placed in a
+  Dired buffer ([Display filtered and sorted files with
+  `denote-sort-dired']).
+
+  The user option `denote-query-links-display-buffer-action' controls
+  the placement of query link buffers. By default, they are designed to
+  appear below the current window.
+
+  Query links are styled with the `denote-faces-query-link' face, which
+  looks a bit different that `denote-faces-link' (though this depends on
+  the active theme).
+
+
+[Linking notes] See section 9
+
+[Interact with the links buffer] See section 16
+
+[Speed up backlinks’ or query links’ buffer creation?] See section 25.10
+
+[Display filtered and sorted files with `denote-sort-dired'] See section
+14
+
+
+9.4 Insert links to all files matching a query in their file name
+─────────────────────────────────────────────────────────────────
+
+  The command `denote-add-links' adds links at point to all file names
+  in the `denote-directory' that match a regular expression or plain
+  string. This is similar to the `denote-link' command, which
+  establishes a direct link to a specified file ([Adding a single direct
+  link]).  Links to files whose names match the given search terms are
+  inserted as a typographic list, such as:
+
+  ┌────
+  │ - link1
+  │ - link2
+  │ - link3
+  └────
+
+  Each link is formatted according to the file type of the current note,
+  as explained further above about the `denote-link' command.  The
+  current note is excluded from the matching entries (adding a link to
+  itself is pointless).
+
+  When called with a prefix argument (`C-u') `denote-add-links' will
+  format all links as `[[denote:IDENTIFIER]]', hence a typographic list:
+
+  ┌────
+  │ - [[denote:IDENTIFIER-1]]
+  │ - [[denote:IDENTIFIER-2]]
+  │ - [[denote:IDENTIFIER-3]]
+  └────
+
+  Same examples of a regular expression that can be used with this
+  command:
+
+  • `journal' match all files which include `journal' anywhere in their
+    name.
+
+  • `_journal' match all files which include `journal' as a keyword.
+
+  • `^2022.*_journal' match all file names starting with `2022' and
+    including the keyword `journal'.
+
+  • `\.txt' match all files including `.txt'.  In practical terms, this
+    only applies to the file extension, as Denote automatically removes
+    dots (and other characters) from the base file name.
+
+  If files are created with `denote-sort-keywords' as non-nil (the
+  default), then it is easy to write a regexp that includes multiple
+  keywords in alphabetic order:
+
+  • `_denote.*_package' match all files that include both the `denote'
+    and `package' keywords, in this order.
+
+  • `\(.*denote.*package.*\)\|\(.*package.*denote.*\)' is the same as
+    above, but out-of-order.
+
+  Remember that regexp constructs only need to be escaped once (like
+  `\|') when done interactively but twice when called from Lisp.  What
+  we show above is for interactive usage.
+
+  Links are created only for files which qualify as a “note” for our
+  purposes ([Linking notes]).
+
+
+[Adding a single direct link] See section 9.1
+
+[Linking notes] See section 9
+
+
+9.5 Insert links to all files matching a query in their contents
+────────────────────────────────────────────────────────────────
+
+  The aforementioned `denote-add-links' command takes a query that
+  matches it against file names ([Insert links to all files matching a
+  query in their file name]).  It then creates a typographic list
+  (bullet list) with direct links to all the matching files. Users who
+  wish to achieve the same result but have the query be matched against
+  file contents (not file names), can use the command
+  `denote-link-to-all-files-with-contents'.
+
+  The command `denote-link-to-all-files-with-contents' is the
+  counterpart of `denote-link-to-file-with-contents' ([Add a direct link
+  to a file whose contents include the given query]).
+
+
+[Insert links to all files matching a query in their file name] See
+section 9.4
+
+[Add a direct link to a file whose contents include the given query] See
+section 9.2
+
+
+9.6 The `denote-open-link-function' user option
+───────────────────────────────────────────────
+
+  The user option `denote-open-link-function' specifies the function
+  used by Denote to open the file of a link. The default value opens the
+  file in the other window. Another common value is the function
+  `find-file', which will open the file in the current window. Users may
+  also specify a function of their choosing.
+
+  Note that this is relevant in buffers other than Org mode because Org
+  has its own mechanism for how to open links (read the documentation of
+  the command `org-open-at-point').
+
+
+9.7 The `denote-org-store-link-to-heading' user option
+──────────────────────────────────────────────────────
+
+  The user option `denote-org-store-link-to-heading' determines whether
+  `org-store-link' links to the current Org heading.
+
+  [ Remember that what `org-store-link' does is merely collect a link.
+    To actually insert it, use the command `org-insert-link'.  Note that
+    `org-capture' uses `org-store-link' internally when it needs to
+    store a link.  ]
+
+  When the value is nil, the Denote handler for `org-store-link'
+  produces links only to the current file (by using the file’s
+  identifier).  For example:
+
+  ┌────
+  │ [[denote:20240118T060608][Some test]]
+  └────
+
+
+  If the value is `context', the link consists of the file’s identifier
+  and the text of the current heading, like this:
+
+  ┌────
+  │ [[denote:20240118T060608::*Heading text][Some test::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.
+
+  If the value is `id' or, for backward-compatibility, any other non-nil
+  value, then Denote will use the standard Org mechanism of the
+  `CUSTOM_ID' property to create a unique link to the heading. If the
+  heading does not have a `CUSTOM_ID', it creates it and includes it in
+  its `PROPERTIES' drawer. If a `CUSTOM_ID' exists, it takes it as-is.
+  The result is like this:
+
+  ┌────
+  │ [[denote:20240118T060608::#h:eed0fb8e-4cc7-478f][Some test::Heading text]]
+  └────
+
+
+  The value of the `CUSTOM_ID' is determined by the Org user option
+  `org-id-method'. The sample shown above uses the default UUID
+  infrastructure (though I deleted a few characters to not get
+  complaints from the byte compiler about long lines in the doc
+  string…).
+
+  Note that this option does not affect how Org behaves with regard to
+  `org-id-link-to-org-use-id'. If that user option is set to create `ID'
+  properties, then those will be created by Org even if the Denote link
+  handler will take care to not use/store the `ID' value. Concretely,
+  users who never want `ID' properties under their headings should keep
+  `org-id-link-to-org-use-id' in its nil value.
+
+  Context links are easier to break than those with a `CUSTOM_ID' in
+  cases where either the heading text changes or there is another
+  heading that matches that text. The potential advantage of context
+  links is that they do not require a `PROPERTIES' drawer.
+
+  When visiting a link to a heading, Org opens the Denote file and then
+  navigates to that heading.
+
+  [ This feature only works in Org mode files, as other file types do
+    not have a linking mechanism that handles unique identifiers for
+    headings or other patterns to jump to. If `org-store-link' is
+    invoked in one such file, it captures only the Denote identifier of
+    the file, even if this user option is set to a non-nil value. ]
+
+
+9.8 Adding direct links to files matching contents
+──────────────────────────────────────────────────
+
+
+9.9 Insert links from marked files in Dired
+───────────────────────────────────────────
+
+  The command `denote-link-dired-marked-notes' is similar to
+  `denote-add-links' in that it inserts in the buffer a typographic list
+  of links to Denote notes ([Insert links matching a regexp]).  Though
+  instead of reading a regular expression, it lets the user mark files
+  in Dired and link to them.  This should be easier for users of all
+  skill levels, instead of having to write a potentially complex regular
+  expression.
+
+  If there are multiple buffers that visit a Denote note, this command
+  will ask to select one among them, using minibuffer completion.  If
+  there is only one buffer, it will operate in it outright.  If there
+  are no buffers, it will produce an error.
+
+  With optional `ID-ONLY' as a prefix argument (`C-u' by default), the
+  command inserts links with just the identifier, which is the same
+  principle as with `denote-link' and others ([Adding a single link]).
+
+  The command `denote-link-dired-marked-notes' is meant to be used from
+  a Dired buffer.
+
+  As always, links are created only for files which qualify as a “note”
+  for our purposes ([Linking notes]).
+
+  The `denote-dired-link-marked-notes' is an alias for
+  `denote-link-dired-marked-notes'.
+
+
+[Insert links matching a regexp] See section 9.4
+
+[Adding a single link] See section 9.1
+
+[Linking notes] See section 9
+
+
+9.10 Link to an existing note or create a new one
+─────────────────────────────────────────────────
+
+  In one’s note-taking workflow, there may come a point where they are
+  expounding on a certain topic but have an idea about another subject
+  they would like to link to ([Linking notes]).  The user can always
+  rely on the other linking facilities we have covered herein to target
+  files that already exist.  Though they may not know whether they
+  already have notes covering the subject or whether they would need to
+  write new ones.  To this end, Denote provides two convenience
+  commands:
+
+  `denote-link-after-creating'
+        Create new note in the background and link to it directly.
+
+        Use `denote' interactively to produce the new note.  Its doc
+        string or this manual explains which prompts will be used and
+        under what conditions ([Standard note creation]).
+
+        With optional `ID-ONLY' as a prefix argument (this is the `C-u'
+        key, by default) create a link that consists of just the
+        identifier.  Else try to also include the file’s title.  This
+        has the same meaning as in `denote-link' ([Adding a single
+        link]).
+
+        IMPORTANT NOTE: Normally, `denote' does not save the buffer it
+        produces for the new note ([The
+        `denote-save-buffer-after-creation' option]).  This is a safety
+        precaution to not write to disk unless the user wants it
+        (e.g. the user may choose to kill the buffer, thus cancelling
+        the creation of the note). However, for this command the
+        creation of the note happens in the background and the user may
+        miss the step of saving their buffer. We thus have to save the
+        buffer in order to (i) establish valid links, and (ii) retrieve
+        whatever front matter from the target file.
+
+  `denote-link-after-creating-with-command'
+        This command is like `denote-link-after-creating' except it
+        prompts for a note-creating command ([Points of entry]).  Use
+        this to, for example, call `denote-signature' so that the newly
+        created note has a signature as part of its file name.  Optional
+        `ID-ONLY' has the same meaning as in the command
+        `denote-link-after-creating'.
+
+  `denote-link-or-create'
+        Use `denote-link' on `TARGET' file, creating it if necessary.
+
+        If `TARGET' file does not exist, call
+        `denote-link-after-creating' which runs the `denote' command
+        interactively to create the file.  The established link will
+        then be targeting that new file.
+
+        If `TARGET' file does not exist, add the user input that was
+        used to search for it to the history of the
+        `denote-file-prompt'.  The user can then retrieve and possibly
+        further edit their last input, using it as the newly created
+        note’s actual title.  At the `denote-file-prompt' type `M-p'
+        with the default key bindings, which calls
+        `previous-history-element'.
+
+        With optional `ID-ONLY' as a prefix argument create a link with
+        just the file’s identifier.  This has the same meaning as in
+        `denote-link'.
+
+        This command has the alias
+        `denote-link-to-existing-or-new-note', which helps with
+        discoverability.
+
+  In all of the above, an optional prefix argument (`C-u' by default)
+  creates a link that consists of just the identifier.  This has the
+  same meaning as in the regular `denote-link' command.
+
+  Denote provides similar functionality for opening an existing note or
+  creating a new one ([Open an existing note or create it if missing]).
+
+
+[Linking notes] See section 9
+
+[Standard note creation] See section 5.1
+
+[Adding a single link] See section 9.1
+
+[The `denote-save-buffer-after-creation' option] See section 5.1.5
+
+[Points of entry] See section 5
+
+[Open an existing note or create it if missing] See section 5.6
+
+
+9.11 The backlinks’ buffer
+──────────────────────────
+
+  [ Older versions of Denote had two types of formatting for the
+    backlinks’ buffer. As part of version `4.0.0', we only support the
+    standard Xref view which shows matches in their context. The user
+    option `denote-backlinks-show-context' is thus removed. ]
+
+  The command `denote-backlinks' (alias `denote-show-backlinks-buffer')
+  produces a bespoke buffer which displays backlinks to the current note
+  ([Interact with the links buffer]). A “backlink” is a link back to the
+  present entry. Backlinks can be generated for any file type that has a
+  Denote file-naming scheme, such as PDFs, images, and videos, as well
+  as the regular plain text files.
+
+  The backlinks’ buffer is, in essence, the equivalent of a Unix `grep'
+  command across the `denote-directory' ([Speed up backlinks’ buffer
+  creation?]).  It groups matches by file name, while it displays the
+  line on which a link to the current file occurs together with its
+  context. It looks like this (plus the appropriate fontification):
+
+  ┌────
+  │ Backlinks to "On being honest" (20220614T130812)
+  │ ------------------------------------------------
+  │ 
+  │ 20220614T145606--let-this-glance-become-a-stare__journal.txt
+  │ 37: growing into it: [[denote:20220614T130812][On being honest]].
+  │ 64: As I said in [[denote:20220614T130812][On being honest]] I have never
+  │ 20220616T182958--feeling-butterflies-in-your-stomach__journal.txt
+  │ 62: indifference.  In [[denote:20220614T130812][On being honest]] I alluded
+  └────
+
+  Note that the width of the lines in the context depends on the
+  underlying file. In the above example, the lines are split at the
+  `fill-column'. Long lines will show up just fine. Also note that the
+  built-in user option `xref-truncation-width' can truncate long lines
+  to a given maximum number of characters.
+
+  As with query links, the backlinking facility uses Emacs’ built-in
+  Xref infrastructure ([Adding a query link]). On some operating
+  systems, the user may need to add certain executables to the relevant
+  environment variable ([Why do I get “Search failed with status 1” when
+  I search for backlinks?]).
+
+  The placement of the backlinks’ buffer is subject to the user option
+  `denote-backlinks-display-buffer-action'. Due to the nature of the
+  underlying `display-buffer' mechanism, this inevitably is a relatively
+  advanced feature. By default, the backlinks’ buffer is displayed below
+  the current window.
+
+  Backlinks to the current file can also be visited by using the
+  minibuffer completion interface with the `denote-find-backlink'
+  command ([Visiting linked files via the minibuffer]).
+
+
+[Interact with the links buffer] See section 16
+
+[Speed up backlinks’ buffer creation?] See section 25.10
+
+[Adding a query link] See section 9.3
+
+[Why do I get “Search failed with status 1” when I search for
+backlinks?] See section 25.11
+
+[Visiting linked files via the minibuffer] See section 9.13
+
+
+9.12 Writing metanotes
+──────────────────────
+
+  A “metanote” is an entry that describes other entries who have
+  something in common.  Writing metanotes can be part of a workflow
+  where the user periodically reviews their work in search of patterns
+  and deeper insights.  For example, you might want to read your journal
+  entries from the past year to reflect on your experiences, evolution
+  as a person, and the like.
+
+  The commands `denote-add-links', `denote-link-dired-marked-notes' are
+  suited for this task.
+
+  [Insert links matching a regexp].
+
+  [Insert links from marked files in Dired].
+
+  You will create your metanote the way you use Denote ordinarily
+  (metanotes may have the `metanote' keyword, among others), write an
+  introduction or however you want to go about it, invoke the command
+  which inserts multiple links at once (see the above-cited nodes), and
+  continue writing.
+
+  Metanotes can serve as entry points to groupings of individual notes.
+  They are not the same as a filtered list of files, i.e. what you would
+  do in Dired or the minibuffer where you narrow the list of notes to a
+  given query.  Metanotes contain the filtered list plus your thoughts
+  about it.  The act of purposefully grouping notes together and
+  contemplating on their shared patterns is what adds value.
+
+  Your future self will appreciate metanotes for the function they serve
+  in encapsulating knowledge, while current you will be equipped with
+  the knowledge derived from the deliberate self-reflection.
+
+
+[Insert links matching a regexp] See section 9.4
+
+[Insert links from marked files in Dired] See section 9.9
+
+
+9.13 Visiting linked files via the minibuffer
+─────────────────────────────────────────────
+
+  Denote has a major-mode-agnostic mechanism to collect all linked file
+  references in the current buffer and return them as an appropriately
+  formatted list.  This list can then be used in interactive commands.
+  The `denote-find-link' is such a command.  It uses minibuffer
+  completion to visit a file that is linked to from the current note.
+  The candidates have the correct metadata, which is ideal for
+  integration with other standards-compliant tools ([Extending Denote]).
+  For instance, a package such as `marginalia' will display accurate
+  annotations, while the `embark' package will be able to work its magic
+  such as in exporting the list into a filtered Dired buffer (i.e. a
+  familiar Dired listing with only the files of the current minibuffer
+  session).
+
+  To visit backlinks to the current note via the minibuffer, use
+  `denote-find-backlink'.  This is an alternative to placing backlinks
+  in a dedicated buffer ([The backlinks’ buffer]).
+
+
+[Extending Denote] See section 19
+
+[The backlinks’ buffer] See section 9.11
+
+
+9.14 Fontify links in non-Org buffers
+─────────────────────────────────────
+
+  Denote links are automatically fontified in Org buffers ([Adding a
+  single link]).  This means that Org recognises the link and applies
+  the relevant properties to it to make it clickable/actionable. Other
+  major modes, such as `markdown-mode' (for `.md' files) or `text-mode'
+  (for `.txt' files) do not have this feature built into them. Users can
+  still get the same behaviour as with Org by activating the
+  `denote-fontify-links-mode'.
+
+  The `denote-fontify-links-mode' is a buffer-local minor mode. Users
+  can enable it automatically in plain text files that correspond to
+  denote notes with something like this:
+
+  ┌────
+  │ (add-hook 'text-mode-hook #'denote-fontify-links-mode-maybe)
+  └────
+
+  The `text-mode-hook' applies to all modes derived from `text-mode',
+  including `markdown-mode'. Though a more explicit setup does no harm:
+
+  ┌────
+  │ (add-hook 'markdown-mode-hook #'denote-fontify-links-mode-maybe)
+  └────
+
+  Because Org already recognises `denote:' links, the function
+  `denote-fontify-links-mode-maybe' will not enable the mode
+  `denote-fontify-links-mode' in Org buffers.
+
+  In files whose major mode is `markdown-mode', the default key binding
+  `C-c C-o' (which calls the command `markdown-follow-thing-at-point')
+  correctly resolves `denote:' links. Interested users can refer to the
+  function `denote-link-markdown-follow' for the implementation details.
+
+
+[Adding a single link] See section 9.1
+
+
+9.15 The `denote-link-description-format' to format link descriptions
+─────────────────────────────────────────────────────────────────────
+
+  The user option `denote-link-description-format' controls how the
+  command `denote-link' and related functions create a link description
+  by default.
+
+  The value can be either a function or a string. If it is a function,
+  it is called with one argument, the file, and should return a string
+  representing the link description.
+
+  The default is a function that returns the active region or the title
+  of the note (with the signature if present).
+
+  If the value is a string, it treats specially the following
+  specifiers:
+
+  • The `%t' is the Denote `TITLE' in the front matter or the file name.
+  • The `%T' is the Denote `TITLE' in the file name.
+  • The `%i' is the Denote `IDENTIFIER' of the file.
+  • The `%I' is the identifier converted to `DAYNAME, DAYNUM MONTHNUM
+      YEAR'.
+  • The `%d' is the same as `%i' (`DATE' mnemonic).
+  • The `%D' is a “do what I mean” which behaves the same as `%t' and if
+    that returns nothing, it falls back to `%I', then `%i'.
+  • The `%d' is the same as `%i' (`DATE' mnemonic).
+  • The `%s' is the Denote `SIGNATURE' of the file.
+  • The `%k' is the Denote `KEYWORDS' of the file.
+  • The `%%' is a literal percent sign.
+
+  In addition, the following flags are available for each of the
+  specifiers:
+
+  0
+        Pad to the width, if given, with zeros instead of spaces.
+  -
+        Pad to the width, if given, on the right instead of the left.
+  <
+        Truncate to the width and precision, if given, on the left.
+  >
+        Truncate to the width and precision, if given, on the right.
+  ^
+        Convert to upper case.
+  _
+        Convert to lower case.
+
+  When combined all together, the above are written thus:
+
+  ┌────
+  │ %<flags><width><precision>SPECIFIER-CHARACTER
+  └────
+
+
+  Any other text in the string it taken as-is. Users may want, for
+  example, to include some text that makes Denote links stand out, such
+  as a `[D]' prefix.
+
+  If the region is active, its text is used as the link’s description.
+
+
+10 Choose which commands to prompt for
+══════════════════════════════════════
+
+  The user option `denote-commands-for-new-notes' specifies a list of
+  commands that are available at the `denote-command-prompt'.  This
+  prompt is used by Denote commands that ask the user how to create a
+  new note, as described elsewhere in this manual:
+
+  • [Open an existing note or create it if missing]
+  • [Link to a note or create it if missing]
+
+  The default value includes all the basic file-creating commands
+  ([Points of entry]).  Users may customise this value if (i) they only
+  want to see fewer options and/or (ii) wish to include their own custom
+  command in the list ([Write your own convenience commands]).
+
+
+[Open an existing note or create it if missing] See section 5.6
+
+[Link to a note or create it if missing] See section 9.10
+
+[Points of entry] See section 5
+
+[Write your own convenience commands] See section 5.1.4.1
+
+
+11 Fontification in Dired
+═════════════════════════
+
+  One of the upsides of Denote’s file-naming scheme is the predictable
+  pattern it establishes, which appears as a near-tabular presentation
+  in a listing of notes (i.e. in Dired).  The `denote-dired-mode' can
+  help enhance this impression, by fontifying the components of the file
+  name to make the date (identifier) and keywords stand out.
+
+  There are two ways to set the mode.  Either use it for all
+  directories, which probably is not needed:
+
+  ┌────
+  │ (add-hook 'dired-mode-hook #'denote-dired-mode)
+  └────
+
+  Or configure the user option `denote-dired-directories' and then set
+  up the function `denote-dired-mode-in-directories':
+
+  ┌────
+  │ ;; We use different ways to specify a path for demo purposes.
+  │ (setq denote-dired-directories
+  │       (list denote-directory
+  │ 	    (thread-last denote-directory (expand-file-name "attachments"))
+  │ 	    (expand-file-name "~/Documents/vlog")))
+  │ 
+  │ (add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)
+  └────
+
+  The user option `denote-dired-directories-include-subdirectories'
+  specifies whether the `denote-dired-directories' also cover their
+  subdirectories. By default they do not. Set this option to `t' to
+  include subdirectories as well.
+
+  The faces we define for this purpose are:
+
+  ⁃ `denote-faces-date'
+  ⁃ `denote-faces-delimiter'
+  ⁃ `denote-faces-extension'
+  ⁃ `denote-faces-keywords'
+  • `denote-faces-signature'
+  ⁃ `denote-faces-subdirectory'
+  ⁃ `denote-faces-time'
+  ⁃ `denote-faces-title'
+
+  For more control, we also provide these:
+
+  #+vindex denote-faces-year +vindex denote-faces-month +vindex
+  #denote-faces-day +vindex denote-faces-hour +vindex
+  #denote-faces-minute +vindex denote-faces-second
+  ⁃ `denote-faces-year'
+  ⁃ `denote-faces-month'
+  ⁃ `denote-faces-day'
+  ⁃ `denote-faces-hour'
+  ⁃ `denote-faces-minute'
+  ⁃ `denote-faces-second'
+
+  For the time being, the `diredfl' package is not compatible with this
+  facility.
+
+  The `denote-dired-mode' does not only fontify note files that were
+  created by Denote: it covers every file name that follows our naming
+  conventions ([The file-naming scheme]).  This is particularly useful
+  for scenaria where, say, one wants to organise their collection of
+  PDFs and multimedia in a systematic way (and, perhaps, use them as
+  attachments for the notes Denote produces if you are writing Org notes
+  and are using its standand attachments’ facility).
+
+
+[The file-naming scheme] See section 7
+
+
+12 Automatically rename Denote buffers
+══════════════════════════════════════
+
+  The minor mode `denote-rename-buffer-mode' provides the means to
+  automatically rename the buffer of a Denote file upon visiting the
+  file. This applies both to existing Denote files as well as new ones
+  ([Points of entry]). Enable the mode thus:
+
+  ┌────
+  │ (denote-rename-buffer-mode 1)
+  └────
+
+  Buffers are named by applying the function specified in the user
+  option `denote-rename-buffer-function'. The default function is
+  `denote-rename-buffer': it renames the buffer based on the template
+  set in the user option `denote-rename-buffer-format'. By default, the
+  formatting template targets only the `TITLE' component of the file
+  name ([The file-naming scheme]). Other fields are explained elsewhere
+  in this manual ([The denote-rename-buffer-format]).
+
+  Note that renaming a buffer is not the same as renaming a file
+  ([Renaming files]). The former is just for convenience inside of
+  Emacs.  Whereas the latter is for writing changes to disk, making them
+  available to all programs.
+
+
+[Points of entry] See section 5
+
+[The file-naming scheme] See section 7
+
+[The denote-rename-buffer-format] See section 12.1
+
+[Renaming files] See section 6
+
+12.1 The `denote-rename-buffer-format' option
+─────────────────────────────────────────────
+
+  The user option `denote-rename-buffer-format' controls how the
+  function `denote-rename-buffer' chooses the name of the
+  buffer-to-be-renamed.
+
+  The value of this user option is a string. The following specifiers
+  are placeholders for Denote file name components ([The file-naming
+  scheme]):
+
+  • The `%t' is the Denote `TITLE' in the front matter or the file name.
+  • The `%T' is the Denote `TITLE' in the file name.
+  • The `%i' is the Denote `IDENTIFIER' of the file.
+  • The `%I' is the identifier converted to `DAYNAME, DAYNUM MONTHNUM
+      YEAR'.
+  • The `%d' is the same as `%i' (`DATE' mnemonic).
+  • The `%D' is a “do what I mean” which behaves the same as `%t' and if
+    that returns nothing, it falls back to `%I', then `%i'.
+  • The `%s' is the Denote `SIGNATURE' of the file.
+  • The `%k' is the Denote `KEYWORDS' of the file.
+  • The `%b' is an indicator of whether or not the file has backlinks
+    pointing to it. The indicator string is defined in the user option
+    `denote-rename-buffer-backlinks-indicator', alias
+    `denote-buffer-has-backlinks-string'.
+  • The `%%' is a literal percent sign.
+
+  In addition, the following flags are available for each of the
+  specifiers:
+
+  `0'
+        Pad to the width, if given, with zeros instead of spaces.
+  `-'
+        Pad to the width, if given, on the right instead of the left.
+  `<'
+        Truncate to the width and precision, if given, on the left.
+  `>'
+        Truncate to the width and precision, if given, on the right.
+  `^'
+        Convert to upper case.
+  `_'
+        Convert to lower case.
+
+  When combined all together, the above are written thus:
+
+  ┌────
+  │ %<flags><width><precision>SPECIFIER-CHARACTER
+  └────
+
+
+  Any other string it taken as-is.  Users may want, for example, to
+  include some text that makes Denote buffers stand out, such as a `[D]'
+  prefix.  Examples:
+
+  ┌────
+  │ ;; The following is the default value.  Use a literal [D] prefix,
+  │ ;; followed by the title and then the backlinks indicator.  If there
+  │ ;; is no title, use the identifier in its human-readable date
+  │ ;; representation, and if that is not possible, use the identifier
+  │ ;; as-is.
+  │ (setq denote-rename-buffer-format "[D] %D%b")
+  │ 
+  │ ;; Customize what the backlink indicator looks like.  This two-faced
+  │ ;; arrow is the default.
+  │ (setq denote-rename-buffer-backlinks-indicator  "<-->")
+  │ 
+  │ ;; Use just the title and keywords with some emoji in between, because
+  │ ;; why not?
+  │ (setq denote-rename-buffer-format "%t 🤨 %k")
+  │ 
+  │ ;; Use the title with a literal "[D]" before it.
+  │ (setq denote-rename-buffer-format "[D] %t")
+  │ 
+  │ ;; As above, but also add the `denote-rename-buffer-backlinks-indicator' at the end.
+  │ (setq denote-rename-buffer-format "[D] %t%b")
+  └────
+
+  Users who need yet more flexibility are best served by writing their
+  own function and assigning it to the `denote-rename-buffer-function'.
+
+
+[The file-naming scheme] See section 7
+
+
+13 Use Org dynamic blocks
+═════════════════════════
+
+  This section is about the external package `denote-org' (by
+  Protesilaos). The code of `denote-org' used to be available as part of
+  the main `denote' package, but we decided to keep each optional
+  extension as a separate package to make things easier to maintain and
+  to understand.
+
+  Denote can optionally integrate with Org mode’s “dynamic blocks”
+  facility. This means that it can use special blocks that are evaluated
+  with `C-c C-x C-u' (`org-dblock-update') to generate their contents.
+
+  Dynamic blocks are particularly useful for metanote entries that
+  reflect on the status of earlier notes ([Writing metanotes]). The
+  `denote-org' package defines many of these Org dynamic blocks.
+
+  ⁃ Package name (GNU ELPA): `denote-org'
+  ⁃ Official manual: <https://protesilaos.com/emacs/denote-org>
+  ⁃ Git repository: <https://github.com/protesilaos/denote-org>
+  ⁃ Backronym: Denote… Ordinarily Restricts Gyrations.
+
+
+[Writing metanotes] See section 9.12
+
+
+14 Display filtered and sorted files with `denote-sort-dired' or `denote-dired'
+═══════════════════════════════════════════════════════════════════════════════
+
+  The `denote.el' file contains functions which empower user or
+  developers to sort files by the given file name component ([The
+  file-naming scheme]).
+
+  The command `denote-sort-dired' (alias `denote-dired') produces a
+  Dired file listing with a flat, filtered, and sorted set of files from
+  the `denote-directory' ([Define a sorting function per component]). It
+  does so by a series of prompts, which can be configured with the user
+  option `denote-sort-dired-extra-prompts' ([Configure what extra
+  prompts `denote-sort-dired' issues]).
+
+  Think of `denote-sort-dired' as the counterpart to the Unix `find'
+  command. While `denote-grep' corresponds to the Unix `grep' ([Use
+  `denote-grep' to search inside files]).
+
+  The out-of-the-box behaviour of `denote-sort-dired' is as follows:
+
+  1. It first asks for a regular expression with which to match Denote
+     file names. Remember that due to Denote’s efficient file-naming
+     scheme, you usually do not need to write some complex regular
+     expression. For example, something like `_journal' will match only
+     files with a `journal' keyword.
+  2. Once the regular expression is provided, the command asks for a
+     Denote file name component to sort files by. This is a symbol among
+     `title', `keywords', `signature', and `identifier' ([Define a
+     sorting function per component]).
+  3. Finally, it asks a “yes or no” on whether to reverse the sort
+     order.
+
+  The resulting listing is a regular Dired buffer, unlike that of
+  `dired-virtual-mode' ([Use `dired-virtual-mode' for arbitrary file
+  listings]).
+
+  The sorting mechanism can be used by other packages to achieve their
+  ends. As an example, the dynamic Org blocks that the `denote-org'
+  package (by Protesilaos) defines also use this feature internally by
+  means of the non-interactive function `denote-sort-files'.
+
+
+[The file-naming scheme] See section 7
+
+[Define a sorting function per component] See section 14.2
+
+[Configure what extra prompts `denote-sort-dired' issues] See section
+14.1
+
+[Use `denote-grep' to search inside files] See section 15
+
+[Use `dired-virtual-mode' for arbitrary file listings] See section 19.6
+
+14.1 Configure what extra prompts `denote-sort-dired' issues
+────────────────────────────────────────────────────────────
+
+  By default, the `denote-sort-dired' command prompts for (i) a query to
+  match file names, (ii) a file name component to sort by, and (iii)
+  whether to reverse the sorting ([Display filtered and sorted files
+  with denote-sort-dired]).  Users can configure the latter two by
+  modifying the user option `denote-sort-dired-extra-prompts'.
+
+  The `denote-sort-dired-extra-prompts' accepts either a nil value or a
+  list of symbols among `sort-by-component', `reverse-sort', and
+  `exclude-regexp'. The order those symbols appear in the list is
+  significant, with the leftmost coming first.
+
+  These symbols correspond to the following:
+
+  • A choice to select the file name component to sort by.
+  • A yes or no prompt on whether to reverse the sorting.
+  • A string (or regular expression) of files to be excluded from the
+    results.
+
+  In case of a nil value, those extra prompts will not happen, meaning
+  that `denote-sort-dired' will fall back to using whatever is defined
+  in the variables `denote-sort-dired-default-sort-component' and
+  `denote-sort-dired-default-reverse-sort'.
+
+  Here are some examples:
+
+  ┌────
+  │ ;; The default extra prompts...
+  │ (setq denote-sort-dired-extra-prompts '(sort-by-component reverse-sort))
+  │ 
+  │ ;; When using `denote-sort-dired', ask whether to reverse the sort and
+  │ ;; then which file name component to sort by.  These are always done
+  │ ;; after the prompt to search for files matching a regexp.
+  │ (setq denote-sort-dired-extra-prompts '(reverse-sort sort-by-component))
+  │ 
+  │ ;; Do not prompt for a reverse sort.  Just use the value of
+  │ ;; `denote-sort-dired-default-reverse-sort' (which is nil out-of-the-box).
+  │ (setq denote-sort-dired-extra-prompts '(sort-by-component))
+  │ 
+  │ ;; Do not issue any extra prompts.  Always sort by the `title' file
+  │ ;; name component and never do a reverse sort.
+  │ (setq denote-sort-dired-extra-prompts nil)
+  │ (setq denote-sort-dired-default-sort-component 'title)
+  │ (setq denote-sort-dired-default-reverse-sort nil)
+  └────
+
+
+[Display filtered and sorted files with denote-sort-dired] See section
+14
+
+
+14.2 Define a sorting function per component
+────────────────────────────────────────────
+
+  When sorting by `title', `keywords', or `signature' with the
+  `denote-sort-dired' command, Denote will internally apply a sorting
+  function that is specific to each component ([Configure what extra
+  prompts `denote-sort-dired' issues]).  These are subject to user
+  configuration:
+
+  • `denote-sort-identifier-comparison-function'
+
+  • `denote-sort-title-comparison-function'
+
+  • `denote-sort-keywords-comparison-function'
+
+  • `denote-sort-signature-comparison-function'
+
+  By default, all these user options use the same sorting function,
+  namely `string-collate-lessp'. Users who have specific needs for any
+  of those file name components can write their own sorting algorithms
+  ([Sort signatures that include Luhmann-style sequences]).
+
+
+[Configure what extra prompts `denote-sort-dired' issues] See section
+14.1
+
+[Sort signatures that include Luhmann-style sequences] See section
+14.2.1
+
+14.2.1 Sort signatures that include Luhmann-style sequences
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  [ The `denote-sequence' package (by Protesilaos) covers this use-case
+    and many others ([Write sequence notes or folgezettel]). It is the
+    superior option for anyone interested in this functionality. We keep
+    the code below for reference, as there may be users of it who need
+    to revisit it. Though long-term, it is better to use
+    `denote-sequence'. ]
+
+  Niklas Luhmann would edit notes to form sequences of thoughts with
+  branching paths, such as `1.1', `1.1a', `1.2', `1.2a', `1.2b', etc.
+  With the Denote file-naming scheme, we make the word separator in each
+  file name component use the same character as the entire field, so
+  words in a title have a dash between them and signatures have the
+  equals sign ([The file-naming scheme]). Thus, our Luhmann-style
+  signature will be slightly different in their looks: `1=1', `1=1a',
+  `1=2', `1=2a', `1=2b'.
+
+  When using the `denote-sort-dired' command with default settings, our
+  signatures will not sort in an intuitive way. This is because they
+  combine numbers and letters, which require a different approach than
+  what the default sorting function is using ([Define a sorting function
+  per component]).  In the following code block, we show a sorting
+  algorithm that should do the right thing while dealing with
+  Luhmann-style signatures.
+
+  ┌────
+  │ (defun my-denote--split-luhman-sig (signature)
+  │   "Split numbers and letters in Luhmann-style SIGNATURE string."
+  │   (replace-regexp-in-string
+  │    "\\([a-zA-Z]+?\\)\\([0-9]\\)" "\\1=\\2"
+  │    (replace-regexp-in-string
+  │     "\\([0-9]+?\\)\\([a-zA-Z]\\)" "\\1=\\2"
+  │     signature)))
+  │ 
+  │ (defun my-denote--pad-sig (signature)
+  │   "Create a new signature with padded spaces for all components"
+  │   (combine-and-quote-strings
+  │    (mapcar
+  │     (lambda (x)
+  │       (string-pad x 5 32 t))
+  │     (split-string (my-denote--split-luhman-sig signature) "=" t))
+  │    "="))
+  │ 
+  │ (defun my-denote-sort-for-signatures (sig1 sig2)
+  │   "Return non-nil if SIG1 is smaller that SIG2.
+  │ Perform the comparison with `string<'."
+  │   (string< (my-denote--pad-sig sig1) (my-denote--pad-sig sig2)))
+  │ 
+  │ ;; Change the sorting function only when we sort by signature.
+  │ (setq denote-sort-signature-comparison-function #'my-denote-sort-for-signatures)
+  └────
+
+
+[Write sequence notes or folgezettel] See section 18.2
+
+[The file-naming scheme] See section 7
+
+[Define a sorting function per component] See section 14.2
+
+
+15 Use `denote-grep' to search inside files
+═══════════════════════════════════════════
+
+  The command `denote-grep' searches for the given query across all
+  readable files in the `denote-directory'. It puts the collected
+  results in an Xref buffer (just like with our backlinks and query
+  links functionality). In this buffer, users can do `M-x describe-mode'
+  (`C-h m' with default key bindings) to learn about all the actions
+  they can perform and the keys they are bound to ([Interact with the
+  links buffer]).
+
+  Think of `denote-grep' as the counterpart to the Unix `grep' command.
+  While `denote-sort-dired' corresponds to the Unix `find' ([Display
+  filtered and sorted files with `denote-sort-dired']).
+
+  The command `denote-grep-marked-dired-files' is like `denote-grep' but
+  operates on the files that are marked in a Dired buffer.
+
+  The command `denote-grep-files-referenced-in-region' is like
+  `denote-grep' for any files referenced within the boundaries of the
+  marked region. Files are referenced by their identifier. This includes
+  links with just the identifier (as described in `denote-link' and
+  related ([Add a single direct link using a file name prompt])), links
+  written by an Org dynamic block (see the `denote-org' package ([Use
+  Org dynamic blocks])), or even file listings such as those of `dired'
+  and the command-line `ls' program.
+
+  The user option `denote-grep-display-buffer-action' controls where the
+  buffer with the search results is displayed at. By default, they
+  appear in the same window where the command `denote-grep' is called
+  from.
+
+
+[Interact with the links buffer] See section 16
+
+[Display filtered and sorted files with `denote-sort-dired'] See section
+14
+
+[Add a single direct link using a file name prompt] See section 9.1
+
+[Use Org dynamic blocks] See section 13
+
+
+16 Interact with the links buffer
+═════════════════════════════════
+
+  Denote commands, such as `denote-grep', `denote-backlinks', and
+  `denote-query-contents-link', produce an Xref buffer with search
+  results ([Speed up backlinks’ or query links’ buffer creation?]).
+  Matching lines are grouped by the file name they belong to.
+
+  • [Use `denote-grep' to search inside files].
+  • [The backlinks’ buffer].
+  • [Add a query link].
+
+  This buffer uses the major mode `denote-query-mode'. It binds commands
+  to keys in the `denote-query-mode-map'. Those allow users to filter
+  the output of the last search. Here, “last search” refers to the list
+  of files that were returned by whichever command produced the buffer
+  (e.g. the last `denote-grep').
+
+  `denote-query-focus-last-search'
+        Perform a search in the contents of files that were matched by
+        the last search.
+
+  `denote-query-exclude-files'
+        Exclude files from the last search whose name matches the given
+        input.
+
+  `denote-query-only-include-files'
+        Only keep files from the last search whose name matches the
+        given input.
+
+  `denote-query-exclude-files-with-keywords'
+        Exclude files from the last search whose name includes the given
+        keywords.
+
+  `denote-query-only-include-files-with-keywords'
+        Only keep files from the last search whose name includes the
+        given keywords.
+
+  `denote-query-clear-all-filters'
+        Clear all the applied filters.
+
+  Remember that these are easy to use even without knowledge of regular
+  expressions, thanks to the efficiency of the Denote file-naming scheme
+  ([Features of the file-naming scheme for searching or filtering]). For
+  instance, to exclude notes with the keyword `philosophy' from current
+  search buffer, use `denote-query-exclude-files' and then type
+  `_philosophy' as your input.
+
+  In addition to those filtering options, the `denote-query-mode' also
+  allows provides an outline mechanism to hide or show the matches as
+  these are grouped per file. There also are some of the default actions
+  provided by the Xref infrastructure. Users can do `M-x describe-mode'
+  (`C-h m' with default key bindings) to learn about all the actions
+  they can perform.
+
+
+[Speed up backlinks’ or query links’ buffer creation?] See section 25.10
+
+[Use `denote-grep' to search inside files] See section 15
+
+[The backlinks’ buffer] See section 9.11
+
+[Add a query link] See section 9.3
+
+[Features of the file-naming scheme for searching or filtering] See
+section 7.4
+
+
+17 Minibuffer histories
+═══════════════════════
+
+  Denote has a dedicated minibuffer history for each one of its prompts.
+  This practically means that using `M-p' (`previous-history-element')
+  and `M-n' (`next-history-element') will only cycle through the
+  relevant record of inputs, such as your latest titles in the `TITLE'
+  prompt, and keywords in the `KEYWORDS' prompt.
+
+  The built-in `savehist' library saves minibuffer histories.  Sample
+  configuration:
+
+  ┌────
+  │ (require 'savehist)
+  │ (setq savehist-file (locate-user-emacs-file "savehist"))
+  │ (setq history-length 500)
+  │ (setq history-delete-duplicates t)
+  │ (setq savehist-save-minibuffer-history t)
+  │ (add-hook 'after-init-hook #'savehist-mode)
+  └────
+
+
+18 Packages that build on Denote
+════════════════════════════════
+
+  This is a list of packages that extend Denote. If you are a package
+  author, please let us know about your work and we will include it here
+  (either use the Git repositories or email Protesilaos directly).
+
+
+18.1 Use the `consult-denote' package for enhanced minibuffer interactions
+──────────────────────────────────────────────────────────────────────────
+
+  The `consult-denote' package by me (Protesilaos) integrates Denote
+  with Daniel Mendler’s `consult' package:
+  <https://github.com/protesilaos/consult-denote>.
+
+  The idea is to preserve the familiar patterns of interaction with the
+  various Denote commands but add to them an extra layer of
+  functionality, such as the preview mechanism that Consult provides
+  (e.g. preview the file you are about to link to).
+
+  Additionally, `consult-denote' defines new “sources” for the
+  `consult-buffer' command. This command provides a single point of
+  entry for buffers, recently opened files, and bookmarks. With
+  `consult-denote', it has a dedicated place for Denote-specific
+  buffers, silos, and more (all of which are configurable).
+
+  Unlike the `consult-notes' package by Colin McLear, `consult-denote'
+  uses the same presentation of data in the minibuffer to stay in sync
+  with Denote and make its feature set entirely optional ([Use the
+  `consult-notes' package]).  It also only works with Denote.
+
+
+[Use the `consult-notes' package] See section 18.9
+
+
+18.2 Use the `denote-sequence' package to write sequence notes or "folgezettel"
+───────────────────────────────────────────────────────────────────────────────
+
+  This section is about the external package `denote-sequence' (by
+  Protesilaos). The original idea was to include the code as part of the
+  `denote' package, but we decided to keep each optional extension as a
+  separate package to make things easier to maintain and to understand.
+
+  Denote defines an optional file name component called the `SIGNATURE'
+  ([The file-naming scheme]). This is a free-form field that users can
+  fill in with whatever text they want, such as to have a video split up
+  into `part1' and `part2', or to set some kind of priority like `a' and
+  `b', or even to have a special tag that stands out from the rest of
+  the keywords.
+
+  A more specialised use-case of the `SIGNATURE' is to define a
+  hierarchical relationship between notes, such that the thoughts they
+  expound on form sequences. For example, an article about the Labrador
+  Retriever dog breed is a continuation of a thought process that
+  extends something about dog breeds in general which, in turn, is a
+  topic that belongs to the wider theme of dogs.
+
+  The `denote-sequence' package has a manual that explains these
+  concepts and relevant commands in further detail:
+
+  ⁃ Package name (GNU ELPA): `denote-sequence'
+  ⁃ Official manual: <https://protesilaos.com/emacs/denote-sequence>
+  ⁃ Git repository: <https://github.com/protesilaos/denote-sequence>
+  ⁃ Backronym: Denote… Sequences Efficiently Queue Unsorted Entries
+    Notwithstanding Curation Efforts.
+
+
+[The file-naming scheme] See section 7
+
+
+18.3 Use the `denote-markdown' package to better integrate Markdown with Denote
+───────────────────────────────────────────────────────────────────────────────
+
+  The `denote-markdown' package (by Protesilaos) provides some
+  convenience functions to better integrate Markdown with Deonte. This
+  is mostly about converting links from one type to another so that they
+  can work in different applications (because Markdown does not have a
+  standardised way to define custom link types).
+
+  The code of `denote-markdown' used to be bundled up with the `denote'
+  package before version `4.0.0' of the latter and was available in the
+  file `denote-md-extras.el'. Users of the old code will need to adapt
+  their setup to use the `denote-markdown' package. This can be done by
+  replacing all instances of `denote-md-extras' with `denote-markdown'
+  across their configuration.
+
+  ⁃ Package name (GNU ELPA): `denote-markdown'
+  ⁃ Official manual: <https://protesilaos.com/emacs/denote-markdown>
+  ⁃ Git repository: <https://github.com/protesilaos/denote-markdown>
+  ⁃ Backronyms: Denote… Markdown’s Ambitious Reimplimentations Knowingly
+    Dilute Obvious Widespread Norms; Denote… Markup Agnosticism Requires
+    Knowhow to Do Only What’s Necessary.
+
+
+18.4 Use the `denote-journal' package which was formerly `denote-journal-extras.el'
+───────────────────────────────────────────────────────────────────────────────────
+
+  The `denote-journal' package (by Protesilaos) makes it easier to use
+  Denote for journaling. While it is possible to use the generic
+  `denote' command (and related) to maintain a journal, this package
+  defines extra functionality to streamline the journaling workflow.
+
+  The code of `denote-journal' used to be bundled up with the `denote'
+  package before version `4.0.0' of the latter and was available in the
+  file `denote-journal-extras.el'. Users of the old code will need to
+  adapt their setup to use the `denote-journal' package. This can be
+  done by replacing all instances of `denote-journal-extras' with
+  `denote-journal' across their configuration.
+
+  ⁃ Package name (GNU ELPA): `denote-journal'
+  ⁃ Official manual: <https://protesilaos.com/emacs/denote-journal>
+  ⁃ Git repository: <https://github.com/protesilaos/denote-journal>
+  ⁃ Backronym: Denote… Journaling Obviously Utilises Reasonableness
+    Notwithstanding Affectionate Longing.
+
+
+18.5 Use the `denote-silo' package which formerly was `denote-silo-extras.el'
+─────────────────────────────────────────────────────────────────────────────
+
+  The `denote-silo' package (by Protesilaos) provides convenience
+  functions for working with silos ([Maintain separate directory silos
+  for notes]).
+
+  The code of `denote-silo' used to be bundled up with the `denote'
+  package before version `4.0.0' of the latter and was available in the
+  file `denote-silo-extras.el'. Users of the old code will need to adapt
+  their setup to use the `denote-silo' package. This can be done by
+  replacing all instances of `denote-silo-extras' with `denote-silo'
+  across their configuration.
+
+  ⁃ Package name (GNU ELPA): `denote-silo'
+  ⁃ Official manual: <https://protesilaos.com/emacs/denote-silo>
+  ⁃ Git repository: <https://github.com/protesilaos/denote-silo>
+  ⁃ Backronym: Denote… Silos Insulate Localised Objects.
+
+
+[Maintain separate directory silos for notes] See section 5.7
+
+
+18.6 Use the `denote-search' package as a search interface
+──────────────────────────────────────────────────────────
+
+  [ As part of version `4.0.0', Denote comes with the `denote-grep'
+    command and related functionality ([Use `denote-grep' to search
+    inside files]).  The core of this feature set was written by Lucas
+    Quintana. ]
+
+  The `denote-search' package by Lucas Quintana provides a search
+  utility for Denote: <https://github.com/lmq-10/denote-search>.
+
+  It allows you to search for a regular expression in the content of
+  your notes. Its main advantages over other similar tools are the
+  possibility of filtering the results by file name and doing further
+  searches in the files matched previously. This allows for advanced
+  usage (think about finding a note with two or three specific words in
+  different lines and with a specific keyword). More features are
+  described in its comprehensive manual. `denote-search' builds upon
+  standard Emacs libraries, namely Xref, and so it doesn’t have external
+  dependencies other than Denote itself.
+
+
+[Use `denote-grep' to search inside files] See section 15
+
+
+18.7 Use the `denote-explore' package to explore your notes
+───────────────────────────────────────────────────────────
+
+  Peter Prevos has developed the `denote-explore' package which provides
+  four groups of Emacs commands to explore your Denote files:
+
+  Summary statistics
+        Count notes, attachments and keywords.
+  Random walks
+        Generate new ideas using serendipity.
+  Janitor
+        Manage your denote collection.
+  Visualisations
+        Visualise your Denote network.
+
+  The package’s documentation covers the details:
+  <https://lucidmanager.org/productivity/denote-explore/>.
+
+
+18.8 Use the `citar-denote' package for bibliography notes
+──────────────────────────────────────────────────────────
+
+  Peter Prevos has produced the `citar-denote' package which makes it
+  possible to write notes on BibTeX entries with the help of the `citar'
+  package.  These notes have the citation’s unique key associated with
+  them in the file’s front matter.  They also get a configurable keyword
+  in their file name, making it easy to find them in Dired and/or
+  retrieve them with the various Denote methods.
+
+  With `citar-denote', the user leverages standard minibuffer completion
+  mechanisms (e.g. with the help of the `vertico' and `embark' packages)
+  to manage bibliographic notes and access those notes with ease.  The
+  package’s documentation covers the details:
+  <https://lucidmanager.org/productivity/bibliographic-notes-in-emacs-with-citar-denote/>.
+
+
+18.9 Use the `consult-notes' package
+────────────────────────────────────
+
+  [ Also check the `consult-denote' package by me (Protesilaos): [Use
+    the `consult-denote' package for enhanced minibuffer
+    interactions]. ]
+
+  If you are using Daniel Mendler’s `consult' (which is a brilliant
+  package), you will most probably like its `consult-notes' extension,
+  developed by Colin McLear.  It uses the familiar mechanisms of Consult
+  to preview the currently selected entry and to filter searches via a
+  prefix key.  For example:
+
+  ┌────
+  │ (setq consult-notes-file-dir-sources
+  │       `(("Denote Notes"  ?d ,(denote-directory))
+  │ 	("Books"  ?b "~/Documents/books/")))
+  └────
+
+  With the above, `M-x consult-notes' will list the files in those two
+  directories.  If you type `d' and space, it narrows the list to just
+  the notes, while `b' does the same for books.
+
+  The other approach is to enable the `consult-notes-denote-mode'.  It
+  takes care to add the `denote-directory' to the sources that
+  `consult-notes' reads from.  Denote notes are then filtered by the `d'
+  prefix followed by a space.
+
+  The minor mode has the extra feature of reformatting the title of
+  notes shown in the minibuffer.  It isolates the `TITLE' component of
+  each note and shows it without hyphens, while presenting keywords in
+  their own column.  The user option `consult-notes-denote-display-id'
+  can be set to `nil' to hide the identifier.  Depending on how one
+  searches through their notes, this refashioned presentation may be the
+  best option ([Features of the file-naming scheme for searching or
+  filtering]).
+
+
+[Use the `consult-denote' package for enhanced minibuffer interactions]
+See section 18.1
+
+[Features of the file-naming scheme for searching or filtering] See
+section 7.4
+
+
+18.10 Use the `denote-menu' package
+───────────────────────────────────
+
+  Denote’s file-naming scheme is designed to be efficient and to provide
+  valueable meta information about the file.  The cost, however, is that
+  it is terse and harder to read, depending on how the user chooses to
+  filter and process their notes.
+
+  To this end, [the `denote-menu' package by Mohamed Suliman] provides
+  the convenience of a nice tabular interface for all notes.
+  `denote-menu' removes the delimiters that are found in Denote file
+  names and presents the information in a human-readable format.
+  Furthermore, the package provides commands to interact with the list
+  of notes, such as to filter them and to transition from the tabular
+  list to Dired.  Its documentation expands on the technicalities.
+
+
+[the `denote-menu' package by Mohamed Suliman]
+<https://github.com/namilus/denote-menu>
+
+
+18.11 Use the `denote-zettel-interface' package
+───────────────────────────────────────────────
+
+  The [`denote-zettel-interface' package by Kristoffer Balintona] is
+  designed for those who want to use Denote while adhering to a strict
+  Zettelkasten methodology of sequence notes (Folgezettel). This method
+  leverages the optional `SIGNATURE' file name component of Denote ([The
+  file-naming scheme]).  The package provides a point of entry to one’s
+  note by visualising them in a tabulated (grid) interface. Files are
+  sorted by their Folgezettel index. Users can then use a number of
+  commands to filter their files, navigate around, and the like.
+
+  Note that the package is in early development as of this writing
+  (2024-12-03 10:18 +0200).
+
+
+[`denote-zettel-interface' package by Kristoffer Balintona]
+<https://github.com/krisbalintona/denote-zettel-interface>
+
+[The file-naming scheme] See section 7
+
+
+19 Extending Denote
+═══════════════════
+
+  Denote is a tool with a narrow scope: create notes and link between
+  them, based on the aforementioned file-naming scheme. For other common
+  operations the user is advised to rely on standard Emacs facilities or
+  specialised third-party packages ([Packages that build on
+  Denote]). This section covers the details.
+
+
+[Packages that build on Denote] See section 18
+
+19.1 Access the data of the latest note
+───────────────────────────────────────
+
+  The variable `denote-current-data' is updated each time a new note is
+  created as well as after a rename operation.
+
+  This is an alist where each `car' is one among `title', `keywords',
+  `signature', `directory', `date', `id', `file-type', `template'. The
+  value each of them contains is the unprocessed input (e.g. the title
+  before it is sluggified).
+
+  Users who need to access this data as part of their custom code can
+  rely on the hooks `denote-after-new-note-hook' and
+  `denote-after-rename-file-hook'.
+
+
+19.2 Create a new note in any directory
+───────────────────────────────────────
+
+  The commands that create new files are designed to write to the
+  `denote-directory'. The idea is that the linking mechanism can find
+  any file by its identifier if it is in the `denote-directory'
+  (searching the entire file system would be cumbersome).
+
+  However, these are cases where the user needs to create a new note in
+  an arbitrary directory. The following command can do this. Put the
+  code in your configuration file and evaluate it. Then call the command
+  by its name with `M-x'.
+
+  ┌────
+  │ (defun my-denote-create-note-in-any-directory ()
+  │   "Create new Denote note in any directory.
+  │ Prompt for the directory using minibuffer completion."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let ((denote-directory (read-directory-name "New note in: " nil nil :must-match)))
+  │     (call-interactively 'denote)))
+  └────
+
+
+19.3 Find empty notes and put them in a Dired buffer
+────────────────────────────────────────────────────
+
+  [ This feature is based on the command `denote-sort-dired' ([Sort
+  files by component]). ]
+
+  Users may have a workflow where they use the commands
+  `denote-link-or-create' or `denote-link-after-creating' (and related)
+  to produce new notes that they plan to elaborate on later ([Link to an
+  existing note or create a new one]).
+
+  To help users find those empty notes, we document the following
+  commands:
+
+  • `my-denote-sort-dired-empty-files'
+  • `my-denote-sort-dired-without-empty-files'
+  • `my-denote-sort-dired-all-empty-files'
+  • `my-denote-sort-dired-without-all-empty-files'
+
+  ┌────
+  │ (require 'denote-sort)
+  │ 
+  │ (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
+  │ has no contents or has only the front matter."
+  │   (and (denote-file-is-note-p file)
+  │        (or (denote--file-with-temp-buffer file
+  │ 	     (re-search-forward "^$" nil t)
+  │ 	     (if (re-search-forward "[^\s\t\n\r]+" nil t)
+  │ 		 nil
+  │ 	       t))
+  │ 	   ;; This must come later because here we consider a file
+  │ 	   ;; "empty" even if it only has front matter.
+  │ 	   (denote--file-empty-p file))))
+  │ 
+  │ (defun my-denote-sort-dired-empty-files (files-matching-regexp sort-by-component reverse)
+  │   "Like `denote-sort-dired' but only cover empty files.
+  │ Empty files are those that satisfy `my-denote--note-has-no-contents-p'."
+  │   (interactive
+  │    (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts)))
+  │   (let ((component (or sort-by-component
+  │ 		       denote-sort-dired-default-sort-component
+  │ 		       'identifier))
+  │ 	(reverse-sort (or reverse
+  │ 			  denote-sort-dired-default-reverse-sort
+  │ 			  nil)))
+  │     (if-let* ((default-directory (denote-directory))
+  │ 	      (files (denote-sort-get-directory-files files-matching-regexp component reverse-sort))
+  │ 	      (empty-files (seq-filter #'my-denote--note-has-no-contents-p files))
+  │ 	      ;; NOTE 2023-12-04: Passing the FILES-MATCHING-REGEXP as
+  │ 	      ;; buffer-name produces an error if the regexp contains a
+  │ 	      ;; wildcard for a directory. I can reproduce this in emacs
+  │ 	      ;; -Q and am not sure if it is a bug. Anyway, I will report
+  │ 	      ;; it upstream, but even if it is fixed we cannot use it
+  │ 	      ;; for now (whatever fix will be available for Emacs 30+).
+  │ 	      (denote-sort-dired-buffer-name (format "Denote sort `%s' by `%s'" files-matching-regexp component))
+  │ 	      (buffer-name (format "Denote sort by `%s' at %s" component (format-time-string "%T"))))
+  │ 	(let ((dired-buffer (dired (cons buffer-name (mapcar #'file-relative-name empty-files)))))
+  │ 	  (setq denote-sort--dired-buffer dired-buffer)
+  │ 	  (with-current-buffer dired-buffer
+  │ 	    (setq-local revert-buffer-function
+  │ 			(lambda (&rest _)
+  │ 			  (kill-buffer dired-buffer)
+  │ 			  (denote-sort-dired files-matching-regexp component reverse-sort))))
+  │ 	  ;; Because of the above NOTE, I am printing a message.  Not
+  │ 	  ;; what I want, but it is better than nothing...
+  │ 	  (message denote-sort-dired-buffer-name))
+  │       (message "No matching files for: %s" files-matching-regexp))))
+  │ 
+  │ (defun my-denote-sort-dired-without-empty-files (files-matching-regexp sort-by-component reverse)
+  │   "Like `denote-sort-dired' but only cover empty files.
+  │ Empty files are those that satisfy `my-denote--note-has-no-contents-p'."
+  │   (interactive
+  │    (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts)))
+  │   (let ((component (or sort-by-component
+  │ 		       denote-sort-dired-default-sort-component
+  │ 		       'identifier))
+  │ 	(reverse-sort (or reverse
+  │ 			  denote-sort-dired-default-reverse-sort
+  │ 			  nil)))
+  │     (if-let* ((default-directory (denote-directory))
+  │ 	      (files (denote-sort-get-directory-files files-matching-regexp component reverse-sort))
+  │ 	      (empty-files (seq-remove #'my-denote--note-has-no-contents-p files))
+  │ 	      ;; NOTE 2023-12-04: Passing the FILES-MATCHING-REGEXP as
+  │ 	      ;; buffer-name produces an error if the regexp contains a
+  │ 	      ;; wildcard for a directory. I can reproduce this in emacs
+  │ 	      ;; -Q and am not sure if it is a bug. Anyway, I will report
+  │ 	      ;; it upstream, but even if it is fixed we cannot use it
+  │ 	      ;; for now (whatever fix will be available for Emacs 30+).
+  │ 	      (denote-sort-dired-buffer-name (format "Denote sort `%s' by `%s'" files-matching-regexp component))
+  │ 	      (buffer-name (format "Denote sort by `%s' at %s" component (format-time-string "%T"))))
+  │ 	(let ((dired-buffer (dired (cons buffer-name (mapcar #'file-relative-name empty-files)))))
+  │ 	  (setq denote-sort--dired-buffer dired-buffer)
+  │ 	  (with-current-buffer dired-buffer
+  │ 	    (setq-local revert-buffer-function
+  │ 			(lambda (&rest _)
+  │ 			  (kill-buffer dired-buffer)
+  │ 			  (denote-sort-dired files-matching-regexp component reverse-sort))))
+  │ 	  ;; Because of the above NOTE, I am printing a message.  Not
+  │ 	  ;; what I want, but it is better than nothing...
+  │ 	  (message denote-sort-dired-buffer-name))
+  │       (message "No matching files for: %s" files-matching-regexp))))
+  │ 
+  │ (defun my-denote-sort-dired-all-empty-files ()
+  │   "List all empty files in a Dired buffer.
+  │ This is the same as calling `my-denote-sort-dired' with a
+  │ FILES-MATCHING-REGEXP of \".*\"."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let* ((other-prompts (denote-sort-dired--prompts))
+  │ 	 (sort-key (nth 1 other-prompts))
+  │ 	 (reverse (nth 2 other-prompts)))
+  │     (funcall-interactively #'my-denote-sort-dired-empty-files ".*" sort-key reverse)))
+  │ 
+  │ (defun my-denote-sort-dired-without-all-empty-files ()
+  │   "List all empty files in a Dired buffer.
+  │ This is the same as calling `my-denote-sort-dired' with a
+  │ FILES-MATCHING-REGEXP of \".*\"."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let* ((other-prompts (denote-sort-dired--prompts))
+  │ 	 (sort-key (nth 1 other-prompts))
+  │ 	 (reverse (nth 2 other-prompts)))
+  │     (funcall-interactively #'my-denote-sort-dired-without-empty-files ".*" sort-key reverse)))
+  └────
+
+  [ In the above snippet, I am purposefully duplicating code to make it
+    easier for users to pick the ones they need. ]
+
+
+[Sort files by component] See section 14
+
+[Link to an existing note or create a new one] See section 9.10
+
+
+19.4 Automatically rename the note after saving it
+──────────────────────────────────────────────────
+
+  While experimenting with Denote, users may need to try different
+  workflows to figure out what works for them. Those might involve
+  changing keywords and specifying titles in a particular way. The
+  following sample can be used:
+
+  ┌────
+  │ (defun my-denote-always-rename-on-save-based-on-front-matter ()
+  │   "Rename the current Denote file, if needed, upon saving the file.
+  │ Rename the file based on its front matter, checking for changes in the
+  │ 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))
+  │       (ignore-errors (denote-rename-file-using-front-matter buffer-file-name))
+  │       (message "Buffer saved; Denote file renamed"))))
+  │ 
+  │ (add-hook 'after-save-hook #'my-denote-always-rename-on-save-based-on-front-matter)
+  └────
+
+
+19.5 Narrow the list of files in Dired
+──────────────────────────────────────
+
+  Emacs’ standard file manager (or directory editor) can read a regular
+  expression to mark the matching files.  This is the command
+  `dired-mark-files-regexp', which is bound to `% m' by default.  For
+  example, `% m _denote' will match all files that have the `denote'
+  keyword ([Features of the file-naming scheme for searching or
+  filtering]).
+
+  Once the files are matched, the user has two options: (i) narrow the
+  list to the matching items or (ii) exclude the matching items from the
+  list.
+
+  For the former, we want to toggle the marks by typing `t' (calls the
+  command `dired-toggle-marks' by default) and then hit the letter `k'
+  (for `dired-do-kill-lines').  The remaining files are those that match
+  the regexp that was provided earlier.
+
+  For the latter approach of filtering out the matching items, simply
+  involves the use of the `k' command (`dired-do-kill-lines') to omit
+  the marked files from the list.
+
+  These sequences can be combined to incrementally narrow the list.
+  Note that `dired-do-kill-lines' does not delete files: it simply hides
+  them from the current view.
+
+  Revert to the original listing with `g' (`revert-buffer').
+
+  For a convenient wrapper, consider this example:
+
+  ┌────
+  │ (defvar prot-dired--limit-hist '()
+  │   "Minibuffer history for `prot-dired-limit-regexp'.")
+  │ 
+  │ ;;;###autoload
+  │ (defun prot-dired-limit-regexp (regexp omit)
+  │   "Limit Dired to keep files matching REGEXP.
+  │ 
+  │ With optional OMIT argument as a prefix (\\[universal-argument]),
+  │ exclude files matching REGEXP.
+  │ 
+  │ Restore the buffer with \\<dired-mode-map>`\\[revert-buffer]'."
+  │   (interactive
+  │    (list
+  │     (read-regexp
+  │      (concat "Files "
+  │ 	     (when current-prefix-arg
+  │ 	       (propertize "NOT " 'face 'warning))
+  │ 	     "matching PATTERN: ")
+  │      nil 'prot-dired--limit-hist)
+  │     current-prefix-arg))
+  │   (dired-mark-files-regexp regexp)
+  │   (unless omit (dired-toggle-marks))
+  │   (dired-do-kill-lines))
+  └────
+
+
+[Features of the file-naming scheme for searching or filtering] See
+section 7.4
+
+
+19.6 Use `dired-virtual-mode' for arbitrary file listings
+─────────────────────────────────────────────────────────
+
+  Emacs’ Dired is a powerful file manager that builds its functionality
+  on top of the Unix `ls' command.  As noted elsewhere in this manual,
+  the user can update the `ls' flags that Dired uses to display its
+  contents ([I want to sort by last modified, why won’t Denote let
+  me?]).
+
+  What Dired cannot do is parse the output of a result that is produced
+  by piped commands, such as `ls -l | sort -t _ -k2'.  This specific
+  example targets the second underscore-separated field of the file
+  name, per our conventions ([The file-naming scheme]).  Conceretely, it
+  matches the “alpha” as the sorting key in something like this:
+
+  ┌────
+  │ 20220929T200432--testing-file-one__alpha.txt
+  └────
+
+  Consider then, how Dired will sort those files by their identifier:
+
+  ┌────
+  │ 20220929T200432--testing-file-one__alpha.txt
+  │ 20220929T200532--testing-file-two__beta.txt
+  │ 20220929T200632--testing-file-three__alpha.txt
+  │ 20220929T200732--testing-file-four__beta.txt
+  └────
+
+  Whereas on the command line, we can get the following:
+
+  ┌────
+  │ $ ls | sort -t _ -k 2
+  │ 20220929T200432--testing-file-one__alpha.txt
+  │ 20220929T200632--testing-file-three__alpha.txt
+  │ 20220929T200532--testing-file-two__beta.txt
+  │ 20220929T200732--testing-file-four__beta.txt
+  └────
+
+  This is where `dired-virtual-mode' shows its utility.  If we tweak our
+  command-line invocation to include `ls -l', this mode can behave like
+  Dired on the listed files.  (We omit the output of the `-l' flag from
+  this tutorial, as it is too verbose.)
+
+  What we now need is to capture the output of `ls -l | sort -t _ -k 2'
+  in an Emacs buffer and then enable `dired-virtual-mode'.  To do that,
+  we can rely on either `M-x shell' or `M-x eshell' and then manually
+  copy the relevant contents.
+
+  For the user’s convenience, I share what I have for Eshell to quickly
+  capture the last command’s output in a dedicated buffer:
+
+  ┌────
+  │ (defcustom prot-eshell-output-buffer "*Exported Eshell output*"
+  │   "Name of buffer with the last output of Eshell command.
+  │ Used by `prot-eshell-export'."
+  │   :type 'string
+  │   :group 'prot-eshell)
+  │ 
+  │ (defcustom prot-eshell-output-delimiter "* * *"
+  │   "Delimiter for successive `prot-eshell-export' outputs.
+  │ This is formatted internally to have newline characters before
+  │ and after it."
+  │   :type 'string
+  │   :group 'prot-eshell)
+  │ 
+  │ (defun prot-eshell--command-prompt-output ()
+  │   "Capture last command prompt and its output."
+  │   (let ((beg (save-excursion
+  │ 	       (goto-char (eshell-beginning-of-input))
+  │ 	       (goto-char (point-at-bol)))))
+  │     (when (derived-mode-p 'eshell-mode)
+  │       (buffer-substring-no-properties beg (eshell-end-of-output)))))
+  │ 
+  │ ;;;###autoload
+  │ (defun prot-eshell-export ()
+  │   "Produce a buffer with output of the last Eshell command.
+  │ If `prot-eshell-output-buffer' does not exist, create it.  Else
+  │ append to it, while separating multiple outputs with
+  │ `prot-eshell-output-delimiter'."
+  │   (interactive)
+  │   (let ((eshell-output (prot-eshell--command-prompt-output)))
+  │     (with-current-buffer (get-buffer-create prot-eshell-output-buffer)
+  │       (let ((inhibit-read-only t))
+  │ 	(goto-char (point-max))
+  │ 	(unless (eq (point-min) (point-max))
+  │ 	  (insert (format "\n%s\n\n" prot-eshell-output-delimiter)))
+  │ 	(goto-char (point-at-bol))
+  │ 	(insert eshell-output)
+  │ 	(switch-to-buffer-other-window (current-buffer))))))
+  └────
+
+  Bind `prot-eshell-export' to a key in the `eshell-mode-map' and give
+  it a try (I use `C-c C-e').  In the produced buffer, activate the
+  `dired-virtual-mode'.
+
+
+[I want to sort by last modified, why won’t Denote let me?] See section
+25.7
+
+[The file-naming scheme] See section 7
+
+
+19.7 Use Embark to collect minibuffer candidates
+────────────────────────────────────────────────
+
+  `embark' is a remarkable package that lets you perform relevant,
+  context-dependent actions using a prefix key (simplifying in the
+  interest of brevity).
+
+  For our purposes, Embark can be used to produce a Dired listing
+  directly from the minibuffer.  Suppose the current note has links to
+  three other notes.  You might use the `denote-find-link' command to
+  pick one via the minibuffer.  But why not turn those three links into
+  their own Dired listing?  While in the minibuffer, invoke `embark-act'
+  which you may have already bound to `C-.' and then follow it up with
+  `E' (for the `embark-export' command).
+
+  This pattern can be repeated with any list of candidates, meaning that
+  you can narrow the list by providing some input before eventually
+  exporting the results with Embark.
+
+  Overall, this is very powerful and you might prefer it over doing the
+  same thing directly in Dired, since you also benefit from all the
+  power of the minibuffer ([Narrow the list of files in Dired]).
+
+
+[Narrow the list of files in Dired] See section 19.5
+
+
+19.8 Search file contents
+─────────────────────────
+
+  [ Users of `consult' can use the `consult-denote' package instead
+    ([Use the `consult-denote' package for enhanced minibuffer
+    interactions]). ]
+
+  Emacs provides built-in commands which are wrappers of standard Unix
+  tools: `M-x grep' lets the user input the flags of a `grep' call and
+  pass a regular expression to the `-e' flag.
+
+  The author of Denote uses this thin wrapper instead:
+
+  ┌────
+  │ (defvar prot-search--grep-hist '()
+  │   "Input history of grep searches.")
+  │ 
+  │ ;;;###autoload
+  │ (defun prot-search-grep (regexp &optional recursive)
+  │   "Run grep for REGEXP.
+  │ 
+  │ Search in the current directory using `lgrep'.  With optional
+  │ prefix argument (\\[universal-argument]) for RECURSIVE, run a
+  │ search starting from the current directory with `rgrep'."
+  │   (interactive
+  │    (list
+  │     (read-from-minibuffer (concat (if current-prefix-arg
+  │ 				      (propertize "Recursive" 'face 'warning)
+  │ 				    "Local")
+  │ 				  " grep for PATTERN: ")
+  │ 			  nil nil nil 'prot-search--grep-hist)
+  │     current-prefix-arg))
+  │   (unless grep-command
+  │     (grep-compute-defaults))
+  │   (if recursive
+  │       (rgrep regexp "*" default-directory)
+  │     (lgrep regexp "*" default-directory)))
+  └────
+
+  Rather than maintain custom code, consider using the excellent
+  `consult' package: it provides commands such as `consult-grep' and
+  `consult-find' which provide live results and are generally easier to
+  use than the built-in commands.
+
+
+[Use the `consult-denote' package for enhanced minibuffer interactions]
+See section 18.1
+
+
+19.9 Bookmark the directory with the notes
+──────────────────────────────────────────
+
+  Part of the reason Denote does not reinvent existing functionality is
+  to encourage you to learn more about Emacs.  You do not need a bespoke
+  “jump to my notes” directory because such commands do not scale well.
+  Will you have a “jump to my downloads” then another for multimedia and
+  so on?  No.
+
+  Emacs has a built-in framework for recording persistent markers to
+  locations.  Visit the `denote-directory' (or any dir/file for that
+  matter) and invoke the `bookmark-set' command (bound to `C-x r m' by
+  default).  It lets you create a bookmark.
+
+  The list of bookmarks can be reviewed with the `bookmark-bmenu-list'
+  command (bound to `C-x r l' by default).  A minibuffer interface is
+  available with `bookmark-jump' (`C-x r b').
+
+  If you use the `consult' package, its default `consult-buffer' command
+  has the means to group together buffers, recent files, and bookmarks.
+  Each of those types can be narrowed to with a prefix key.  The package
+  `consult-dir' is an extension to `consult' which provides useful
+  extras for working with directories, including bookmarks.
+
+
+19.10 Treat your notes as a project
+───────────────────────────────────
+
+  Emacs has a built-in library for treating a directory tree as a
+  “project”.  This means that the contents of this tree are seen as part
+  of the same set, so commands like `project-switch-to-buffer' (`C-x p
+  b' by default) will only consider buffers in the current project
+  (e.g. three notes that are currently being visited).
+
+  Normally, a “project” is a directory tree whose root is under version
+  control.  For our purposes, all you need is to navigate to the
+  `denote-directory' (for the shell or via Dired) and use the
+  command-line to run this (requires the `git' executable):
+
+  ┌────
+  │ git init
+  └────
+
+
+  From Dired, you can type `M-!' which invokes
+  `dired-smart-shell-command' and then run the git call there.
+
+  The project can then be registered by invoking any project-related
+  command inside of it, such as `project-find-file' (`C-x p f').
+
+  It is a good idea to keep your notes under version control, as that
+  gives you a history of changes for each file.  We shall not delve into
+  the technicalities here, though suffice to note that Emacs’ built-in
+  version control framework or the exceptionally well-crafted `magit'
+  package will get the job done (VC can work with other backends besides
+  Git).
+
+
+19.11 Use the tree-based file prompt for select commands
+────────────────────────────────────────────────────────
+
+  Older versions of Denote had a file prompt that resembled that of the
+  standard `find-file' command (bound to `C-x C-f' by default).  This
+  means that it used a tree-based method of navigating the filesystem by
+  selecting the specific directory and then the given file.
+
+  Currently, Denote flattens the file prompt so that every file in the
+  `denote-directory' and its subdirectories can be matched from anywhere
+  using the power of Emacs’ minibuffer completion (such as with the help
+  of the `orderless' package in addition to built-in options).
+
+  Users who need the old behaviour on a per-command basis can define
+  their own wrapper functions as shown in the following code block.
+
+  ┌────
+  │ ;; This is the old `denote-file-prompt' that we renamed to
+  │ ;; `denote-file-prompt-original' for clarity.
+  │ (defun denote-file-prompt-original (&optional initial-text)
+  │   "Prompt for file with identifier in variable `denote-directory'.
+  │ With optional INITIAL-TEXT, use it to prepopulate the minibuffer."
+  │   (read-file-name "Select note: " (denote-directory) nil nil initial-text
+  │ 		  (lambda (f)
+  │ 		    (or (denote-file-has-identifier-p f)
+  │ 			(file-directory-p f)))))
+  │ 
+  │ ;; Our wrapper command that changes the current `denote-file-prompt'
+  │ ;; to the functionality of `denote-file-prompt-original' only when
+  │ ;; this command is used.
+  │ (defun my-denote-link ()
+  │   "Call `denote-link' but use Denote's original file prompt.
+  │ See `denote-file-prompt-original'."
+  │   (interactive)
+  │   (cl-letf (((symbol-function 'denote-file-prompt) #'denote-file-prompt-original))
+  │     (call-interactively #'denote-link)))
+  └────
+
+
+19.12 Rename files with Denote in the Image Dired thumbnails buffer
+───────────────────────────────────────────────────────────────────
+
+  [Rename files with Denote using `dired-preview']
+
+  Just as with the `denote-dired-rename-marked-files-with-keywords', we
+  can use Denote in the Image Dired buffer ([Rename multiple files at
+  once]).  Here is the custom code:
+
+  ┌────
+  │ (autoload 'image-dired--with-marked "image-dired")
+  │ (autoload 'image-dired-original-file-name "image-dired-util")
+  │ 
+  │ (defun my-denote-image-dired-rename-marked-files (keywords)
+  │   "Like `denote-dired-rename-marked-files-with-keywords' but for Image Dired.
+  │ Prompt for KEYWORDS and rename all marked files in the Image
+  │ Dired buffer to have a Denote-style file name with the given
+  │ KEYWORDS.
+  │ 
+  │ IMPORTANT NOTE: if there are marked files in the corresponding
+  │ Dired buffers, those will be targeted as well.  This is not the
+  │ fault of Denote: it is how Dired and Image Dired work in tandem.
+  │ To only rename the marked thumbnails, start by unmarking
+  │ everything in Dired.  Then mark the items in Image Dired and
+  │ invoke this command."
+  │   (interactive (list (denote-keywords-prompt)) image-dired-thumbnail-mode)
+  │   (image-dired--with-marked
+  │    (when-let* ((file (image-dired-original-file-name))
+  │ 	       (dir (file-name-directory file))
+  │ 	       (id (or (denote-retrieve-filename-identifier file) ""))
+  │ 	       (file-type (denote-filetype-heuristics file))
+  │ 	       (title (denote--retrieve-title-or-filename file file-type))
+  │ 	       (signature (or (denote-retrieve-filename-signature file) "")
+  │ 	       (extension (file-name-extension file t))
+  │ 	       (new-name (denote-format-file-name dir id keywords title extension signature))
+  │ 	       (default-directory dir))
+  │      (denote-rename-file-and-buffer file new-name))))
+  └────
+
+  While the `my-denote-image-dired-rename-marked-files' renames files in
+  the helpful Denote-compliant way, users may still need to not prepend
+  a unique identifier and not sluggify (hyphenate and downcase) the
+  image’s existing file name.  To this end, the following custom command
+  can be used instead:
+
+  ┌────
+  │ (defun my-image-dired-rename-marked-files (keywords)
+  │   "Like `denote-dired-rename-marked-files-with-keywords' but for Image Dired.
+  │ Prompt for keywords and rename all marked files in the Image
+  │ Dired buffer to have Denote-style keywords, but none of the other
+  │ conventions of Denote's file-naming scheme."
+  │   (interactive (list (denote-keywords-prompt)) image-dired-thumbnail-mode)
+  │   (image-dired--with-marked
+  │    (when-let* ((file (image-dired-original-file-name))
+  │ 	       (dir (file-name-directory file))
+  │ 	       (file-type (denote-filetype-heuristics file))
+  │ 	       (title (denote--retrieve-title-or-filename file file-type))
+  │ 	       (extension (file-name-extension file t))
+  │ 	       (kws (denote--keywords-combine keywords))
+  │ 	       (new-name (concat dir title "__" kws extension))
+  │ 	       (default-directory dir))
+  │      (denote-rename-file-and-buffer file new-name))))
+  └────
+
+
+[Rename files with Denote using `dired-preview'] See section 19.13
+
+[Rename multiple files at once] See section 6.3
+
+
+19.13 Rename files with Denote using `dired-preview'
+────────────────────────────────────────────────────
+
+  The `dired-preview' package (by me/Protesilaos) automatically displays
+  a preview of the file at point in Dired.  This can be helpful in
+  tandem with Denote when we want to rename multiple files by taking a
+  quick look at their contents.
+
+  The command `denote-dired-rename-marked-files-with-keywords' will
+  generate Denote-style file names based on the keywords it prompts
+  for. Identifiers are derived from each file’s modification date
+  ([Rename multiple files at once]). There is no need for any custom
+  code in this scenario.
+
+  As noted in the section about Image Dired, the user may sometimes not
+  need a fully fledged Denote-style file name but only append
+  Denote-like keywords to each file name (e.g. `Original
+  Name__denote_test.jpg' instead of
+  `20230710T195843--original-name__denote_test.jpg').
+
+  [Rename files with Denote in the Image Dired thumbnails buffer]
+
+  In such a workflow, it is unlikely to be dealing with ordinary text
+  files where front matter can be helpful.  A custom command does not
+  need to behave like what Denote provides out-of-the-box, but can
+  instead append keywords to file names without conducting any further
+  actions.  We thus have:
+
+  ┌────
+  │ (defun my-denote-dired-rename-marked-files-keywords-only ()
+  │   "Like `denote-dired-rename-marked-files-with-keywords' but only for keywords in file names.
+  │ 
+  │ Prompt for keywords and rename all marked files in the Dired
+  │ buffer to only have Denote-style keywords, but none of the other
+  │ conventions of Denote's file-naming scheme."
+  │   (interactive nil dired-mode)
+  │   (if-let* ((marks (dired-get-marked-files)))
+  │       (let ((keywords (denote-keywords-prompt)))
+  │ 	(dolist (file marks)
+  │ 	  (let* ((dir (file-name-directory file))
+  │ 		 (file-type (denote-filetype-heuristics file))
+  │ 		 (title (denote--retrieve-title-or-filename file file-type))
+  │ 		 (extension (file-name-extension file t))
+  │ 		 (kws (denote--keywords-combine keywords))
+  │ 		 (new-name (concat dir title "__" kws extension)))
+  │ 	    (denote-rename-file-and-buffer file new-name)))
+  │ 	(revert-buffer))
+  │     (user-error "No marked files; aborting")))
+  └────
+
+
+[Rename multiple files at once] See section 6.3
+
+[Rename files with Denote in the Image Dired thumbnails buffer] See
+section 19.12
+
+
+19.14 Avoid duplicate identifiers when exporting Denote notes
+─────────────────────────────────────────────────────────────
+
+  When exporting Denote notes to, for example, an HTML or PDF file,
+  there is a high probability that the same file name is used with a new
+  extension.  This is problematic because it creates files with
+  duplicate identifiers.  The `20230515T085612--example__keyword.org'
+  produces a `20230515T085612--example__keyword.pdf'.  Any link to the
+  `20230515T085612' will thus break: it does not honor Denote’s
+  expectation of finding unique identifiers.  This is not the fault of
+  Denote: exporting is done by the user without Denote’s involvement.
+
+  Org Mode and Markdown use different approaches to exporting files.  No
+  recommended method is available for plain text files as there is no
+  standardised export functionality for this format (the user can always
+  create a new note using the file type they want on a case-by-case
+  basis: [Convenience commands for note creation]).
+
+
+[Convenience commands for note creation] See section 5.1.4
+
+19.14.1 Export Denote notes with Org Mode
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  Org Mode has a built-in configurable export engine.  You can prevent
+  duplicate identifiers when exporting manually for each exported file
+  or by advising the Org export function.
+
+  The `denote-org' package (by Protesilaos) also provides commands to
+  convert `denote:' links to their `file:' equivalent, in case this is a
+  required pre-processing step for export purposes.
+
+
+◊ 19.14.1.1 Manually configure Org export
+
+  Insert `#+export_file_name: FILENAME' in the front matter before
+  exporting to force a filename called whatever the value of `FILENAME'
+  is.  The `FILENAME' does not specify the file type extension, such as
+  `.pdf'.  This is up to the export engine.  For example, a Denote note
+  with a complete file name of `20230515T085612--example__keyword.org'
+  and a front matter entry of `#+export_file_name: hello' will be
+  exported as `hello.pdf'.
+
+  The advantage of this manual method is that it gives the user full
+  control over the resulting file name.  The disadvantage is that it
+  depends on the user’s behaviour.  Forgetting to add a new name can
+  lead to duplicate identifiers, as already noted in the introduction to
+  this section ([Export Denote notes]).
+
+
+  [Export Denote notes] See section 19.14
+
+
+◊ 19.14.1.2 Automatically store Org exports in another folder
+
+  It is possible to automatically place all exports in another folder by
+  making Org’s function `org-export-output-file-name' create the target
+  directory if needed and move the exported file there.  Remember that
+  advising Elisp code must be handled with care, as it might break the
+  original function in subtle ways.
+
+  ┌────
+  │ (defvar my-org-export-output-directory-prefix "./export_"
+  │   "Prefix of directory used for org-mode export.
+  │ 
+  │ The single dot means that the directory is created on the same
+  │ level as the one where the Org file that performs the exporting
+  │ is.  Use two dots to place the directory on a level above the
+  │ current one.
+  │ 
+  │ If this directory is part of `denote-directory', make sure it is
+  │ not read by Denote.  See `denote-excluded-directories-regexp'.
+  │ This way there will be no known duplicate Denote identifiers
+  │ produced by the Org export mechanism.")
+  │ 
+  │ (defun my-org-export-create-directory (fn extension &rest args)
+  │   "Move Org export file to its appropriate directory.
+  │ 
+  │ Append the file type EXTENSION of the exported file to
+  │ `my-org-export-output-directory-prefix' and, if absent, create a
+  │ directory named accordingly.
+  │ 
+  │ Install this as advice around `org-export-output-file-name'.  The
+  │ EXTENSION is supplied by that function.  ARGS are its remaining
+  │ arguments."
+  │   (let ((export-dir (format "%s%s" my-org-export-output-directory-prefix extension)))
+  │     (unless (file-directory-p export-dir)
+  │       (make-directory export-dir)))
+  │   (apply fn extension args))
+  │ 
+  │ (advice-add #'org-export-output-file-name :around #'my-org-export-create-directory)
+  └────
+
+  The target export directory should not be a subdirectory of
+  `denote-directory', as that will result in duplicate identifiers.
+  Exclude it with the `denote-excluded-directories-regexp' user option
+  ([Exclude certain directories from all operations]).
+
+  [ NOTE: I (Protesilaos) am not a LaTeX user and cannot test the
+    following. ]
+
+  Using a different directory will require some additional configuration
+  when exporting using LaTeX.  The export folder cannot be inside the
+  path of the `denote-directory' to prevent Denote from recognising it
+  as an attachment:
+  <https://emacs.stackexchange.com/questions/45751/org-export-to-different-directory>.
+
+
+  [Exclude certain directories from all operations] See section 5.9
+
+
+◊ 19.14.1.3 Org Mode Publishing
+
+  Org Mode also has a publishing tool for exporting a collection of
+  files. Some user might apply this approach to convert their note
+  collection to a public or private website.
+
+  The `org-publish-project-alist' variable drives the publishing
+  process, including the publishing directory.
+
+  The publishing directory should not be a subdirectory of
+  `denote-directory', as that will result in duplicate identifiers.
+  Exclude it with the `denote-excluded-directories-regexp' user option
+  ([Exclude certain directories from all operations]).
+
+
+  [Exclude certain directories from all operations] See section 5.9
+
+
+19.14.2 Export Denote notes with Markdown
+╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+
+  Exporting from Markdown requires an external processor (e.g.,
+  Markdown.pl, Pandoc, or MultiMarkdown).  The `markdown-command'
+  variable defines the command line used in export, for example:
+
+  ┌────
+  │ (setq markdown-command "multimarkdown")
+  └────
+
+  The export process thus occurs outside of Emacs.  Users need to read
+  the documentation of their preferred processor to prevent the creation
+  of duplicate Denote identifiers.
+
+
+19.15 Set up your workflow for daily or weekly meeting notes
+────────────────────────────────────────────────────────────
+
+  Perhaps as part of work, we meet with certain people on a regular
+  basis. During the meeting we may discuss a variety of topics. How best
+  to approach with the help of Denote?
+
+  One option is to write a new file for each meeting, giving it the
+  appropriate keywords each time ([Points of entry]). This is what
+  Denote does by default and does not need any further tweaks. If we
+  need to review those notes, we can use the command `denote-sort-dired'
+  ([Sort files by component]), or one of the Org dynamic blocks we
+  provide ([Use Org dynamic blocks]), among other options.
+
+  Another approach is to write one file per person with the regular
+  `denote' command (or related), give it the name of the person as a
+  title and, optionally, use some relevant keywords. Inside each file,
+  write a top-level heading with the date of the meeting, and then
+  produce the meeting notes below as paragraphs and subheadings. This
+  can all be done without any changes to Denote, though we can
+  streamline it by incorporating the following code in our setup.
+  Configure `my-denote-colleagues' and then use the command
+  `my-denote-colleagues-new-meeting' to see how it works.
+
+  ┌────
+  │ (defvar my-denote-colleagues '("Prot" "Protesilaos")
+  │   "List of names I collaborate with.
+  │ There is at least one file in the variable `denote-directory' that has
+  │ the name of this person.")
+  │ 
+  │ (defvar my-denote-colleagues-prompt-history nil
+  │   "Minibuffer history for `my-denote-colleagues-new-meeting'.")
+  │ 
+  │ (defun my-denote-colleagues-prompt ()
+  │   "Prompt with completion for a name among `my-denote-colleagues'.
+  │ Use the last input as the default value."
+  │   (let ((default-value (car my-denote-colleagues-prompt-history)))
+  │     (completing-read
+  │      (format-prompt "New meeting with COLLEAGUE" default-value)
+  │      my-denote-colleagues
+  │      nil :require-match nil
+  │      'my-denote-colleagues-prompt-history
+  │      default-value)))
+  │ 
+  │ (defun my-denote-colleagues-get-file (name)
+  │   "Find file in variable `denote-directory' for NAME colleague.
+  │ If there are more than one files, prompt with completion for one among
+  │ them.
+  │ 
+  │ NAME is one among `my-denote-colleagues'."
+  │   (if-let* ((files (denote-directory-files name))
+  │ 	    (length-of-files (length files)))
+  │       (cond
+  │        ((= length-of-files 1)
+  │ 	(car files))
+  │        ((> length-of-files 1)
+  │ 	(completing-read "Select a file: " files nil :require-match)))
+  │     (user-error "No files for colleague with name `%s'" name)))
+  │ 
+  │ (defun my-denote-colleagues-new-meeting ()
+  │   "Prompt for the name of a colleague and insert a timestamped heading therein.
+  │ The name of a colleague corresponds to at least one file in the variable
+  │ `denote-directory'.  In case there are multiple files, prompt to choose
+  │ one among them and operate therein."
+  │   (declare (interactive-only t))
+  │   (interactive)
+  │   (let* ((name (my-denote-colleagues-prompt))
+  │ 	 (file (my-denote-colleagues-get-file name))
+  │ 	 (time (format-time-string "%F %a %R")))  ; remove %R if you do not want the time
+  │     (with-current-buffer (find-file file)
+  │       (goto-char (point-max))
+  │       ;; Here I am assuming we are in `org-mode', hence the leading
+  │       ;; asterisk for the heading.  Adapt accordingly.
+  │       (insert (format "* [%s]\n\n" time)))))
+  └────
+
+
+[Points of entry] See section 5
+
+[Sort files by component] See section 14
+
+[Use Org dynamic blocks] See section 13
+
+
+20 For developers or advanced users
+═══════════════════════════════════
+
+  Denote is in a stable state and can be relied upon as the basis for
+  custom extensions ([Packages that build on Denote]). Further below is
+  a list with the functions or variables we provide for public usage.
+  Those are in addition to all user options and commands that are
+  already documented in the various sections of this manual.
+
+  In this context “public” is any form with single hyphens in its
+  symbol, such as `denote-directory-files'.  We expressly support those,
+  meaning that we consider them reliable and commit to documenting any
+  changes in their particularities (such as through `make-obsolete', a
+  record in the change log, a blog post on the maintainer’s website, and
+  the like).
+
+  By contradistinction, a “private” form is declared with two hyphens in
+  its symbol such as `denote--file-extension'.  Do not use those as we
+  might change them without further notice.
+
+  The following sections cover the specifics.
+
+
+[Packages that build on Denote] See section 18
+
+20.1 Common building blocks for developers or advanced users
+────────────────────────────────────────────────────────────
+
+  Variable `denote-id-format'
+        Format of ID prefix of a note’s filename.  The note’s ID is
+        derived from the date and time of its creation ([The file-naming
+        scheme]).
+
+  Variable `denote-id-regexp'
+        Regular expression to match `denote-id-format'.
+
+  Variable `denote-signature-regexp'
+        Regular expression to match the `SIGNATURE' field in a file
+        name.
+
+  Variable `denote-title-regexp'
+        Regular expression to match the `TITLE' field in a file name
+        ([The file-naming scheme]).
+
+  Variable `denote-keywords-regexp'
+        Regular expression to match the `KEYWORDS' field in a file name
+        ([The file-naming scheme]).
+
+  Function `denote-identifier-p'
+        Return non-nil if `IDENTIFIER' string is a Denote identifier.
+
+  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'.
+
+  Function `denote-file-has-identifier-p'
+        Return non-nil if `FILE' has a Denote identifier.
+
+  Function `denote-file-has-denoted-filename-p'
+        Return non-nil if `FILE' respects the file-naming scheme of
+        Denote. This tests the rules of Denote’s file-naming
+        scheme. Sluggification is ignored. It is done by removing all
+        file name components and validating what remains.
+
+  Function `denote-file-has-signature-p'
+        Return non-nil if `FILE' has a signature.
+
+  Function `denote-file-has-supported-extension-p'
+        Return non-nil if `FILE' has supported extension.  Also account
+        for the possibility of an added `.gpg' suffix. Supported
+        extensions are those implied by `denote-file-type'.
+
+  Function `denote-file-is-writable-and-supported-p'
+        Return non-nil if `FILE' is writable and has supported
+        extension.
+
+  Function `denote-file-type-extensions'
+        Return all file type extensions in `denote-file-types'.
+
+  Variable `denote-encryption-file-extensions'
+        List of strings specifying file extensions for encryption.
+
+  Function `denote-file-type-extensions-with-encryption'
+        Derive `denote-file-type-extensions' plus
+        `denote-encryption-file-extensions'.
+
+  Function `denote-get-file-extension'
+        Return extension of `FILE' with dot included.  Account for
+        `denote-encryption-file-extensions'.  In other words, return
+        something like `.org.gpg' if it is part of the file, else return
+        `.org'.
+
+  Function `denote-get-file-extension-sans-encryption'
+        Return extension of `FILE' with dot included and without the
+        encryption part.  Build on top of `denote-get-file-extension'
+        though always return something like `.org' even if the actual
+        file extension is `.org.gpg'.
+
+  Functions `denote-infer-keywords-from-files'
+        Return list of keywords in `denote-directory-files'. With
+        optional `FILES-MATCHING-REGEXP', only extract keywords from the
+        matching files. Otherwise, do it for all files. Keep any
+        duplicates. Users who do not want duplicates should refer to the
+        functions `denote-keywords'.
+
+  Function `denote-keywords'
+        Return appropriate list of keyword candidates. If
+        `denote-infer-keywords' is non-nil, infer keywords from existing
+        notes and combine them into a list with
+        `denote-known-keywords'. Else use only the latter set of
+        keywords ([Standard note creation]). In the case of keyword
+        inferrence, use optional `FILES-MATCHING-REGEXP', to extract
+        keywords only from the matching files. Otherwise, do it for all
+        files. Filter inferred keywords with the user option
+        `denote-excluded-keywords-regexp'.
+
+  Function `denote-keywords-sort'
+        Sort `KEYWORDS' if `denote-sort-keywords' is non-nil.
+        `KEYWORDS' is a list of strings, per `denote-keywords-prompt'.
+
+  Function `denote-keywords-combine'
+        Combine `KEYWORDS' list of strings into a single
+        string. Keywords are separated by the underscore character, per
+        the Denote file-naming scheme.
+
+  Function `denote-valid-date-p'
+        Return `DATE' as a valid date. A valid `DATE' is a value that
+        can be parsed by either `decode-time' or `date-to-time' .Those
+        functions signal an error if `DATE' is a value they do not
+        recognise. If `DATE' is nil, return nil.
+
+  Function `denote-directory'
+        Return path of the variable `denote-directory' as a proper
+        directory, also because it accepts a directory-local value for
+        what we internally refer to as “silos” ([Maintain separate
+        directories for notes]).  Custom Lisp code can `let' bind the
+        value of the variable `denote-directory' to override what this
+        function returns.
+
+  Function `denote-directory-files'
+        Return list of absolute file paths in variable
+        `denote-directory'. Files that match
+        `denote-excluded-files-regexp' are excluded from the list. Files
+        only need to have an identifier. The return value may thus
+        include file types that are not implied by
+        `denote-file-type'. With optional `FILES-MATCHING-REGEXP',
+        restrict files to those matching the given regular
+        expression. With optional `OMIT-CURRENT' as a non-nil value, do
+        not include the current Denote file in the returned list. With
+        optional `TEXT-ONLY' as a non-nil value, limit the results to
+        text files that satisfy `denote-file-is-note-p'. With optional
+        `EXCLUDE-REGEXP' exclude the files that match the given regular
+        expression. This is done after `FILES-MATCHING-REGEXP' and
+        `OMIT-CURRENT' have been applied.
+
+  Function `denote-directory-subdirectories'
+        Return list of subdirectories in variable
+        `denote-directory'. Omit dotfiles (such as .git)
+        unconditionally.  Also exclude whatever matches
+        `denote-excluded-directories-regexp'.  Note that the
+        `denote-directory' accepts a directory-local value for what we
+        call “silos” ([Maintain separate directories for notes]).
+
+
+[The file-naming scheme] See section 7
+
+[Standard note creation] See section 5.1
+
+[Maintain separate directories for notes] See section 5.7
+
+
+20.2 File path interface for developers or advanced users
+─────────────────────────────────────────────────────────
+
+  Function `denote-file-name-relative-to-denote-directory'
+        Return name of `FILE' relative to the variable
+        `denote-directory'.  `FILE' must be an absolute path.
+
+  Function `denote-slug-keep-only-ascii'
+        Remove all non-ASCII characters from `STR' and replace them with
+        spaces. This is useful as a helper function to construct
+        `denote-file-name-slug-functions' ([Custom sluggification to
+        remove non-ASCII characters]).
+
+  Function `denote-sluggify'
+        Make `STR' an appropriate slug for file name `COMPONENT'
+        ([Sluggification of file name components]).  Apply the function
+        specified in `denote-file-name-slug-function' to `COMPONENT'
+        which is one of `title', `signature', `keyword'. If the
+        resulting string still contains consecutive `-',=_= or `=', they
+        are replaced by a single occurence of the character, if
+        necessary according to `COMPONENT'. If `COMPONENT' is `keyword',
+        remove underscores from `STR' as they are used as the keywords
+        separator in file names.
+
+  Function `denote-sluggify-keyword'
+        Sluggify `STR' while joining separate words.
+
+  Function `denote-sluggify-signature'
+        Make `STR' an appropriate slug for signatures ([Sluggification
+        of file name components]).
+
+  Function `denote-sluggify-keywords'
+        Sluggify `KEYWORDS', which is a list of strings ([Sluggification
+        of file name components]).
+
+  Function `denote-use-date'
+        The date to be used in a note creation command. See the
+        documentation of `denote' for acceptable values.  This variable
+        is ignored if nil. Only ever `let' bind this, otherwise the
+        title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-use-directory'
+        The directory to be used in a note creation command. See the
+        documentation of `denote' for acceptable values. This variable
+        is ignored if nil. Only ever `let' bind this, otherwise the
+        title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-use-file-type'
+        The file type to be used in a note creation command. See the
+        documentation of `denote' for acceptable values. This variable
+        is ignored if nil. Only ever `let' bind this, otherwise the
+        title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-use-keywords'
+        The keywords to be used in a note creation command. See the
+        documentation of `denote' for acceptable values. This variable
+        is ignored if `default'. Only ever `let' bind this, otherwise
+        the title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-use-signature'
+        The signature to be used in a note creation command. See the
+        documentation of `denote' for acceptable values. This variable
+        is ignored if nil. Only ever `let' bind this, otherwise the
+        title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-use-template'
+        The template to be used in a note creation command. See the
+        documentation of `denote' for acceptable values. This variable
+        is ignored if nil. Only ever `let' bind this, otherwise the
+        title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-use-title'
+        The title to be used in a note creation command. See the
+        documentation of `denote' for acceptable values. This variable
+        is ignored if nil. Only ever `let' bind this, otherwise the
+        title will always be the same and the title prompt will be
+        skipped.
+
+  Function `denote-format-file-name'
+        Format file name. `DIR-PATH', `ID', `KEYWORDS', `TITLE',
+        `EXTENSION' and `SIGNATURE' are expected to be supplied by
+        `denote' or equivalent command.
+
+        `DIR-PATH' is a string pointing to a directory. It ends with a
+        forward slash (the function `denote-directory' makes sure this
+        is the case when returning the value of the variable
+        `denote-directory').  `DIR-PATH' cannot be nil or an empty
+        string.
+
+        `ID' is a string holding the identifier of the note. It can be
+        an empty string, in which case its respective file name
+        component is not added to the base file name.
+
+        `DIR-PATH' and `ID' form the base file name.
+
+        `KEYWORDS' is a list of strings that is reduced to a single
+        string by `denote-keywords-combine'. `KEYWORDS' can be an empty
+        list or a nil value, in which case the relevant file name
+        component is not added to the base file name.
+
+        `TITLE' and `SIGNATURE' are strings. They can be an empty
+        string, in which case their respective file name component is
+        not added to the base file name.
+
+        `EXTENSION' is a string that contains a dot followed by the file
+        type extension. It can be an empty string or a nil value, in
+        which case it is not added to the base file name.
+
+
+[Custom sluggification to remove non-ASCII characters] See section 7.3.1
+
+[Sluggification of file name components] See section 7.2
+
+
+20.3 Data retrieval interface for developers or advanced users
+──────────────────────────────────────────────────────────────
+
+  Function `denote-get-path-by-id'
+        Return absolute path of `ID' string in `denote-directory-files'.
+
+  Function `denote-get-identifier-at-point'
+        Return the identifier at point or `POINT'.
+
+  Function `denote-extract-keywords-from-path'
+        Extract keywords from `PATH' and return them as a list of
+        strings.  `PATH' must be a Denote-style file name where keywords
+        are prefixed with an underscore.  If `PATH' has no such
+        keywords, which is possible, return nil ([The file-naming
+        scheme]).
+
+  Function `denote-extract-id-from-string'
+        Return existing Denote identifier in `STRING', else nil.
+
+  Function `denote-retrieve-filename-identifier'
+        Extract identifier from `FILE' name, if present, else return
+        nil. To create a new one from a date, refer to the
+        `denote-get-identifier' function.
+
+  Function `denote-retrieve-filename-title'
+        Extract Denote title component from `FILE' name, if present,
+        else return nil.
+
+  Function `denote-retrieve-filename-keywords'
+        Extract keywords from `FILE' name, if present, else return
+        nil. Return matched keywords as a single string.
+
+  Function `denote-retrieve-filename-signature'
+        Extract signature from `FILE' name, if present, else return nil.
+
+  Function `denote-retrieve-title-or-filename'
+        Return appropriate title for `FILE' given its `TYPE'. This is a
+        wrapper for `denote-retrieve-front-matter-title-value' and
+        `denote-retrieve-filename-title'.
+
+  Function `denote-get-identifier'
+        Convert `DATE' into a Denote identifier using
+        `denote-id-format'. If `DATE' is nil, return an empty string as
+        the identifier.
+
+  Function `denote-retrieve-front-matter-title-value'
+        Return title value from `FILE' front matter per `FILE-TYPE'.
+
+  Function `denote-retrieve-front-matter-title-line'
+        Return title line from `FILE' front matter per `FILE-TYPE'.
+
+  Function `denote-retrieve-front-matter-keywords-value'
+        Return keywords value from `FILE' front matter per
+        `FILE-TYPE'. The return value is a list of strings.
+
+  Function `denote-retrieve-front-matter-keywords-line'
+        Return keywords line from `FILE' front matter per `FILE-TYPE'.
+
+
+[The file-naming scheme] See section 7
+
+
+20.4 Prompt interface for developers or advanced users
+──────────────────────────────────────────────────────
+
+  Function `denote-add-prompts'
+        Add list of `ADDITIONAL-PROMPTS' to `denote-prompts'. This is
+        best done inside of a `let' to create a wrapper function around
+        `denote', `denote-rename-file', and generally any command that
+        consults the value of `denote-prompts'.
+
+  Function `denote-signature-prompt'
+        Prompt for signature string.  With optional `INITIAL-SIGNATURE'
+        use it as the initial minibuffer text. With optional
+        `PROMPT-TEXT' use it in the minibuffer instead of the default
+        prompt. Previous inputs at this prompt are available for
+        minibuffer completion if the user option
+        `denote-history-completion-in-prompts' is set to a non-nil value
+        ([The `denote-history-completion-in-prompts' option]).
+
+  Function `denote-file-prompt'
+        Prompt for file in variable `denote-directory'. Files that match
+        `denote-excluded-files-regexp' are excluded from the list. With
+        optional `FILES-MATCHING-REGEXP', filter the candidates per the
+        given regular expression. With optional `PROMPT-TEXT', use it
+        instead of the default call to select a file. With optional
+        `NO-REQUIRE-MATCH' accept the given input as-is. Return the
+        absolute path to the matching file.
+
+  Function `denote-keywords-prompt'
+        Prompt for one or more keywords.  Read entries as separate when
+        they are demarcated by the `crm-separator', which typically is a
+        comma. With optional `PROMPT-TEXT', use it to prompt the user
+        for keywords. Else use a generic prompt. With optional
+        `INITIAL-KEYWORDS' use them as the initial minibuffer text.
+
+  Function `denote-title-prompt'
+        Prompt for title string. With optional `INITIAL-TITLE' use it as
+        the initial minibuffer text. With optional `PROMPT-TEXT' use it
+        in the minibuffer instead of the default prompt. Previous inputs
+        at this prompt are available for minibuffer completion if the
+        user option `denote-history-completion-in-prompts' is set to a
+        non-nil value ([The `denote-history-completion-in-prompts'
+        option]).
+
+  Variable `denote-title-prompt-current-default'
+        Currently bound default title for `denote-title-prompt'.  Set
+        the value of this variable within the lexical scope of a command
+        that needs to supply a default title before calling
+        `denote-title-prompt' and use `unwind-protect' to set its value
+        back to nil.
+
+  Function `denote-file-type-prompt'
+        Prompt for `denote-file-type'.  Note that a non-nil value other
+        than `text', `markdown-yaml', and `markdown-toml' falls back to
+        an Org file type.  We use `org' here for clarity.
+
+  Function `denote-date-prompt'
+        Prompt for date, expecting `YYYY-MM-DD' or that plus `HH:MM' (or
+        even `HH:MM:SS'). Use Org’s more advanced date selection utility
+        if the user option `denote-date-prompt-use-org-read-date' is
+        non-nil. It requires Org ([The
+        denote-date-prompt-use-org-read-date option]). With optional
+        `INITIAL-DATE' use it as the initial minibuffer text. With
+        optional `PROMPT-TEXT' use it in the minibuffer instead of the
+        default prompt. `INITIAL-DATE' is a string that can be processed
+        by `denote-valid-date-p', a value that can be parsed by
+        `decode-time' or nil.
+
+  Function `denote-command-prompt'
+        Prompt for command among `denote-commands-for-new-notes'
+        ([Points of entry]).
+
+  Variable `denote-prompts-with-history-as-completion'
+        Prompts that conditionally perform completion against their
+        history. These are minibuffer prompts that ordinarily accept a
+        free form string input, as opposed to matching against a
+        predefined set. These prompts can optionally perform completion
+        against their own minibuffer history when the user option
+        `denote-history-completion-in-prompts' is set to a non-nil value
+        ([The `denote-history-completion-in-prompts' option]).
+
+  Function `denote-files-matching-regexp-prompt'
+        Prompt for `REGEXP' to filter Denote files by. With optional
+        `PROMPT-TEXT' use it instead of a generic prompt.
+
+  Function `denote-prompt-for-date-return-id'
+        Use `denote-date-prompt' and return it as `denote-id-format'.
+
+  Function `denote-template-prompt'
+        Prompt for template key in `denote-templates' and return its
+        value.
+
+  Function `denote-subdirectory-prompt'
+        Prompt for subdirectory of the variable `denote-directory'.  The
+        table uses the `file' completion category (so it works with
+        packages such as `marginalia' and `embark').
+
+
+[The `denote-history-completion-in-prompts' option] See section 5.1.2
+
+[The denote-date-prompt-use-org-read-date option] See section 5.1.7
+
+[Points of entry] See section 5
+
+
+20.5 Front matter interface for developers or advanced users
+────────────────────────────────────────────────────────────
+
+  Function `denote-filetype-heuristics'
+        Return likely file type of `FILE'. If in the process of
+        `org-capture', consider the file type to be that of
+        Org. Otherwise, use the file extension to detect the file type
+        of `FILE'.
+
+        If more than one file type correspond to this file extension,
+        use the first file type for which the :title-key-regexp in
+        `denote-file-types' matches in the file.
+
+        Return nil if the file type is not recognized.
+
+  Variable `denote-org-front-matter'
+        Specifies the Org front matter.  It is passed to `format' with
+        arguments `TITLE', `DATE', `KEYWORDS', `ID' ([Change the front
+        matter format])
+
+  Variable `denote-yaml-front-matter'
+        Specifies the YAML (Markdown) front matter.  It is passed to
+        `format' with arguments `TITLE', `DATE', `KEYWORDS', `ID'
+        ([Change the front matter format])
+
+  Variable `denote-toml-front-matter'
+        Specifies the TOML (Markdown) front matter.  It is passed to
+        `format' with arguments `TITLE', `DATE', `KEYWORDS', `ID'
+        ([Change the front matter format])
+
+  Variable `denote-text-front-matter'
+        Specifies the plain text front matter.  It is passed to `format'
+        with arguments `TITLE', `DATE', `KEYWORDS', `ID' ([Change the
+        front matter format])
+
+  Function `denote-date-org-timestamp'
+        Format `DATE' using the Org inactive timestamp notation.
+
+  Function `denote-date-rfc3339'
+        Format `DATE' using the RFC3339 specification.
+
+  Function `denote-date-iso-8601'
+        Format `DATE' according to ISO 8601 standard.
+
+  Function `denote-trim-whitespace'
+        Trim whitespace around string `S'.  This can be used in
+        `denote-file-types' to format front mattter.
+
+  Function `denote-trim-whitespace-then-quotes'
+        Trim whitespace then quotes around string `S'.  This can be used
+        in `denote-file-types' to format front mattter.
+
+  Function `denote-format-string-for-org-front-matter'
+        Return string `S' as-is for Org or plain text front matter. If
+        `S' is not a string, return an empty string.
+
+  Function `denote-format-string-for-md-front-matter'
+        Surround string `S' with quotes. If `S' is not a string, return
+        a literal emptry string. This can be used in `denote-file-types'
+        to format front mattter.
+
+  Function `denote-format-keywords-for-md-front-matter'
+        Format front matter `KEYWORDS' for markdown file type.
+        `KEYWORDS' is a list of strings.  Consult the
+        `denote-file-types' for how this is used.
+
+  Function `denote-format-keywords-for-text-front-matter'
+        Format front matter `KEYWORDS' for text file type.  `KEYWORDS'
+        is a list of strings.  Consult the `denote-file-types' for how
+        this is used.
+
+  Function `denote-format-keywords-for-org-front-matter'
+        Format front matter `KEYWORDS' for org file type.  `KEYWORDS' is
+        a list of strings.  Consult the `denote-file-types' for how this
+        is used.
+
+  Function `denote-extract-keywords-from-front-matter'
+        Format front matter `KEYWORDS' for org file type.  `KEYWORDS' is
+        a list of strings.  Consult the `denote-file-types' for how this
+        is used.
+
+  Variable `denote-file-types'
+        Alist of `denote-file-type' and their format properties.
+
+        Each element is of the form `(SYMBOL PROPERTY-LIST)'.  `SYMBOL'
+        is one of those specified in `denote-file-type' or an arbitrary
+        symbol that defines a new file type.
+
+        `PROPERTY-LIST' is a plist that consists of the following
+        elements:
+
+        1. `:extension' is a string with the file extension including
+           the period.
+
+        2. `:date-function' is a function that can format a date.  See
+           the functions `denote--date-iso-8601',
+           `denote--date-rfc3339', and `denote--date-org-timestamp'.
+
+        3. `:front-matter' is either a string passed to `format' or a
+           variable holding such a string.  The `format' function
+           accepts four arguments, which come from `denote' in this
+           order: `TITLE', `DATE', `KEYWORDS', `IDENTIFIER'.  Read the
+           doc string of `format' on how to reorder arguments.
+
+        4. `:title-key-regexp' is a regular expression that is used to
+           retrieve the title line in a file.  The first line matching
+           this regexp is considered the title line.
+
+        5. `:title-value-function' is the function used to format the
+           raw title string for inclusion in the front matter (e.g. to
+           surround it with quotes).  Use the `identity' function if no
+           further processing is required.
+
+        6. `:title-value-reverse-function' is the function used to
+           retrieve the raw title string from the front matter.  It
+           performs the reverse of `:title-value-function'.
+
+        7. `:keywords-key-regexp' is a regular expression used to
+           retrieve the keywords’ line in the file.  The first line
+           matching this regexp is considered the keywords’ line.
+
+        8. `:keywords-value-function' is the function used to format the
+           keywords’ list of strings as a single string, with
+           appropriate delimiters, for inclusion in the front matter.
+
+        9. `:keywords-value-reverse-function' is the function used to
+           retrieve the keywords’ value from the front matter.  It
+           performs the reverse of the `:keywords-value-function'.
+
+        10. `:link' is a string, or variable holding a string, that
+            specifies the format of a link.  See the variables
+            `denote-org-link-format', `denote-md-link-format'.
+
+        11. `:link-in-context-regexp' is a regular expression that is
+            used to match the aforementioned link format.  See the
+            variables `denote-org-link-in-context-regexp',
+            `denote-md-link-in-context-regexp'.
+
+        If `denote-file-type' is nil, use the first element of this list
+        for new note creation.  The default is `org'.
+
+
+[Change the front matter format] See section 8.1
+
+
+20.6 Link interface for developers or advanced users
+────────────────────────────────────────────────────
+
+  Variable `denote-org-link-format'
+        Format of Org link to note.  The value is passed to `format'
+        with `IDENTIFIER' and `TITLE' arguments, in this order.  Also
+        see `denote-org-link-in-context-regexp'.
+
+  Variable `denote-md-link-format'
+        Format of Markdown link to note.  The `%N$s' notation used in
+        the default value is for `format' as the supplied arguments are
+        `IDENTIFIER' and `TITLE', in this order.  Also see
+        `denote-md-link-in-context-regexp'.
+
+  Variable `denote-id-only-link-format'
+        Format of identifier-only link to note.  The value is passed to
+        `format' with `IDENTIFIER' as its sole argument.  Also see
+        `denote-id-only-link-in-context-regexp'.
+
+  Variable `denote-org-link-in-context-regexp'
+        Regexp to match an Org link in its context.  The format of such
+        links is `denote-org-link-format'.
+
+  Variable `denote-md-link-in-context-regexp'
+        Regexp to match an Markdown link in its context.  The format of
+        such links is `denote-md-link-format'.
+
+  Variable `denote-id-only-link-in-context-regexp'
+        Regexp to match an identifier-only link in its context.  The
+        format of such links is `denote-id-only-link-format'.
+
+  Function `denote-select-linked-file-prompt'
+        Prompt for linked file among `FILES'.
+
+  Function `denote-link-return-links'
+        Return list of links in current or optional `FILE'.  Also see
+        `denote-link-return-backlinks'.
+
+  Function `denote-link-return-backlinks'
+        Return list of backlinks in current or optional `FILE'.  Also
+        see `denote-link-return-links'.
+
+  Function `denote-link-description-with-signature-and-title'
+        Return link description for `FILE'.  Produce a description as
+        follows:
+
+        • If the region is active, use it as the description.
+
+        • If `FILE' as a signature, then use the
+          `denote-link-signature-format'.  By default, this looks like
+          “signature title”.
+
+        • If `FILE' does not have a signature, then use its title as the
+          description.
+
+  Variable `denote-link-description-function'
+        Function to use to create the description of links. The function
+        specified should take a `FILE' argument and should return the
+        description as a string. By default, the title of the file is
+        returned as the description.
+
+
+20.7 Xref interface for developers or advanced users
+────────────────────────────────────────────────────
+
+  Function `denote-retrieve-groups-xref-query'
+        Access location of xrefs for `QUERY' and group them per
+        file. Limit the search to text files.
+
+  Function `denote-retrieve-files-xref-query'
+        Return sorted, deduplicated file names with matches for `QUERY'
+        in their contents.  Limit the search to text files.
+
+  Function `denote-retrieve-xref-alist'
+        Return xref alist of files with location of matches for
+        `QUERY'. With optional `FILES-MATCHING-REGEXP', limit the list
+        of files accordingly (per `denote-directory-files'). At all
+        times limit the search to text files.
+
+
+20.8 Renaming files interface for developers or advanced users
+──────────────────────────────────────────────────────────────
+
+  Function `denote-rename-file-prompt'
+        Prompt to rename file named `OLD-NAME' to `NEW-NAME'. If
+        `denote-rename-confirmations' does not contain
+        `modify-file-name', return t without prompting.
+
+  Function `denote-rename-file-and-buffer'
+        Rename file named `OLD-NAME' to `NEW-NAME', updating buffer
+        name.
+
+  Function `denote-prepend-front-matter'
+        Prepend front matter to `FILE'. The `TITLE', `KEYWORDS', `DATE',
+        `ID', `SIGNATURE', and `FILE-TYPE' are passed from the renaming
+        command and are used to construct a new front matter block if
+        appropriate.
+
+  Function `denote-rewrite-front-matter'
+        Rewrite front matter of note after `denote-rename-file' (or
+        related). The `FILE', `TITLE', `KEYWORDS', `SIGNATURE', `DATE',
+        `IDENTIFIER', and `FILE-TYPE' arguments are given by the
+        renaming command and are used to construct new front matter
+        values if appropriate. If `denote-rename-confirmations' contains
+        `rewrite-front-matter', prompt to confirm the rewriting of the
+        front matter. Otherwise produce a `y-or-n-p' prompt to that
+        effect.
+
+  Function `denote-add-front-matter-prompt'
+        Prompt to add a front-matter to `FILE'. Return non-nil if a new
+        front matter should be added. If `denote-rename-confirmations'
+        does not contain `add-front-matter', return t without prompting.
+
+  Function `denote-rewrite-keywords'
+        Rewrite `KEYWORDS' in `FILE' outright according to
+        `FILE-TYPE'. Do the same as `denote-rewrite-front-matter' for
+        keywords, but do not ask for confirmation. With optional
+        `SAVE-BUFFER', save the buffer corresponding to `FILE'. This
+        function is for use in the commands `denote-keywords-add',
+        `denote-keywords-remove', `denote-dired-rename-files', or
+        related.
+
+  Function `denote-update-dired-buffers'
+        Update Dired buffers of variable `denote-directory'. Also revert
+        the current Dired buffer even if it is not inside the
+        `denote-directory'. Note that the `denote-directory' accepts a
+        directory-local value for what we internally refer to as “silos”
+        ([Maintain separate directories for notes]).
+
+
+[Maintain separate directories for notes] See section 5.7
+
+
+21 Troubleshoot Denote in a pristine environment
+════════════════════════════════════════════════
+
+  Sometimes we get reports on bugs that may not be actually caused by
+  some error in the Denote code base.  To help gain insight into what
+  the problem is, we need to be able to reproduce the issue in a minimum
+  viable system.  Below is one way to achieve this.
+
+  1. Find where your `denote.el' file is stored on your filesystem.
+
+  2. Assuming you have already installed the package, one way to do this
+     is to invoke `M-x find-library' and search for `denote'.  It will
+     take you to the source file.  There do `M-x eval-expression', which
+     will bring up a minibuffer prompt.  At the prompt evaluate:
+
+  ┌────
+  │ (kill-new (expand-file-name (buffer-file-name)))
+  └────
+
+  1. The above will save the full file system path to your kill ring.
+
+  2. In a terminal emulator or an `M-x shell' buffer execute:
+
+  ┌────
+  │ emacs -Q
+  └────
+
+  1. This will open a new instance of Emacs in a pristine environment.
+     Only the default settings are loaded.
+
+  2. In the `*scratch*' buffer of `emacs -Q', add your configurations
+     like the following and try to reproduce the issue:
+
+  ┌────
+  │ (require 'denote "/full/path/to/what/you/got/denote.el")
+  │ 
+  │ ;; Your configurations here
+  └────
+
+  Then try to see if your problem still occurs.  If it does, then the
+  fault is with Denote.  Otherwise there is something external to it
+  that we need to account for.  Whatever the case, this exercise helps
+  us get a better sense of the specifics.
+
+
+22 Contributing
+═══════════════
+
+  Denote is a GNU ELPA package. As such, any significant change to the
+  code requires copyright assignment to the Free Software Foundation
+  (more below).
+
+  You do not need to be a programmer to contribute to this package.
+  Sharing an idea or describing a workflow is equally helpful, as it
+  teaches us something we may not know and might be able to cover either
+  by extending Denote or expanding this manual. If you prefer to write a
+  blog post, make sure you share it with us: we can add a section herein
+  referencing all such articles. Everyone gets acknowledged
+  ([Acknowledgements]). There is no such thing as an “insignificant
+  contribution”—they all matter.
+
+  ⁃ Package name (GNU ELPA): `denote'
+  ⁃ Official manual: <https://protesilaos.com/emacs/denote>
+  ⁃ Change log: <https://protesilaos.com/emacs/denote-changelog>
+  ⁃ Git repositories:
+    ⁃ GitHub: <https://github.com/protesilaos/denote>
+    ⁃ GitLab: <https://gitlab.com/protesilaos/denote>
+
+  If our public media are not suitable, you are welcome to contact me
+  (Protesilaos) in private: <https://protesilaos.com/contact>.
+
+  Copyright assignment is a prerequisite to sharing code. It is a simple
+  process. Check the request form below (please adapt it accordingly).
+  You must write an email to the address mentioned in the form and then
+  wait for the FSF to send you a legal agreement. Sign the document and
+  file it back to them. This could all happen via email and take about a
+  week. You are encouraged to go through this process. You only need to
+  do it once. It will allow you to make contributions to Emacs in
+  general.
+
+  ┌────
+  │ Please email the following information to assign@gnu.org, and we
+  │ will send you the assignment form for your past and future changes.
+  │ 
+  │ Please use your full legal name (in ASCII characters) as the subject
+  │ line of the message.
+  │ 
+  │ REQUEST: SEND FORM FOR PAST AND FUTURE CHANGES
+  │ 
+  │ [What is the name of the program or package you're contributing to?]
+  │ 
+  │ GNU Emacs
+  │ 
+  │ [Did you copy any files or text written by someone else in these changes?
+  │ Even if that material is free software, we need to know about it.]
+  │ 
+  │ Copied a few snippets from the same files I edited.  Their author,
+  │ Protesilaos Stavrou, has already assigned copyright to the Free Software
+  │ Foundation.
+  │ 
+  │ [Do you have an employer who might have a basis to claim to own
+  │ your changes?  Do you attend a school which might make such a claim?]
+  │ 
+  │ 
+  │ [For the copyright registration, what country are you a citizen of?]
+  │ 
+  │ 
+  │ [What year were you born?]
+  │ 
+  │ 
+  │ [Please write your email address here.]
+  │ 
+  │ 
+  │ [Please write your postal address here.]
+  │ 
+  │ 
+  │ 
+  │ 
+  │ 
+  │ [Which files have you changed so far, and which new files have you written
+  │ so far?]
+  │ 
+  └────
+
+
+[Acknowledgements] See section 26
+
+22.1 Wishlist of what we can do to extend Denote
+────────────────────────────────────────────────
+
+  These are various ideas to extend Denote. Whether they should be in
+  the core package or a separate extension is something we can discuss.
+  I, Protesilaos, am happy to help anyone who wants to do any of this.
+
+  denote-embark.el
+        Provide integration with the `embark' package.  This can be for
+        doing something with the identifier/link at point.  For example,
+        it could provide an action to produce backlinks for the
+        identifier/file we are linking to, not just the current one.
+
+  denote-transient.el
+        The `transient' package is built into Emacs 29 (Denote supports
+        Emacs 28 though). We can use it to define an alternative to what
+        we have for the menu bar. Perhaps this interface can used to
+        toggle various options, such as to call `denote' with a
+        different set of prompts.
+
+  A `denote-directories' user option
+        This can be either an extension of the `denote-directory'
+        (accept a list of file paths value) or a new variable. The idea
+        is to let the user define separate Denote directories which do
+        know about the presence of each other (unlike silos). This way,
+        a user can have an entry in `~/Documents/notes/' link to
+        something `~/Git/projects/' and everything work as if the
+        `denote-directory' is set to the `~/' (with the status quo as of
+        2024-02-18 08:27 +0200).
+
+  Encode the day in the identifier
+        The idea is to use some coded reference for Monday, Tuesday,
+        etc. instead of having the generic `T' in the identifier. For
+        example, Monday is `A' so the identifier for it is something
+        like `20240219A101522' instead of what we now have as
+        `20240219T101522'. The old method should still be supported.
+        Apart from changing a few regular expressions, this does not
+        seem too complex to me. We would need a user option to opt in to
+        such a feature. Then tweak the relevant parts. The tricky issue
+        is to define a mapping of day names to letters/symbols that
+        works for everyone. Do all countries have a seven-day week, for
+        example? We need something universally applicable here.
+
+  Anything else? You are welcome to discuss these and/or add to the
+  list.
+
+
+23 Publications about Denote
+════════════════════════════
+
+  The Emacs community is putting Denote to great use.  This section
+  includes publications that show how people configure their note-taking
+  setup.  If you have a blog post, video, or configuration file about
+  Denote, feel welcome to tell us about it ([Contributing]).
+
+  ⁃ David Wilson (SystemCrafters): /Generating a Blog Site from Denote
+    Entries/, 2022-09-09, <https://www.youtube.com/watch?v=5R7ad5xz5wo>
+
+  ⁃ David Wilson (SystemCrafters): /Trying Out Prot’s Denote, an Org
+    Roam Alternative?/, 2022-07-15,
+    <https://www.youtube.com/watch?v=QcRY_rsX0yY>
+
+  ⁃ Jack Baty: /Keeping my Org Agenda updated based on Denote keywords/,
+    2022-11-30, <https://baty.net/2022/keeping-my-org-agenda-updated>
+
+  ⁃ Jeremy Friesen: /Denote Emacs Configuration/, 2022-10-02,
+    <https://takeonrules.com/2022/10/09/denote-emacs-configuration/>
+
+  ⁃ Jeremy Friesen: /Exploring the Denote Emacs Package/, 2022-10-01,
+    <https://takeonrules.com/2022/10/01/exploring-the-denote-emacs-package/>
+
+  ⁃ Jeremy Friesen: /Migration Plan for Org-Roam Notes to Denote/,
+    2022-10-02,
+    <https://takeonrules.com/2022/10/02/migration-plan-for-org-roam-notes-to-denote/>
+
+  ⁃ Jeremy Friesen: /Project Dispatch Menu with Org Mode Metadata,
+    Denote, and Transient/, 2022-11-19,
+    <https://takeonrules.com/2022/11/19/project-dispatch-menu-with-org-mode-metadata-denote-and-transient/>
+
+  ⁃ Mohamed Suliman: /Managing a bibliography of BiBTeX entries with
+    Denote/, 2022-12-20,
+    <https://www.scss.tcd.ie/~sulimanm/posts/denote-bibliography.html>
+
+  ⁃ Peter Prevos: /Simulating Text Files with R to Test the Emacs Denote
+    Package/, 2022-07-28,
+    <https://lucidmanager.org/productivity/testing-denote-package/>
+
+  ⁃ Peter Prevos: /Emacs Writing Studio/, 2023-10-19. A configuration
+    for authors, using Denote for taking notes, literature reviews and
+    manage collections of images:
+    • <https://lucidmanager.org/productivity/taking-notes-with-emacs-denote/>
+    • <https://lucidmanager.org/productivity/denote-explore/>
+    • <https://lucidmanager.org/productivity/bibliographic-notes-in-emacs-with-citar-denote/>
+    • <https://lucidmanager.org/productivity/using-emacs-image-dired/>
+
+  ⁃ Stefan Thesing: /Denote as a Zettelkasten/, 2023-03-02,
+    <https://www.thesing-online.de/blog/denote-as-a-zettelkasten>
+
+  ⁃ Summer Emacs: /An explanation of how I use Emacs/, 2023-05-04,
+    <https://github.com/summeremacs/howiuseemacs/blob/main/full-explanation-of-how-i-use-emacs.org>
+
+
+[Contributing] See section 22
+
+
+24 Alternatives to Denote
+═════════════════════════
+
+  What follows is a list of Emacs packages for note-taking.  I
+  (Protesilaos) have not used any of them, as I was manually applying my
+  file-naming scheme beforehand and by the time those packages were
+  available I was already hacking on the predecessor of Denote as a
+  means of learning Emacs Lisp (a package which I called “Unassuming
+  Sidenotes of Little Significance”, aka “USLS” which is pronounced as
+  “U-S-L-S” or “useless”).  As such, I cannot comment at length on the
+  differences between Denote and each of those packages, beside what I
+  gather from their documentation.
+
+  [org-roam]
+        The de facto standard in the Emacs milieu—and rightly so!  It
+        has a massive community, is featureful, and should be an
+        excellent companion to anyone who is invested in the Org
+        ecosystem and/or knows what “Roam” is (I don’t).  It has been
+        explained to me that Org Roam uses a database to store a cache
+        about your notes.  It otherwise uses standard Org files.  The
+        cache helps refer to the same node through aliases which can
+        provide lots of options.  Personally, I follow a
+        single-topic-per-note approach, so anything beyond that is
+        overkill.  If the database is only for a cache, then maybe that
+        has no downside, though I am careful with any kind of
+        specialised program as it creates a dependency.  If you ask me
+        about database software in particular, I have no idea how to use
+        one, let alone debug it or retrieve data from it if something
+        goes awry (I could learn, but that is beside the point).
+
+  [zk (or zk.el)]
+        Reading its documentation makes me think that this is Denote’s
+        sibling—the two projects have a lot of things in common,
+        including the preference to rely on plain files and standard
+        tools.  The core difference is that Denote has a strict
+        file-naming scheme.  Other differences in available features
+        are, in principle, matters of style or circumstance: both
+        packages can have them.  As its initials imply, ZK enables a
+        zettelkasten-like workflow.  It does not enforce it though,
+        letting the user adapt the method to their needs and
+        requirements.
+
+  [zettelkasten]
+        This is another one of Denote’s relatives, at least insofar as
+        the goal of simplicity is concerned.  The major difference is
+        that according to its documentation “the name of the file that
+        is created is just a unique ID”.  This is not consistent with
+        our file-naming scheme which is all about making sense of your
+        files by their name alone and being able to visually parse a
+        listing of them without any kind of specialised tool (e.g. `ls
+        -l' or `ls -C' on the command-line from inside the
+        `denote-directory' give you a human-readable set of files names,
+        while `find * -maxdepth 0 -type f' is another approach).
+
+  [zetteldeft]
+        This is a zettelkasten note-taking system built on top of the
+        `deft' package.  Deft provides a search interface to a
+        directory, in this case the one holding the user’s `zetteldeft'
+        notes.  Denote has no such dependency and is not opinionated
+        about how the user prefers to search/access their notes: use
+        Dired, Grep, the `consult' package, or whatever else you already
+        have set up for all things Emacs, not just your notes.
+
+  Searching through `M-x list-packages' for “zettel” brings up more
+  matches.  `zetteldesk' is an extension to Org Roam and, as such, I
+  cannot possibly know what Org Roam truly misses and what the
+  added-value of this package is.  `neuron-mode' builds on top of an
+  external program called `neuron', which I have never used.
+
+  Searching for “note” gives us a few more results.  `notes-mode' has
+  precious little documentation and I cannot tell what it actually does
+  (as I said in my presentation for LibrePlanet 2022, inadequate docs
+  are a bug).  `side-notes' differs from what we try to do with Denote,
+  as it basically gives you the means to record your thoughts about some
+  other project you are working on and keep them on the side: so it and
+  Denote should not be mutually exclusive.
+
+  If I missed something, please let me know.
+
+
+[org-roam] <https://github.com/org-roam/org-roam>
+
+[zk (or zk.el)] <https://github.com/localauthor/zk>
+
+[zettelkasten] <https://github.com/ymherklotz/emacs-zettelkasten>
+
+[zetteldeft] <https://github.com/EFLS/zetteldeft>
+
+24.1 Alternative implementations and further reading
+────────────────────────────────────────────────────
+
+  This section covers blog posts and implementations from the Emacs
+  community about the topic of note-taking and file organization.  They
+  may refer to some of the packages covered in the previous section or
+  provide their custom code ([Alternatives to Denote]).  The list is
+  unsorted.
+
+  ⁃ José Antonio Ortega Ruiz (aka “jao”) explains a note-taking method
+    that is simple like Denote but differs in other ways.  An
+    interesting approach overall:
+    <https://jao.io/blog/simple-note-taking.html>.
+
+  ⁃ Jethro Kuan (the main `org-roam' developer) explains their
+    note-taking techniques:
+    <https://jethrokuan.github.io/org-roam-guide/>.  Good ideas all
+    round, regardless of the package/code you choose to use.
+
+  ⁃ Karl Voit’s tools [date2name], [filetags], [appendfilename], and
+    [move2archive] provide a Python-based implementation to organize
+    individual files which do not require Emacs.  His approach ([blog
+    post] and his [presentation at GLT18]) has been complemented by
+    [memacs] to process e.g., the date of creation of photographs, or
+    the log of a phone call in a format compatible to org.
+
+  [ Development note: help expand this list. ]
+
+
+[Alternatives to Denote] See section 24
+
+[date2name] <https://github.com/novoid/date2name>
+
+[filetags] <https://github.com/novoid/filetags/>
+
+[appendfilename] <https://github.com/novoid/appendfilename/>
+
+[move2archive] <https://github.com/novoid/move2archive>
+
+[blog post] <https://karl-voit.at/managing-digital-photographs/>
+
+[presentation at GLT18] <https://www.youtube.com/watch?v=rckSVmYCH90>
+
+[memacs] <https://github.com/novoid/memacs>
+
+
+25 Frequently Asked Questions
+═════════════════════════════
+
+  I (Protesilaos) answer some questions I have received or might get.
+  It is assumed that you have read the rest of this manual: I will not
+  go into the specifics of how Denote works.
+
+
+25.1 Why develop Denote when PACKAGE already exists?
+────────────────────────────────────────────────────
+
+  I wrote Denote because I was using a variant of Denote’s file-naming
+  scheme before I was even an Emacs user (I switched to Emacs from
+  Tmux+Vim+CLI in the summer of 2019).  I was originally inspired by
+  Jekyll, the static site generator, which I started using for my
+  website in 2016 (was on WordPress before).  Jekyll’s files follow the
+  `YYYY-MM-DD-TITLE.md' pattern.  I liked its efficiency relative to the
+  unstructured mess I had before.  Eventually, I started using that
+  scheme outside the confines of my website’s source code.  Over time I
+  refined it and here we are.
+
+  Note-taking is something I take very seriously, as I am a prolific
+  writer (just check my website, which only reveals the tip of the
+  iceberg).  As such, I need a program that does exactly what I want and
+  which I know how to extend.  I originally tried to use Org capture
+  templates to create new files with a Denote-style file-naming scheme
+  but never managed to achieve it.  Maybe because `org-capture' has some
+  hard-coded assumptions or I simply am not competent enough to hack on
+  core Org facilities.  Whatever the case, an alternative was in order.
+
+  The existence of PACKAGE is never a good reason for me not to conduct
+  my own experiments for recreational, educational, or practical
+  purposes.  When the question arises of “why not contribute to PACKAGE
+  instead?” the answer is that without me experimenting in the first
+  place, I would lack the skills for such a task.  Furthermore,
+  contributing to another package does not guarantee I get what I want
+  in terms of workflow.
+
+  Whether you should use Denote or not is another matter altogether:
+  choose whatever you want.
+
+
+25.2 Why not rely exclusively on Org?
+─────────────────────────────────────
+
+  I think Org is one of Emacs’ killer apps.  I also believe it is not
+  the right tool for every job.  When I write notes, I want to focus on
+  writing.  Nothing more.  I thus have no need for stuff like org-babel,
+  scheduling to-do items, clocking time, and so on.  The more “mental
+  dependencies” you add to your workflow, the heavier the burden you
+  carry and the less focused you are on the task at hand: there is
+  always that temptation to tweak the markup, tinker with some syntactic
+  construct, obsess about what ought to be irrelevant to writing as
+  such.
+
+  In technical terms, I also am not fond of Org’s code base (I
+  understand why it is the way it is—just commenting on the fact).  Ever
+  tried to read it?  You will routinely find functions that are
+  tens-to-hundreds of lines long and have all sorts of special casing.
+  As I am not a programmer and only learnt to write Elisp through trial
+  and error, I have no confidence in my ability to make Org do what I
+  want at that level, hence `denote' instead of `org-denote' or
+  something.
+
+  Perhaps the master programmer is one who can deal with complexity and
+  keep adding to it.  I am of the opposite view, as language—code
+  included—is at its communicative best when it is clear and accessible.
+
+  Make no mistake: I use Org for the agenda and also to write technical
+  documentation that needs to be exported to various formats, including
+  this very manual.
+
+
+25.3 Why care about Unix tools when you use Emacs?
+──────────────────────────────────────────────────
+
+  My notes form part of my longer-term storage.  I do not want to have
+  to rely on a special program to be able to read them or filter them.
+  Unix is universal, at least as far as I am concerned.
+
+  Denote streamlines some tasks and makes things easier in general,
+  which is consistent with how Emacs provides a layer of interactivity
+  on top of Unix.  Still, Denote’s utilities can, in principle, be
+  implemented as POSIX shell scripts (minus the Emacs-specific parts
+  like fontification in Dired or the buttonization of links).
+
+  Portability matters.  For example, in the future I might own a
+  smartphone, so I prefer not to require Emacs, Org, or some other
+  executable to access my files on the go.
+
+  Furthermore, I might want to share those files with someone.  If I
+  make Emacs a requirement, I am limiting my circle to a handful of
+  relatively advanced users.
+
+  Please don’t misinterpret this: I am using Emacs full-time for my
+  computing and maintain a growing list of packages for it.  This is
+  just me thinking long-term.
+
+
+25.4 Why many small files instead of few large ones?
+────────────────────────────────────────────────────
+
+  I have read that Org favours the latter method.  If true, I strongly
+  disagree with it because of the implicit dependency it introduces and
+  the way it favours machine-friendliness over human-readability in
+  terms of accessing information.  Notes are long-term storage.  I might
+  want to access them on (i) some device with limited features, (ii)
+  print on paper, (iii) share with another person who is not a tech
+  wizard.
+
+  There are good arguments for few large files, but all either
+  prioritize machine-friendliness or presuppose the use of sophisticated
+  tools like Emacs+Org.
+
+  Good luck using `less' on a generic TTY to read a file with a zillion
+  words, headings, sub-headings, sub-sub-headings, property drawers, and
+  other constructs!  You will not get the otherwise wonderful folding of
+  headings the way you do in Emacs—do not take such features for
+  granted.
+
+  My point is that notes should be atomic to help the user—and
+  potentially the user’s family, friends, acquaintances—make sense of
+  them in a wide range of scenaria.  The more program-agnostic your file
+  is, the better for you and/or everyone else you might share your
+  writings with.
+
+  Human-readability means that we optimize for what matters to us.  If
+  (a) you are the only one who will ever read your notes, (b) always
+  have access to good software like Emacs+Org, (c) do not care about
+  printing on paper, then Denote’s model is not for you.  Maybe you need
+  to tweak some `org-capture' template to append a new entry to one mega
+  file (I do that for my Org agenda, by the way, as I explained before
+  about using the right tool for the job).
+
+
+25.5 Does Denote perform well at scale?
+───────────────────────────────────────
+
+  Denote does not do anything fancy and has no special requirements: it
+  uses standard tools to accomplish ordinary tasks.  If Emacs can cope
+  with lots of files, then that is all you need to know: Denote will
+  work.
+
+  To put this to the test, Peter Prevos is running simulations with R
+  that generate large volumes of notes.  You can read the technicalities
+  here: <https://lucidmanager.org/productivity/testing-denote-package/>.
+  Excerpt:
+
+        Using this code I generated ten thousands notes and used
+        this to test the Denote package to see it if works at a
+        large scale. This tests shows that Prot’s approach is
+        perfectly capable of working with thousands of notes.
+
+  Of course, we are always prepared to make refinements to the code,
+  where necessary, without compromising on the project’s principles.
+
+
+25.6 I add TODOs to my notes; will many files slow down the Org agenda?
+───────────────────────────────────────────────────────────────────────
+
+  Yes, many files will slow down the agenda due to how that works.  Org
+  collects all files specified in the `org-agenda-files', searches
+  through their contents for timestamped entries, and then loops through
+  all days to determine where each entry belongs.  The more days and
+  more files, the longer it takes to build the agenda.  Doing this with
+  potentially hundreds of files will have a noticeable impact on
+  performance.
+
+  This is not a deficiency of Denote.  It happens with generic Org
+  files.  The way the agenda is built is heavily favoring the use of a
+  single file that holds all your timestamped entries (or at least a few
+  such files).  Tens or hundreds of files are inefficient for this job.
+  Plus doing so has the side-effect of making Emacs open all those
+  files, which you probably do not need.
+
+  If you want my opinion though, be more forceful with the separation of
+  concerns.  Decouple your knowledge base from your ephemeral to-do
+  list: Denote (and others) can be used for the former, while you let
+  standard Org work splendidly for the latter—that is what I do, anyway.
+
+  Org has a powerful linking facility, whether you use `org-store-link'
+  or do it via an `org-capture' template.  If you want a certain note to
+  be associated with a task, just store the task in a single `tasks.org'
+  (or however you name it) and link to the relevant context.
+
+  Do not mix your knowledge base with your to-do items.  If you need
+  help figuring out the specifics of this workflow, you are welcome to
+  ask for help in our relevant channels ([Contributing]).
+
+
+[Contributing] See section 22
+
+
+25.7 I want to sort by last modified in Dired, why won’t Denote let me?
+───────────────────────────────────────────────────────────────────────
+
+  Denote does not control how Dired sorts files. I encourage you to read
+  the manpage of the `ls' executable. It will help you in general, while
+  it applies to Emacs as well via Dired. The gist is that you can update
+  the `ls' flags that Dired uses on-the-fly: type `C-u M-x
+  dired-sort-toggle-or-edit' (`C-u s' by default) and append
+  `--sort=time' at the prompt. To reverse the order, add the `-r' flag.
+  The user option `dired-listing-switches' sets your default preference.
+
+  For an on-demand sorted and filtered Dired listing of Denote files,
+  use the command `denote-sort-dired' ([Sort files by component]).
+
+
+[Sort files by component] See section 14
+
+
+25.8 How do you handle the last modified case?
+──────────────────────────────────────────────
+
+  Denote does not insert any meta data or heading pertaining to edits in
+  the file.  I am of the view that these either do not scale well or are
+  not descriptive enough.  Suppose you use a “lastmod” heading with a
+  timestamp: which lines where edited and what did the change amount to?
+
+  This is where an external program can be helpful.  Use a Version
+  Control System, such as Git, to keep track of all your notes.  Every
+  time you add a new file, record the addition.  Same for post-creation
+  edits.  Your VCS will let you review the history of those changes.
+  For instance, Emacs’ built-in version control framework has a command
+  that produces a log of changes for the current file: `M-x
+  vc-print-log', bound to `C-x v l' by default.  From there one can
+  access the corresponding diff output (use `M-x describe-mode' (`C-h
+  m') in an unfamiliar buffer to learn more about it).  With Git in
+  particular, Emacs users have the option of the all-round excellent
+  `magit' package.
+
+  In short: let Denote (or equivalent) create notes and link between
+  them, the file manager organise and provide access to files, search
+  programs deal with searching and narrowing, and version control
+  software handle the tracking of changes.
+
+
+25.9 Why are some Org links opening outside Emacs?
+──────────────────────────────────────────────────
+
+  Org has its own mechanism to determine how best to open a link. This
+  affects the `file:' link type, but also the `denote:' one (which is
+  designed to be as close to `file:' as possible).
+
+  When following a link, Org usually displays the data in an Emacs
+  buffer, though it might launch an external application instead. The
+  idea is to use a specialised program when that is relevant, such as to
+  display a video. Though there can be scenaria the user does not like,
+  such as when Org decides to load `.md' or `.html' files with an
+  external app. To compound the problem, users can name any file type
+  using the Denote file-naming scheme, including images, PDFs, videos,
+  and more ([Renaming files]).
+
+  To instruct Org to stay in Emacs for such cases, the user needs to
+  modify the variable `org-file-apps', which is not specific to Denote.
+  As one use-case, `org-file-apps' associates a regular expression to
+  match file names with a method on how to display them (do `M-x
+  describe-variable' and then search for `org-file-apps' to read its
+  documentation). Thus, the user can use something like the following in
+  their Org or Denote configuration:
+
+  ┌────
+  │ ;; Tell Org to use Emacs when opening files that end in .md
+  │ (add-to-list 'org-file-apps '("\\.md\\'" . emacs))
+  │ 
+  │ ;; Do the same for .html
+  │ (add-to-list 'org-file-apps '("\\.html\\'" . emacs))
+  └────
+
+  Each of these adds a new entry to the existing value of that user
+  option. Replace `md' or `html' with the desired file type extension.
+
+
+[Renaming files] See section 6
+
+
+25.10 Speed up backlinks’ or query links’ buffer creation?
+──────────────────────────────────────────────────────────
+
+  Denote leverages the built-in `xref' library to search for the
+  identifier of the current file and return any links to it.  For users
+  of Emacs version 28 or higher, there exists a user option to specify
+  the program that performs this search: `xref-search-program'.  The
+  default is `grep', which can be slow, though one may opt for `ugrep',
+  `ripgrep', or even specify something else (read the doc string of that
+  user option for the details).
+
+  Try either for these for better results:
+
+  ┌────
+  │ (setq xref-search-program 'ripgrep)
+  │ 
+  │ ;; OR
+  │ 
+  │ (setq xref-search-program 'ugrep)
+  └────
+
+  To use whatever executable is available on your system, use something
+  like this:
+
+  ┌────
+  │ ;; Prefer ripgrep, then ugrep, and fall back to regular grep.
+  │ (setq xref-search-program
+  │       (cond
+  │        ((or (executable-find "ripgrep")
+  │ 	    (executable-find "rg"))
+  │ 	'ripgrep)
+  │        ((executable-find "ugrep")
+  │ 	'ugrep)
+  │        (t
+  │ 	'grep)))
+  └────
+
+
+25.11 Why do I get “Search failed with status 1” when I search for backlinks?
+─────────────────────────────────────────────────────────────────────────────
+
+  Denote uses [Emacs’ Xref] to find backlinks.  Xref requires `xargs'
+  and one of `grep' or `ripgrep', depending on your configuration.
+
+  This is usually not an issue on *nix systems, but the necessary
+  executables are not available on Windows Emacs distributions.  Please
+  ensure that you have both `xargs' and either `grep' or `ripgrep'
+  available within your `PATH' environment variable.
+
+  If you have `git' on Windows installed, then you may use the following
+  code (adjust the git’s installation path if necessary):
+  ┌────
+  │ (setenv "PATH" (concat (getenv "PATH") ";" "C:\\Program Files\\Git\\usr\\bin"))
+  └────
+
+
+[Emacs’ Xref] <info:emacs#Xref>
+
+
+25.12 Why do I get a double `#+title' in Doom Emacs?
+────────────────────────────────────────────────────
+
+  Doom Emacs provides a set of bespoke templates for Org. One of those
+  prefills any new Org file with a `#+title' field. So when Denote
+  creates a new Org file and inserts front matter to it, it inevitably
+  adds an extra title to the existing one.
+
+  This is not a Denote problem. We can only expect a new file to be
+  empty by default. Check how to disable the relevant module in your
+  Doom Emacs configuration file.
+
+
+26 Acknowledgements
+═══════════════════
+
+  Denote is meant to be a collective effort.  Every bit of help matters.
+
+  Author/maintainer
+        Protesilaos Stavrou.
+
+  Contributions to code or the manual
+        Abdul-Lateef Haji-Ali, Abin Simon, Adam Růžička, Alan Schmitt,
+        Alexandre Rousseau, Ashton Wiersdorf, Aziz, Benjamin Kästner,
+        Bruno Boal, Charanjit Singh, Claudio Migliorelli, Clemens
+        Radermacher, Colin McLear, Damien Cassou, Eduardo Grajeda, Elias
+        Storms, Eshel Yaron, Florian, Glenna D., Graham Marlow, Hilde
+        Rhyne, Ivan Sokolov, Jack Baty, Jakub Szczerbowski, 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 Lemon, Noboru
+        Ota (nobiot), Norwid Behrnd, Octavian, Peter Prevos, Philip
+        Kaludercic, Quiliro Ordóñez, Stephen R. Kifer, Stefan Monnier,
+        Stefan Thesing, Thibaut Benjamin, Tomasz Hołubowicz, TomoeMami ,
+        Vedang Manerikar, Wesley Harvey, Zhenxu Xu, arsaber101,
+        bryanrinders, eum3l, ezchi, jarofromel, leinfink (Henrik),
+        l-o-l-h (Lincoln), mattyonweb, maxbrieiev, mentalisttraceur,
+        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, 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, Kolmas, Lukas C. Bossert, M. Hadi Timachi,
+        Maikol Solis, Mark Olson, Mirko Hernandez, Niall Dooley, Nick
+        Bell, Oliver Epper, Paul van Gelder, Peter Prevos, Peter Smith,
+        Riccardo Giannitrapani, 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, atanasj, azegas,
+        babusri, bdillahu, coherentstate, doolio, duli, drcxd, elge70,
+        elliottw, fingerknight, hpgisler, hyperfocus1337, jtpavlock,
+        juh, leafarbelm, mentalisttraceur, pRot0ta1p, rbenit68,
+        relict007, sarcom-sar, sienic, skissue, sundar bp,
+        yetanotherfossman, zadca123
+
+  Special thanks to Peter Povinec who helped refine the file-naming
+  scheme, which is the cornerstone of this project.
+
+  Special thanks to Jean-Philippe Gagné Guay for the numerous
+  contributions to the code base.
+
+
+27 GNU Free Documentation License
+═════════════════════════════════
+
+
+28 Indices
+══════════
+
+28.1 Function index
+───────────────────
+
+
+28.2 Variable index
+───────────────────
+
+
+28.3 Concept index
+──────────────────
blob - /dev/null
blob + 08540f63c17e06cdba24c8ce6c447e6950d89c6e (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/README.md
@@ -0,0 +1,24 @@
+# denote: Simple notes with an efficient file-naming scheme
+
+Denote is a simple note-taking tool for Emacs.  It is based on the idea
+that notes should follow a predictable and descriptive file-naming
+scheme.  The file name must offer a clear indication of what the note is
+about, without reference to any other metadata.  Denote basically
+streamlines the creation of such files while providing facilities to
+link between them.
+
+Denote's file-naming scheme is not limited to "notes".  It can be used
+for all types of file, including those that are not editable in Emacs,
+such as videos.  Naming files in a consistent way makes their
+filtering and retrieval considerably easier.  Denote provides relevant
+facilities to rename files, regardless of file type.
+
++ Package name (GNU ELPA): `denote`
++ Official manual: <https://protesilaos.com/emacs/denote>
++ Change log: <https://protesilaos.com/emacs/denote-changelog>
++ Git repositories:
+  + GitHub: <https://github.com/protesilaos/denote>
+  + GitLab: <https://gitlab.com/protesilaos/denote>
++ Video demo: <https://protesilaos.com/codelog/2022-06-18-denote-demo/>
++ Backronyms: Denote Everything Neatly; Omit The Excesses.  Don't Ever
+  Note Only The Epiphenomenal.
blob - /dev/null
blob + 505300ca60d8d62af9aedbb0d466ed97860601d3 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/README.org
@@ -0,0 +1,6808 @@
+#+title: denote: Simple notes with an efficient file-naming scheme
+#+author: Protesilaos Stavrou
+#+email: info@protesilaos.com
+#+language: en
+#+options: ':t toc:nil author:t email:t num:t
+#+startup: content
+#+macro: stable-version 4.0.0
+#+macro: release-date 2025-04-15
+#+macro: development-version 4.1.0-dev
+#+export_file_name: denote.texi
+#+texinfo_filename: denote.info
+#+texinfo_dir_category: Emacs misc features
+#+texinfo_dir_title: Denote: (denote)
+#+texinfo_dir_desc: Simple notes with an efficient file-naming scheme
+#+texinfo_header: @set MAINTAINERSITE @uref{https://protesilaos.com,maintainer webpage}
+#+texinfo_header: @set MAINTAINER Protesilaos Stavrou
+#+texinfo_header: @set MAINTAINEREMAIL @email{info@protesilaos.com}
+#+texinfo_header: @set MAINTAINERCONTACT @uref{mailto:info@protesilaos.com,contact the maintainer}
+
+#+texinfo: @insertcopying
+
+This manual, written by Protesilaos Stavrou, describes the customization
+options for the Emacs package called ~denote~ (or =denote.el=), and
+provides every other piece of information pertinent to it.
+
+The documentation furnished herein corresponds to stable version
+{{{stable-version}}}, released on {{{release-date}}}.  Any reference to
+a newer feature which does not yet form part of the latest tagged
+commit, is explicitly marked as such.
+
+Current development target is {{{development-version}}}.
+
++ Package name (GNU ELPA): ~denote~
++ Official manual: <https://protesilaos.com/emacs/denote>
++ Change log: <https://protesilaos.com/emacs/denote-changelog>
++ Git repositories:
+  + GitHub: <https://github.com/protesilaos/denote>
+  + GitLab: <https://gitlab.com/protesilaos/denote>
++ Video demo: <https://protesilaos.com/codelog/2022-06-18-denote-demo/>
++ Backronyms: Denote Everything Neatly; Omit The Excesses.  Don't Ever
+  Note Only The Epiphenomenal.
+
+If you are viewing the README.org version of this file, please note that
+the GNU ELPA machinery automatically generates an Info manual out of it.
+
+#+toc: headlines 8 insert TOC here, with eight headline levels
+
+* COPYING
+:PROPERTIES:
+:COPYING: t
+:CUSTOM_ID: h:40b18bb2-4dc1-4202-bd0b-6fab535b2a0f
+:END:
+
+Copyright (C) 2022-2025  Free Software Foundation, Inc.
+
+#+begin_quote
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and
+with the Back-Cover Texts as in (a) below.  A copy of the license is
+included in the section entitled “GNU Free Documentation License.”
+
+(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
+modify this GNU manual.”
+#+end_quote
+
+* Installation
+:PROPERTIES:
+:CUSTOM_ID: h:f3bdac2c-4704-4a51-948c-a789a2589790
+:END:
+#+cindex: Installation instructions
+
+** GNU ELPA package
+:PROPERTIES:
+:CUSTOM_ID: h:42953f87-82bd-43ec-ab99-22b1e22955e7
+:END:
+
+The package is available as =denote=.  Simply do:
+
+: M-x package-refresh-contents
+: M-x package-install
+
+And search for it.
+
+GNU ELPA provides the latest stable release.  Those who prefer to follow
+the development process in order to report bugs or suggest changes, can
+use the version of the package from the GNU-devel ELPA archive.  Read:
+https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/.
+
+** Manual installation
+:PROPERTIES:
+:CUSTOM_ID: h:d397712c-c8c0-4cfa-ad1a-ef28cf78d1f0
+:END:
+
+Assuming your Emacs files are found in =~/.emacs.d/=, execute the
+following commands in a shell prompt:
+
+#+begin_src sh
+cd ~/.emacs.d
+
+# Create a directory for manually-installed packages
+mkdir manual-packages
+
+# Go to the new directory
+cd manual-packages
+
+# Clone this repo, naming it "denote"
+git clone https://github.com/protesilaos/denote denote
+#+end_src
+
+Finally, in your =init.el= (or equivalent) evaluate this:
+
+#+begin_src emacs-lisp
+;; Make Elisp files in that directory available to the user.
+(add-to-list 'load-path "~/.emacs.d/manual-packages/denote")
+#+end_src
+
+Everything is in place to set up the package.
+
+* Sample configuration
+:PROPERTIES:
+:CUSTOM_ID: h:5d16932d-4f7b-493d-8e6a-e5c396b15fd6
+:END:
+#+cindex: Package configuration
+
+Denote is immediately useful for beginners and power users alike. This
+manual covers everything in detail, though do not let the numerous
+possibilities distract you from the fact that a basic configuration is
+enough to be highly productive ([[#h:998ae528-9276-47ec-b642-3d7355a38f27][Get started with this sample configuration]]).
+
+** Get started with this sample configuration
+:PROPERTIES:
+:CUSTOM_ID: h:998ae528-9276-47ec-b642-3d7355a38f27
+:END:
+
+If you are new to Denote, this a good place to start. Then work your
+way through the manual and expand your configuration accordingly. Only
+include commands/variables that are useful to you. We provide another
+code sample if you need some ideas ([[#h:58c4746b-b0d8-4896-9d88-a99b1d487231][More comprehensive sample configuration]]).
+
+#+begin_src emacs-lisp
+;; Remember that the website version of this manual shows the latest
+;; developments, which may not be available in the package you are
+;; using.  Instead of copying from the web site, refer to the version
+;; of the documentation that comes with your package.  Evaluate:
+;;
+;;     (info "(denote) Sample configuration")
+(use-package denote
+  :ensure t
+  :hook (dired-mode . denote-dired-mode)
+  :bind
+  (("C-c n n" . denote)
+   ("C-c n r" . denote-rename-file)
+   ("C-c n l" . denote-link)
+   ("C-c n b" . denote-backlinks)
+   ("C-c n d" . denote-dired)
+   ("C-c n g" . denote-grep))
+  :config
+  (setq denote-directory (expand-file-name "~/Documents/notes/"))
+
+  ;; Automatically rename Denote buffers when opening them so that
+  ;; instead of their long file name they have, for example, a literal
+  ;; "[D]" followed by the file's title.  Read the doc string of
+  ;; `denote-rename-buffer-format' for how to modify this.
+  (denote-rename-buffer-mode 1))
+#+end_src
+
+** More comprehensive sample configuration
+:PROPERTIES:
+:CUSTOM_ID: h:58c4746b-b0d8-4896-9d88-a99b1d487231
+:END:
+
+Here we include more of what you can configure with Denote ([[#h:998ae528-9276-47ec-b642-3d7355a38f27][Get started with this sample configuration]]).
+
+#+begin_src emacs-lisp
+;; Remember that the website version of this manual shows the latest
+;; developments, which may not be available in the package you are
+;; using.  Instead of copying from the web site, refer to the version
+;; of the documentation that comes with your package.  Evaluate:
+;;
+;;     (info "(denote) Sample configuration")
+(use-package denote
+  :ensure t
+  :hook
+  ( ;; If you use Markdown or plain text files, then you want to make
+   ;; the Denote links clickable (Org renders links as buttons right
+   ;; away)
+   (text-mode . denote-fontify-links-mode-maybe)
+   ;; Apply colours to Denote names in Dired.  This applies to all
+   ;; directories.  Check `denote-dired-directories' for the specific
+   ;; directories you may prefer instead.  Then, instead of
+   ;; `denote-dired-mode', use `denote-dired-mode-in-directories'.
+   (dired-mode . denote-dired-mode))
+  :bind
+  ;; Denote DOES NOT define any key bindings.  This is for the user to
+  ;; decide.  For example:
+  ( :map global-map
+    ("C-c n n" . denote)
+    ("C-c n d" . denote-dired)
+    ("C-c n g" . denote-grep)
+    ;; If you intend to use Denote with a variety of file types, it is
+    ;; easier to bind the link-related commands to the `global-map', as
+    ;; shown here.  Otherwise follow the same pattern for `org-mode-map',
+    ;; `markdown-mode-map', and/or `text-mode-map'.
+    ("C-c n l" . denote-link)
+    ("C-c n L" . denote-add-links)
+    ("C-c n b" . denote-backlinks)
+    ("C-c n q c" . denote-query-contents-link) ; create link that triggers a grep
+    ("C-c n q f" . denote-query-filenames-link) ; create link that triggers a dired
+    ;; Note that `denote-rename-file' can work from any context, not just
+    ;; Dired bufffers.  That is why we bind it here to the `global-map'.
+    ("C-c n r" . denote-rename-file)
+    ("C-c n R" . denote-rename-file-using-front-matter)
+
+    ;; Key bindings specifically for Dired.
+    :map dired-mode-map
+    ("C-c C-d C-i" . denote-dired-link-marked-notes)
+    ("C-c C-d C-r" . denote-dired-rename-files)
+    ("C-c C-d C-k" . denote-dired-rename-marked-files-with-keywords)
+    ("C-c C-d C-R" . denote-dired-rename-marked-files-using-front-matter))
+
+  :config
+  ;; Remember to check the doc string of each of those variables.
+  (setq denote-directory (expand-file-name "~/Documents/notes/"))
+  (setq denote-save-buffers nil)
+  (setq denote-known-keywords '("emacs" "philosophy" "politics" "economics"))
+  (setq denote-infer-keywords t)
+  (setq denote-sort-keywords t)
+  (setq denote-prompts '(title keywords))
+  (setq denote-excluded-directories-regexp nil)
+  (setq denote-excluded-keywords-regexp nil)
+  (setq denote-rename-confirmations '(rewrite-front-matter modify-file-name))
+
+  ;; Pick dates, where relevant, with Org's advanced interface:
+  (setq denote-date-prompt-use-org-read-date t)
+
+  ;; Automatically rename Denote buffers using the `denote-rename-buffer-format'.
+  (denote-rename-buffer-mode 1))
+#+end_src
+
+* Overview
+:PROPERTIES:
+:CUSTOM_ID: h:a09b70a2-ae0b-4855-ac14-1dddfc8e3241
+:END:
+
+Denote aims to be a simple-to-use, focused-in-scope, and effective
+note-taking and file-naming tool for Emacs.
+
+Denote is based on the idea that files should follow a predictable and
+descriptive file-naming scheme.  The file name must offer a clear
+indication of what the contents are about, without reference to any
+other metadata.  Denote basically streamlines the creation of such
+files or file names while providing facilities to link between them
+(where those files are editable).
+
+Denote's file-naming scheme is not limited to "notes".  It can be used
+for all types of file, including those that are not editable in Emacs,
+such as videos.  Naming files in a consistent way makes their
+filtering and retrieval considerably easier.  Denote provides relevant
+facilities to rename files, regardless of file type.
+
+Denote is based on the following core design principles:
+
++ Predictability :: File names must follow a consistent and descriptive
+  naming convention ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).  The file name alone
+  should offer a clear indication of what the contents are, without
+  reference to any other metadatum.  This convention is not specific to
+  note-taking, as it is pertinent to any form of file that is part of
+  the user's long-term storage ([[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]).
+
++ Composability :: Be a good Emacs citizen, by integrating with other
+  packages or built-in functionality instead of re-inventing functions
+  such as for filtering or greping.  The author of Denote (Protesilaos,
+  aka "Prot") writes ordinary notes in plain text (=.txt=), switching on
+  demand to an Org file only when its expanded set of functionality is
+  required for the task at hand ([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]).
+
++ Portability :: Notes are plain text and should remain portable.  The
+  way Denote writes file names, the front matter it includes in the
+  note's header, and the links it establishes must all be adequately
+  usable with standard Unix tools.  No need for a database or some
+  specialised software.  As Denote develops and this manual is fully
+  fleshed out, there will be concrete examples on how to do the
+  Denote-equivalent on the command-line.
+
++ Flexibility :: Do not assume the user's preference for a note-taking
+  methodology.  Denote is conceptually similar to the Zettelkasten
+  Method, which you can learn more about in this detailed introduction:
+  <https://zettelkasten.de/introduction/>.  Notes are atomic (one file
+  per note) and have a unique identifier.  However, Denote does not
+  enforce a particular methodology for knowledge management, such as a
+  restricted vocabulary or mutually exclusive sets of keywords.  Denote
+  also does not check if the user writes thematically atomic notes.  It
+  is up to the user to apply the requisite rigor and/or creativity in
+  pursuit of their preferred workflow ([[#h:6060a7e6-f179-4d42-a9de-a9968aaebecc][Writing metanotes]]).
+
++ Hackability :: Denote's code base consists of small and reusable
+  functions.  They all have documentation strings.  The idea is to make
+  it easier for users of varying levels of expertise to understand what
+  is going on and make surgical interventions where necessary (e.g. to
+  tweak some formatting).  In this manual, we provide concrete examples
+  on such user-level configurations ([[#h:4a6d92dd-19eb-4fcc-a7b5-05ce04da3a92][Keep a journal or diary]]).
+
+Now the important part...  "Denote" is the familiar word, though it also
+is a play on the "note" concept.  Plus, we can come up with acronyms,
+recursive or otherwise, of increasingly dubious utility like:
+
++ Don't Ever Note Only The Epiphenomenal
++ Denote Everything Neatly; Omit The Excesses
+
+But we'll let you get back to work.  Don't Eschew or Neglect your
+Obligations, Tasks, and Engagements.
+
+* Points of entry
+:PROPERTIES:
+:CUSTOM_ID: h:17896c8c-d97a-4faa-abf6-31df99746ca6
+:END:
+
+#+findex: denote
+#+findex: denote-type
+#+findex: denote-org-capture
+#+findex: denote-date
+#+findex: denote-subdirectory
+#+findex: denote-template
+#+findex: denote-signature
+There are seven main ways to write a note with Denote: invoke the
+~denote~, ~denote-type~, ~denote-date~, ~denote-subdirectory~,
+~denote-template~, ~denote-signature~ commands, or leverage the
+~org-capture-templates~ by setting up a template which calls the
+function ~denote-org-capture~.  We explain all of those in the
+subsequent sections.  Other more specialised commands exist as well,
+which one shall learn about as they read through this manual.  We do
+not want to overwhelm the user with options at this stage.
+
+All these commands construct the file name in accordance with the user option
+~denote-file-name-components-order~ ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+** Standard note creation
+:PROPERTIES:
+:CUSTOM_ID: h:6a92a8b5-d766-42cc-8e5b-8dc255466a23
+:END:
+
+The ~denote~ command will prompt for a title.  If a region is active,
+the text of the region becomes the default at the minibuffer prompt
+(meaning that typing =RET= without any input will use the default
+value).  Once the title is supplied, the ~denote~ command will then ask
+for keywords.  The resulting note will have a file name as already
+explained: [[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file naming scheme]]
+
+#+vindex: denote-after-new-note-hook
+The ~denote~ command runs the hook ~denote-after-new-note-hook~ after
+creating the new note ([[#h:a947908e-1847-4471-ba07-377ee2f4b36c][Access the data of the latest note]]). When
+called from Lisp, it returns the path it generates. Before returning
+the path, it decides what to do with the buffer of the note, in
+accordance with the user option ~denote-kill-buffers~ ([[#h:c8fd826f-3ac9-4820-9709-4375603f8865][The ~denote-kill-buffers~ option]]).
+
+The file type of the new note is determined by the user option
+~denote-file-type~ ([[#h:13218826-56a5-482a-9b91-5b6de4f14261][Front matter]]).
+
+#+vindex: denote-known-keywords
+#+vindex: denote-infer-keywords
+The keywords' prompt supports minibuffer completion.  Available
+candidates are those defined in the user option ~denote-known-keywords~.
+More candidates can be inferred from the names of existing notes, by
+setting ~denote-infer-keywords~ to non-nil (which is the case by
+default) ([[#h:c0fb477f-4f99-4d76-9cce-132bcfcb351d][Create a controlled vocabulary for keywords]]).
+
+#+vindex: denote-sort-keywords
+Multiple keywords can be inserted by separating them with a comma (or
+whatever the value of the ~crm-separator~ is---which should be a comma).
+When the user option ~denote-sort-keywords~ is non-nil (the default),
+keywords are sorted alphabetically (technically, the sorting is done
+with ~string-lessp~).
+
+The interactive behaviour of the ~denote~ command is influenced by the
+user option ~denote-prompts~ ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The denote-prompts option]]).
+
+The ~denote~ command can also be called from Lisp.  Read its doc string
+for the technicalities.
+
+#+findex: denote-create-note
+In the interest of discoverability, ~denote~ is also available under the
+alias ~denote-create-note~.
+
+*** The ~denote-prompts~ option
+:PROPERTIES:
+:CUSTOM_ID: h:f9204f1f-fcee-49b1-8081-16a08a338099
+:END:
+
+#+vindex: denote-prompts
+The user option ~denote-prompts~ determines how the ~denote~ command
+will behave interactively ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]).
+
+Commands that prompt for user input to construct a Denote file name
+include, but are not limited to: ~denote~, ~denote-signature~,
+~denote-type~, ~denote-date~, ~denote-subdirectory~,
+~denote-rename-file~, ~denote-dired-rename-files~.
+
+- [[#h:887bdced-9686-4e80-906f-789e407f2e8f][Convenience commands for note creation]].
+- [[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]].
+
+The value of this user option is a list of symbols, which includes any
+of the following:
+
+- =title=: Prompt for the title of the new note ([[#h:403422a7-7578-494b-8f33-813874c12da3][The ~denote-history-completion-in-prompts~ option]]).
+
+- =keywords=: Prompts with completion for the keywords of the new note.
+  Available candidates are those specified in the user option
+  ~denote-known-keywords~.  If the user option ~denote-infer-keywords~
+  is non-nil, keywords in existing note file names are included in the
+  list of candidates.  The =keywords= prompt uses
+  ~completing-read-multiple~, meaning that it can accept multiple
+  keywords separated by a comma (or whatever the value of ~crm-separator~
+  is).
+
+- =file-type=: Prompts with completion for the file type of the new
+  note.  Available candidates are those specified in the user option
+  ~denote-file-type~.  Without this prompt, ~denote~ uses the value of
+  ~denote-file-type~.
+
+- =subdirectory=: Prompts with completion for a subdirectory in which to
+  create the note.  Available candidates are the value of the user
+  option ~denote-directory~ and all of its subdirectories.  Any
+  subdirectory must already exist: Denote will not create it.
+
+- =date=: Prompts for the date of the new note.  It will expect an input
+  like 2022-06-16 or a date plus time: 2022-06-16 14:30.  Without the
+  =date= prompt, the ~denote~ command uses the ~current-time~.
+
+  [[#h:e7ef08d6-af1b-4ab3-bb00-494a653e6d63][The denote-date-prompt-use-org-read-date option]].
+
+- =template=: Prompts for a KEY among the ~denote-templates~.  The value
+  of that KEY is used to populate the new note with content, which is
+  added after the front matter ([[#h:f635a490-d29e-4608-9372-7bd13b34d56c][The denote-templates option]]).
+
+- =signature=: - Prompts for an arbitrary string that can be used for
+  any kind of workflow, such as a special tag to label the =part1= and
+  =part2= of a large file that is split in half, or to add special
+  contexts like =home= and =work=, or even priorities like =a=, =b=,
+  =c=. One other use-case is to implement a sequencing scheme that
+  makes notes have hierarchical relationships. This is handled by our
+  optional extension =denote-sequence.el=, which is part of the
+  ~denote~ package ([[#h:d5ca722d-e7fa-46fa-9a57-6363b1d4186f][Write sequence notes or "folgezettel"]]).
+
+The prompts occur in the given order.
+
+If the value of this user option is nil, no prompts are used.  The
+resulting file name will consist of an identifier (i.e. the date and
+time) and a supported file type extension (per ~denote-file-type~).
+
+Recall that Denote's standard file-naming scheme is defined as follows
+([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]):
+
+: DATE--TITLE__KEYWORDS.EXT
+
+If either or both of the =title= and =keywords= prompts are not
+included in the value of this variable, file names will be any of
+those permutations:
+
+: DATE.EXT
+: DATE--TITLE.EXT
+: DATE__KEYWORDS.EXT
+
+When in doubt, always include the =title= and =keywords= prompts.
+
+Finally, this user option only affects the interactive use of the
+~denote~ or other relevant commands (advanced users can call it from
+Lisp). In Lisp usage, the behaviour is always what the caller
+specifies, based on the supplied arguments.
+
+*** The ~denote-history-completion-in-prompts~ option
+:PROPERTIES:
+:CUSTOM_ID: h:403422a7-7578-494b-8f33-813874c12da3
+:END:
+
+#+vindex: denote-history-completion-in-prompts
+The user option ~denote-history-completion-in-prompts~ toggles history
+completion in all ~denote-prompts-with-history-as-completion~.
+
+When this user option is set to a non-nil value, Denote will use
+minibuffer history entries as completion candidates in all of the
+~denote-prompts-with-history-as-completion~. Those will show previous
+inputs from their respective history as possible values to select,
+either to (i) re-insert them verbatim or (ii) with the intent to edit
+them further (depending on the minibuffer user interface, one can
+select a candidate with =TAB= without exiting the minibuffer, as
+opposed to what =RET= normally does by selecting and exiting).
+
+When this user option is set to a nil value, all of the
+~denote-prompts-with-history-as-completion~ will not use minibuffer
+completion: they will just prompt for a string of characters. Their
+history is still available through all the standard ways of retrieving
+minibuffer history, such as with the command ~previous-history-element~.
+
+History completion still allows arbitrary values to be provided as
+input: they do not have to match the available minibuffer completion
+candidates.
+
+Note that some prompts, like ~denote-keywords-prompt~, always use
+minibuffer completion, due to the specifics of their data.
+
+[ Consider enabling the built-in ~savehist-mode~ to persist minibuffer
+  histories between sessions.]
+
+*** The ~denote-templates~ option
+:PROPERTIES:
+:CUSTOM_ID: h:f635a490-d29e-4608-9372-7bd13b34d56c
+:END:
+
+#+vindex: denote-templates
+The user option ~denote-templates~ is an alist of content templates for
+new notes.  A template is arbitrary text that Denote will add to a newly
+created note right below the front matter.
+
+Templates are expressed as a =(KEY . VALUE)= association.
+
+- The =KEY= is the name which identifies the template.  It is an
+  arbitrary symbol, such as =report=, =memo=, =statement=.
+
+- The =VALUE= is either a string or the symbol of a function.
+
+  - If it is a string, it is ordinary text that Denote will insert
+    as-is.  It can contain newline characters to add spacing.  The
+    manual of Denote contains examples on how to use the ~concat~
+    function, beside writing a generic string.
+
+  - If it is a function, it is called without arguments and is expected
+    to return a string.  Denote will call the function and insert the
+    result in the buffer.
+
+The user can choose a template either by invoking the command
+~denote-template~ or by changing the user option ~denote-prompts~ to
+always prompt for a template when calling the ~denote~ command.
+
+[[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The denote-prompts option]].
+
+[[#h:887bdced-9686-4e80-906f-789e407f2e8f][Convenience commands for note creation]].
+
+Templates can be written directly as one large string.  For example (the
+=\n= character is read as a newline):
+
+#+begin_src emacs-lisp
+(setq denote-templates
+      '((report . "* Some heading\n\n* Another heading")
+        (memo . "* Some heading
+
+,* Another heading
+
+")))
+#+end_src
+
+Long strings may be easier to type but interpret indentation literally.
+Also, they do not scale well.  A better way is to use some Elisp code to
+construct the string.  This would typically be the ~concat~ function,
+which joins multiple strings into one.  The following is the same as the
+previous example:
+
+#+begin_src emacs-lisp
+(setq denote-templates
+      `((report . "* Some heading\n\n* Another heading")
+        (memo . ,(concat "* Some heading"
+                         "\n\n"
+                         "* Another heading"
+                         "\n\n"))))
+#+end_src
+
+Notice that to evaluate a function inside of an alist we use the
+backtick to quote the alist (NOT the straight quote) and then prepend a
+comma to the expression that should be evaluated.  The ~concat~ form
+here is not sensitive to indentation, so it is easier to adjust for
+legibility.
+
+For when the =VALUE= is a function, we have this:
+
+#+begin_src emacs-lisp
+(setq denote-templates
+      `((report . "* Some heading\n\n* Another heading")
+        (blog . my-denote-template-function-for-blog) ; a function to return a string
+        (memo . ,(concat "* Some heading"
+                         "\n\n"
+                         "* Another heading"
+                         "\n\n"))))
+#+end_src
+
+In this example, ~my-denote-template-function-for-blog~ is a function
+that returns a string. Denote will take care to insert it in the buffer.
+
+DEV NOTE: We do not provide more examples at this point, though feel
+welcome to ask for help if the information provided herein is not
+sufficient.  We shall expand the manual accordingly.
+
+*** Convenience commands for note creation
+:PROPERTIES:
+:CUSTOM_ID: h:887bdced-9686-4e80-906f-789e407f2e8f
+:END:
+
+Sometimes the user needs to create a note that has different
+requirements from those of ~denote~ ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]).  While
+this can be achieved globally by changing the ~denote-prompts~ user
+option, there are cases where an ad-hoc method is the appropriate one
+([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The denote-prompts option]]).
+
+To this end, Denote provides the following interactive convenience
+commands for note creation. They all work by appending a new prompt to
+the existing ~denote-prompts~.
+
++ Create note by specifying file type :: The ~denote-type~ command
+  creates a note while prompting for a file type.
+
+  This is the equivalent of calling ~denote~ when ~denote-prompts~ has
+  the =file-type= prompt appended to its existing prompts. In practical
+  terms, this lets you produce, say, a note in Markdown even though
+  you normally write in Org ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]).
+
+  #+findex: denote-create-note-using-type
+  The ~denote-create-note-using-type~ is an alias of ~denote-type~.
+
++ Create note using a date :: Normally, Denote reads the current date
+  and time to construct the unique identifier of a newly created note
+  ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]).  Sometimes, however, the user needs to set
+  an explicit date+time value.
+
+  This is where the ~denote-date~ command comes in.  It creates a note
+  while prompting for a date.  The date can be in YEAR-MONTH-DAY
+  notation like =2022-06-30= or that plus the time: =2022-06-16 14:30=.
+
+  [[#h:e7ef08d6-af1b-4ab3-bb00-494a653e6d63][The denote-date-prompt-use-org-read-date option]].
+
+  This is the equivalent of calling ~denote~ when ~denote-prompts~ has
+  the =date= prompt appended to its existing prompts.
+
+  #+findex: denote-create-note-using-date
+  The ~denote-create-note-using-date~ is an alias of ~denote-date~.
+
++ Create note in a specific directory :: The ~denote-subdirectory~
+  command creates a note while prompting for a subdirectory.  Available
+  candidates include the value of the variable ~denote-directory~ and
+  any subdirectory thereof (Denote does not create subdirectories).
+
+  This is the equivalent of calling ~denote~ when ~denote-prompts~ has
+  the =subdirectory= prompt appended to its existing prompts.
+
+  #+findex: denote-create-note-in-subdirectory
+  The ~denote-create-note-in-subdirectory~ is a more descriptive alias
+  of ~denote-subdirectory~.
+
++ Create note and add a template :: The ~denote-template~ command
+  creates a new note and inserts the specified template below the front
+  matter ([[#h:f635a490-d29e-4608-9372-7bd13b34d56c][The denote-templates option]]).  Available candidates for
+  templates are specified in the user option ~denote-templates~.
+
+  This is the equivalent of calling ~denote~ when ~denote-prompts~ has
+  the =template= prompt appended to its existing prompts.
+
+  #+findex: denote-create-note-with-template
+  The ~denote-create-note-with-template~ is an alias of the command
+  ~denote-template~, meant to help with discoverability.
+
++ Create note with a signature :: The ~denote-signature~ command first
+  prompts for an arbitrary string to use in the optional =SIGNATURE=
+  field of the file name and then asks for a title and keywords.
+  Signatures are arbitrary strings of alphanumeric characters which
+  can be used to establish sequential relations between file at the
+  level of their file name (e.g. 1, 1a, 1b, 1b1, 1b2, ...).
+
+  This is the equivalent of calling ~denote~ when ~denote-prompts~ has
+  the =signature= prompt appended to its existing prompts.
+
+  The ~denote-create-note-using-signature~ is an alias of the command
+  ~denote-signature~ intended to make the functionality more
+  discoverable.
+
+**** Write your own convenience commands
+:PROPERTIES:
+:CUSTOM_ID: h:11946562-7eb0-4925-a3b5-92d75f1f5895
+:END:
+
+The convenience commands we provide only cover some basic use-cases
+([[#h:887bdced-9686-4e80-906f-789e407f2e8f][Convenience commands for note creation]]). The user may require
+combinations that are not covered, such as to prompt for a template
+and for a subdirectory, instead of only one of the two. To this end,
+we show how to follow the code we use in Denote to write your own
+variants of those commands.
+
+First let's take a look at the definition of one of those commands.
+They all look the same, but we use ~denote-subdirectory~ for this
+example:
+
+#+begin_src emacs-lisp
+(defun denote-subdirectory ()
+  "Create note while prompting for a subdirectory.
+
+Available candidates include the value of the variable
+`denote-directory' and any subdirectory thereof.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `subdirectory' prompt appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(subdirectory))))
+    (call-interactively #'denote)))
+#+end_src
+
+The hyphenated word after ~defun~ is the name of the function. It has
+to be unique. Then we have the documentation string (or "doc string")
+which is for the user's convenience.
+
+This function is ~interactive~, meaning that it can be called via
+=M-x= or be assigned to a key binding. Then we have the local binding
+of the ~denote-prompts~ to the desired combination ("local" means
+specific to this function without affecting other contexts). Lastly,
+it calls the standard ~denote~ command interactively, so it uses all
+the prompts in their specified order.
+
+The function call ~(denote-add-prompts '(subdirectory))~ will append
+the subdirectory prompt to the existing value of the ~denote-prompts~.
+If, for example, the default value is ='(title keywords)= (to prompt
+for a title and then for keywords), it will become ='(subdirectory
+title keywords)= inside the context of this ~let~. Remember that this
+is "local", so the global value of ~denote-prompts~ remains unaffected.
+
+Now let's say we want to have a command that (i) asks for a template
+(ii) for a subdirectory ([[#h:f635a490-d29e-4608-9372-7bd13b34d56c][The denote-templates option]]), and (iii) then
+goes through the remaining ~denote-prompts~. All we need to do is
+tweak the ~let~ bound value of ~denote-prompts~ and give our command a
+unique name:
+
+#+begin_src emacs-lisp
+;; Like `denote-subdirectory' but also ask for a template
+(defun my-denote-subdirectory-with-template ()
+  "Create note while also prompting for a template and subdirectory.
+
+This is the equivalent of calling `denote' when `denote-prompts' has the
+`subdirectory' and `template' prompts appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(subdirectory template))))
+    (call-interactively #'denote)))
+#+end_src
+
+The tweaks to ~denote-prompts~ determine how the command will behave
+([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The denote-prompts option]]). Use this paradigm to write your own
+variants which you can then assign to keys, invoke with =M-x=, or add
+to the list of commands available at the ~denote-command-prompt~
+([[#h:98c732ac-da0e-4ebd-a0e3-5c47f9075e51][Choose which commands to prompt for]]).
+
+In the above scenario, we are using the ~denote-add-prompts~ function,
+which appends whatever prompts we want to the existing value of
+~denote-prompts~. If the user prefers to completely override the
+~denote-prompts~, they can set the value outright:
+
+#+begin_src emacs-lisp
+(defun my-denote-subdirectory-with-template-title-and-keywords ()
+  "Create a note while prompting for subdirectory, template, title, and keywords.
+
+This is the equivalent of calling `denote' when `denote-prompts' has the
+value '(template subdirectory title keywords)."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts '(subdirectory template title keywords)))
+    (call-interactively #'denote)))
+#+end_src
+
+*** The ~denote-save-buffers~ option
+:PROPERTIES:
+:CUSTOM_ID: h:bf80f4cd-6f56-4f7c-a991-8573161e4511
+:END:
+
+#+vindex: denote-save-buffers
+The user option ~denote-save-buffer-after-creation~ controls whether
+commands that create new notes save their buffer outright.
+
+The default behaviour of commands such as ~denote~ (or related) is to
+not save the buffer they create ([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]). This gives the user
+the chance to review the text before writing it to a file. The user
+may choose to delete the unsaved buffer, thus not creating a new note
+([[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffer-after-creation~ option]]).
+
+This option also applies to notes affected by the renaming commands
+(~denote-rename-file~ and related).
+
+If this user option is set to a non-nil value, such buffers are saved
+automatically. The assumption is that the user who opts in to this
+feature is familiar with the ~denote-rename-file~ operation (or
+related) and knows it is reliable ([[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]).
+
+[[#h:c8fd826f-3ac9-4820-9709-4375603f8865][The ~denote-kill-buffers~ option]].
+
+*** The ~denote-kill-buffers~ option
+:PROPERTIES:
+:CUSTOM_ID: h:c8fd826f-3ac9-4820-9709-4375603f8865
+:END:
+
+#+vindex: denote-kill-buffers
+The user option ~denote-kill-buffers~ controls whether to kill a
+buffer that was generated by a Denote command. This can happen when
+creating a new file or renaming an existing one.
+
+- [[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]].
+- [[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]].
+
+The default behaviour of creation or renaming commands such as
+~denote~ or ~denote-rename-file~ is to not kill the buffer they
+create or modify at the end of their operation. The idea is to give
+the user the chance to confirm that everything is in order.
+
+If this user option is nil (the default), buffers affected by a
+creation or renaming command are not automatically killed.
+
+If set to the symbol =on-creation=, new notes are automatically killed.
+
+If set to the symbol =on-rename=, renamed notes are automatically
+killed.
+
+If set to t, new and renamed notes are killed.
+
+If a buffer is killed, it is also saved, as if ~denote-save-buffers~
+were t ([[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffers~ option]]).
+
+In all cases, if the buffer already existed before the Denote operation
+it is NOT automatically killed.
+
+*** The ~denote-date-prompt-use-org-read-date~ option
+:PROPERTIES:
+:CUSTOM_ID: h:e7ef08d6-af1b-4ab3-bb00-494a653e6d63
+:END:
+
+By default, Denote uses its own simple prompt for date or date+time
+input ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The denote-prompts option]]).  This is done when the
+~denote-prompts~ option includes a =date= symbol and/or when the user
+invokes the ~denote-date~ command.
+
+#+vindex: denote-date-prompt-use-org-read-date
+Users who want to benefit from the more advanced date selection method
+that is common in interactions with Org mode, can set the user option
+~denote-date-prompt-use-org-read-date~ to a non-nil value.
+
+
+** Create note using Org capture
+:PROPERTIES:
+:CUSTOM_ID: h:656c70cd-cf9a-4471-a0b5-4f0aaf60f881
+:END:
+
+For integration with ~org-capture~, the user must first add the relevant
+template.  Such as:
+
+#+begin_src emacs-lisp
+(with-eval-after-load 'org-capture
+  (add-to-list 'org-capture-templates
+               '("n" "New note (with Denote)" plain
+                 (file denote-last-path)
+                 #'denote-org-capture
+                 :no-save t
+                 :immediate-finish nil
+                 :kill-buffer t
+                 :jump-to-captured t)))
+#+end_src
+
+Once the template is added, it is accessed from the specified key. If,
+for instance, ~org-capture~ is bound to =C-c c=, then the note
+creation is initiated with =C-c c n=, per the above snippet. After
+that, the process is the same as with invoking ~denote~ directly,
+namely: a prompt for a title followed by a prompt for keywords,
+assuming the default settings ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]). Concretely,
+this method always respects the value of the user option
+~denote-prompts~ ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The ~denote-prompts~ option]]).
+
+It is also possible to define templates that have specific prompts or
+certain values set, for which there is no prompt:
+
+- [[#h:115b6797-f265-40e9-a603-32eeda13a7ac][Create note with specific values using Org capture]]
+- [[#h:95b78582-9086-47e8-967f-62373e2369a0][Create note with specific prompts using Org capture]]
+
+#+vindex: denote-org-capture-specifiers
+Users may prefer to leverage ~org-capture~ in order to extend file
+creation with the specifiers described in the ~org-capture-templates~
+documentation (such as to capture the active region and/or create a
+hyperlink pointing to the given context).
+
+IMPORTANT.  Due to the particular file-naming scheme of Denote, which is
+derived dynamically, such specifiers or other arbitrary text cannot be
+written directly in the template.  Instead, they have to be assigned to
+the user option ~denote-org-capture-specifiers~, which is interpreted by
+the function ~denote-org-capture~.  Example with our default value:
+
+#+begin_src emacs-lisp
+(setq denote-org-capture-specifiers "%l\n%i\n%?")
+#+end_src
+
+Note that ~denote-org-capture~ ignores the ~denote-file-type~: it always
+sets the Org file extension for the created note to ensure that the
+capture process works as intended, especially for the desired output of
+the ~denote-org-capture-specifiers~.
+
+[ You may not need ~org-capture~ to do what you want ([[#h:11946562-7eb0-4925-a3b5-92d75f1f5895][Write your own convenience commands]]). ]
+
+** Create note with specific prompts using Org capture
+:PROPERTIES:
+:CUSTOM_ID: h:95b78582-9086-47e8-967f-62373e2369a0
+:END:
+
+This section assumes knowledge of how Denote+org-capture work, as
+explained in the previous section ([[#h:656c70cd-cf9a-4471-a0b5-4f0aaf60f881][Create note using Org capture]]).
+
+#+findex: denote-org-capture-with-prompts
+The previous section shows how to define an Org capture template that
+always prompts for whatever is set in the user option ~denote-prompts~
+(title and keywords, by default). There are, however, cases where the
+user wants more control over what kind of input Denote will prompt
+for. To this end, we provide the function ~denote-org-capture-with-prompts~.
+Below we explain it and then show some examples of how to use it.
+
+The ~denote-org-capture-with-prompts~ is like ~denote-org-capture~ but
+with optional prompt parameters.
+
+When called without arguments, it does not prompt for anything.  It
+just returns the front matter with title and keyword fields empty and
+the date and identifier fields specified.  It also makes the file name
+consist of only the identifier plus the Org file name extension ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+Otherwise, it produces a minibuffer prompt for every non-nil value
+that corresponds to the =TITLE=, =KEYWORDS=, =SUBDIRECTORY=, =DATE=,
+and =TEMPLATE= arguments.  The prompts are those used by the standard
+~denote~ command and all of its utility commands ([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]).
+
+When returning the contents that fill in the Org capture template, the
+sequence is as follows: front matter, =TEMPLATE=, and then the value
+of the user option ~denote-org-capture-specifiers~.
+
+Important note: in the case of =SUBDIRECTORY= actual subdirectories
+must exist---Denote does not create them.  Same principle for
+=TEMPLATE= as templates must exist and are specified in the user
+option ~denote-templates~.
+
+This is how one can incorporate ~denote-org-capture-with-prompts~ in
+their Org capture templates.  Instead of passing a generic ~t~ which
+makes it hard to remember what the argument means, we use semantic
+keywords like =:title= for our convenience (internally this does not
+matter as the value still counts as non-nil, so =:foo= for =TITLE= is
+treated the same as =:title= or ~t~).
+
+#+begin_src emacs-lisp
+;; This prompts for TITLE, KEYWORDS, and SUBDIRECTORY
+(add-to-list 'org-capture-templates
+             '("N" "New note with prompts (with denote.el)" plain
+               (file denote-last-path)
+               (function
+                (lambda ()
+                  (denote-org-capture-with-prompts :title :keywords :subdirectory)))
+               :no-save t
+               :immediate-finish nil
+               :kill-buffer t
+               :jump-to-captured t))
+
+;; This prompts only for SUBDIRECTORY
+(add-to-list 'org-capture-templates
+             '("N" "New note with prompts (with denote.el)" plain
+               (file denote-last-path)
+               (function
+                (lambda ()
+                  (denote-org-capture-with-prompts nil nil :subdirectory)))
+               :no-save t
+               :immediate-finish nil
+               :kill-buffer t
+               :jump-to-captured t))
+
+;; This prompts for TITLE and SUBDIRECTORY
+(add-to-list 'org-capture-templates
+             '("N" "New note with prompts (with denote.el)" plain
+               (file denote-last-path)
+               (function
+                (lambda ()
+                  (denote-org-capture-with-prompts :title nil :subdirectory)))
+               :no-save t
+               :immediate-finish nil
+               :kill-buffer t
+               :jump-to-captured t))
+#+end_src
+
+[ You may not need ~org-capture~ to do what you want ([[#h:11946562-7eb0-4925-a3b5-92d75f1f5895][Write your own convenience commands]]). ]
+
+** Create note with specific values using Org capture
+:PROPERTIES:
+:CUSTOM_ID: h:115b6797-f265-40e9-a603-32eeda13a7ac
+:END:
+
+The ordinary procedure to create a note with ~org-capture~ respects
+the value of the user option ~denote-prompts~ ([[#h:656c70cd-cf9a-4471-a0b5-4f0aaf60f881][Create note using Org capture]]):
+the user is prompted for all the values they have configured (title
+and keywords, by default). Sometimes, there is no need to have a
+certain prompt because the value of it will be constant. For example,
+the user wants to have a template that (i) respects the
+~denote-prompts~ but (ii) puts the new note in an existing subdirectory
+of the ~denote-directory~. The following code block does exactly that.
+
+[ It also is possible to have a template that deviates from
+  ~denote-prompts~ and prompts for specific values ([[#h:95b78582-9086-47e8-967f-62373e2369a0][Create note with specific prompts using Org capture]]). ]
+
+#+begin_src emacs-lisp
+(with-eval-after-load 'org-capture
+  (add-to-list 'org-capture-templates
+               '("r" "New reference (with Denote)" plain
+                 (file denote-last-path)
+                 (function
+                  (lambda ()
+                    (let ((denote-use-directory (expand-file-name "reference" (denote-directory))))
+                      (denote-org-capture))))
+                 :no-save t
+                 :immediate-finish nil
+                 :kill-buffer t
+                 :jump-to-captured t)))
+#+end_src
+
+The values one may predefine in this way are via these variables ([[#h:c916d8c5-540a-409f-b780-6ccbd90e088e][For developers or advanced users]]):
+
+#+findex: denote-use-date
++ ~denote-use-date~
+
+#+findex: denote-use-directory
++ ~denote-use-directory~
+
+#+findex: denote-use-file-type
++ ~denote-use-file-type~
+
+#+findex: denote-use-keywords
++ ~denote-use-keywords~
+
+#+findex: denote-use-signature
++ ~denote-use-signature~
+
+#+findex: denote-use-template
++ ~denote-use-template~
+
+#+findex: denote-use-title
++ ~denote-use-title~
+
+When there exists a binding for the aforementioned variables, the
+corresponding prompt is always skipped. It is thus paramount to never
+set those variables outside the scope of a ~let~ (or equivalent).
+
+With those granted, here is another example scenario where the user
+wants to have a constant value for the subdirectory but also be
+prompted for a date.
+
+#+begin_src emacs-lisp
+(with-eval-after-load 'org-capture
+  (add-to-list 'org-capture-templates
+               '("j" "New journal (with Denote)" plain
+                 (file denote-last-path)
+                 (function
+                  (lambda ()
+                    ;; The "journal" subdirectory of the `denote-directory'---this must exist!
+                    (let* ((denote-use-directory (expand-file-name "journal" (denote-directory)))
+                           ;; Use the existing `denote-prompts' as well as the one for a date.
+                           (denote-prompts (denote-add-prompts '(date))))
+                      (denote-org-capture))))
+                 :no-save t
+                 :immediate-finish nil
+                 :kill-buffer t
+                 :jump-to-captured t)))
+#+end_src
+
+The above highlights the hackability of the Denote code base, namely,
+how we can affect the behaviour of the underlying ~denote~ command by
+~let~ binding variables that affect every aspect of its behaviour
+([[#h:11946562-7eb0-4925-a3b5-92d75f1f5895][Write your own convenience commands]]).
+
+
+** Create a note with the region's contents
+:PROPERTIES:
+:CUSTOM_ID: h:2f8090f1-50af-4965-9771-d5a91a0a87bd
+:END:
+
+#+findex: denote-region
+The command ~denote-region~ takes the contents of the active region
+and then calls the ~denote~ command.  Once a new note is created, it
+inserts the contents of the region therein.  This is useful to
+quickly elaborate on some snippet of text or capture it for future
+reference.
+
+#+vindex: denote-region-after-new-note-functions
+When the ~denote-region~ command is called with an active region, it
+finalises its work by calling ~denote-region-after-new-note-functions~.
+This is an abnormal hook, meaning that the functions added to it are
+called with arguments.  The arguments are two, representing the
+beginning and end positions of the newly inserted text.
+
+A common use-case for Org mode users is to call the command
+~org-insert-structure-template~ after a region is inserted.  Emacs
+will thus prompt for a structure template, such as the one
+corresponding to a source block.  In this case the function added to
+~denote-region-after-new-note-functions~ does not actually need
+aforementioned arguments: it can simply declare those as ignored by
+prefixing the argument names with an underscore (an underscore is
+enough, but it is better to include a name for clarity).  For example,
+the following will prompt for a structure template as soon as
+~denote-region~ is done:
+
+#+begin_src emacs-lisp
+(defun my-denote-region-org-structure-template (_beg _end)
+  (when (derived-mode-p 'org-mode)
+    (activate-mark)
+    (call-interactively 'org-insert-structure-template)))
+
+(add-hook 'denote-region-after-new-note-functions #'my-denote-region-org-structure-template)
+#+end_src
+
+Remember that ~denote-region-after-new-note-functions~ are not called
+if ~denote-region~ is used without an active region.
+
+*** A custom ~denote-region~ that references the source
+:PROPERTIES:
+:CUSTOM_ID: h:eb72086e-05be-4ae3-af51-7616999fc7c9
+:END:
+
+The ~denote-region~ command simply creates a new note and includes the
+highlighted region's contents as the initial text of the note ([[#h:2f8090f1-50af-4965-9771-d5a91a0a87bd][Create a note with the region's contents]]).
+However, users may want a more streamlined workflow where the command
+is always used to capture quotes from other sources. In this example,
+we consider "other sources" to come from Emacs EWW buffers (with ~M-x
+eww~) or regular files outside the ~denote-directory~.
+
+[ This is a proof-of-concept that does not cover all cases. If anyone
+  wants to use a variation of this, just let me know. ]
+
+#+begin_src emacs-lisp
+;; Variant of `my-denote-region' to reference the source
+
+(defun my-denote-region-get-source-reference ()
+  "Get a reference to the source for use with `my-denote-region'.
+The reference is a URL or an Org-formatted link to a file."
+  ;; We use a `cond' here because we can extend it to cover move
+  ;; cases.
+  (cond
+   ((derived-mode-p 'eww-mode)
+    (plist-get eww-data :url))
+   ;; Here we are just assuming an Org format.  We can make this more
+   ;; involved, if needed.
+   (buffer-file-name
+    (format "[[file:%s][%s]]" buffer-file-name (buffer-name)))))
+
+(defun my-denote-region ()
+  "Like `denote-region', but add the context afterwards.
+For how the context is retrieved, see `my-denote-region-get-source-reference'."
+  (interactive)
+  (let ((context (my-denote-region-get-source-reference)))
+    (call-interactively 'denote-region)
+    (when context
+      (goto-char (point-max))
+      (insert "\n")
+      (insert context))))
+
+;; Add quotes around snippets of text captured with `denote-region' or `my-denote-region'.
+
+(defun my-denote-region-org-structure-template (beg end)
+  "Automatically quote (with Org syntax) the contents of `denote-region'."
+  (when (derived-mode-p 'org-mode)
+    (goto-char end)
+    (insert "#+end_quote\n")
+    (goto-char beg)
+    (insert "#+begin_quote\n")))
+
+(add-hook 'denote-region-after-new-note-functions #'my-denote-region-org-structure-template)
+#+end_src
+
+With the above in place, calling the ~my-denote-region~ command does
+the following:
+
+- It creates a new note as usual, prompting for the relevant data.
+- Inserts the contents of the region below the front matter of the new
+  note.
+- Adds Org-style quotation block markers around the inserted region.
+- Adds a link to the URL or file from where ~my-denote-region~ was called.
+
+** Open an existing note or create it if missing
+:PROPERTIES:
+:CUSTOM_ID: h:ad91ca39-cf10-4e16-b224-fdf78f093883
+:END:
+
+#+findex: denote-open-or-create
+#+findex: denote-open-or-create-with-command
+Sometimes it is necessary to briefly interrupt the ongoing writing
+session to open an existing note or, if that is missing, to create it.
+This happens when a new tangential thought occurs and the user wants
+to confirm that an entry for it is in place.  To this end, Denote
+provides the command ~denote-open-or-create~ as well as its more
+flexible counterpart ~denote-open-or-create-with-command~.
+
+The ~denote-open-or-create~ prompts to visit a file in the
+~denote-directory~.  At this point, the user must type in search terms
+that match a file name.  If the input does not return any matches and
+the user confirms their choice to proceed (usually by typing RET
+twice, depending on the minibuffer settings), ~denote-open-or-create~
+will call the ~denote~ command interactively to create a new note.  It
+will then use whatever prompts ~denote~ normally has, per the user
+option ~denote-prompts~ ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]).  If the title prompt
+is involved (the default behaviour), the ~denote-open-or-create~ sets
+up this prompt to have the previous input as the default title of the
+note to-be-created.  This means that the user can type RET at the
+empty prompt to re-use what they typed in previously.  Commands to use
+previous inputs from the history are also available (=M-p= or =M-n= in
+the minibuffer, which call ~previous-history-element~ and
+~next-history-element~ by default).  Accessing the history is helpful
+to, for example, make further edits to the available text.
+
+The ~denote-open-or-create-with-command~ is like the above, except
+when it is about to create the new note it first prompts for the
+specific file-creating command to use ([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]).  For example,
+the user may want to specify a signature for this new file, so they
+can select the ~denote-signature~ command.
+
+Denote provides similar functionality for linking to an existing note
+or creating a new one ([[#h:b6056e6b-93df-4e6b-a778-eebd105bac46][Link to a note or create it if missing]]).
+
+** Maintain separate directory silos for notes
+:PROPERTIES:
+:CUSTOM_ID: h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5
+:END:
+#+cindex: Note silos
+
+The user option ~denote-directory~ accepts a value that represents the
+path to a directory, such as =~/Documents/notes=. Normally, the user
+will have one place where they store all their notes, in which case
+this arrangement shall suffice.
+
+There is, however, the possibility to maintain separate directories of
+notes. By "separate", we mean that they do not communicate with each
+other: no linking between them, no common keywords, nothing. Think of
+the scenario where one set of notes is for private use and another is
+for an employer. We call these separate directories "silos".
+
+To create silos, the user must specify a local variable at the root of
+the desired directory. This is done by creating a =.dir-locals.el=
+file, with the following contents:
+
+#+begin_src emacs-lisp
+;;; Directory Local Variables.  For more information evaluate:
+;;;
+;;;     (info "(emacs) Directory Variables")
+
+((nil . ((denote-directory . "/path/to/silo/"))))
+#+end_src
+
+When inside the directory that contains this =.dir-locals.el= file,
+all Denote commands/functions for note creation, linking, the
+inference of available keywords, et cetera will use the silo as their
+point of reference ([[#h:e43baf95-f201-4fec-8620-c0eb5eaa1c85][The ~denote-silo~ package which formerly was =denote-silo-extras.el=]]).
+They will not read the global value of ~denote-directory~. The global
+value of ~denote-directory~ is read everywhere else except the silos.
+
+In concrete terms, this is a representation of the directory structures
+(notice the =.dir-locals.el= file is needed only for the silos):
+
+#+begin_example
+;; This is the global value of 'denote-directory' (no need for a .dir-locals.el)
+~/Documents/notes
+|-- 20210303T120534--this-is-a-test__journal_philosophy.txt
+|-- 20220303T120534--another-sample__journal_testing.md
+`-- 20220620T181255--the-third-test__keyword.org
+
+;; A silo with notes for the employer
+~/different/path/to/notes-for-employer
+|-- .dir-locals.el
+|-- 20210303T120534--this-is-a-test__conference.txt
+|-- 20220303T120534--another-sample__meeting.md
+`-- 20220620T181255--the-third-test__keyword.org
+
+;; Another silo with notes for my volunteering
+~/different/path/to/notes-for-volunteering
+|-- .dir-locals.el
+|-- 20210303T120534--this-is-a-test__activism.txt
+|-- 20220303T120534--another-sample__teambuilding.md
+`-- 20220620T181255--the-third-test__keyword.org
+#+end_example
+
+It is possible to configure other user options of Denote to have a
+silo-specific value.  For example, this one changes the
+~denote-known-keywords~ only for this particular silo:
+
+#+begin_src emacs-lisp
+;;; Directory Local Variables.  For more information evaluate:
+;;;
+;;;     (info "(emacs) Directory Variables")
+
+((nil . ((denote-directory . "/path/to/silo/")
+         (denote-known-keywords . ("food" "drink")))))
+#+end_src
+
+This one is like the above, but also disables ~denote-infer-keywords~:
+
+#+begin_src emacs-lisp
+;;; Directory Local Variables.  For more information evaluate:
+;;;
+;;;     (info "(emacs) Directory Variables")
+
+((nil . ((denote-directory . "/path/to/silo/")
+         (denote-known-keywords . ("food" "drink"))
+         (denote-infer-keywords . nil))))
+#+end_src
+
+To expand the list of local variables to, say, cover specific major
+modes, we can do something like this:
+
+#+begin_src emacs-lisp
+;;; Directory Local Variables.  For more information evaluate:
+;;;
+;;;     (info "(emacs) Directory Variables")
+
+((nil . ((denote-directory . "/path/to/silo/")
+         (denote-known-keywords . ("food" "drink"))
+         (denote-infer-keywords . nil)))
+ (org-mode . ((org-hide-emphasis-markers . t)
+              (org-hide-macro-markers . t)
+              (org-hide-leading-stars . t))))
+#+end_src
+
+As not all user options have a "safe" local value, Emacs will ask the
+user to confirm their choice and to store it in the Custom code
+snippet that is normally appended to init file (or added to the file
+specified by the user option ~custom-file~).
+
+Finally, it is possible to have a =.dir-locals.el= for subdirectories
+of any ~denote-directory~.  Perhaps to specify a different set of
+known keywords, while not making the subdirectory a silo in its own
+right.  We shall not expand on such an example, as we trust the user
+to experiment with the best setup for their workflow.
+
+Feel welcome to ask for help if the information provided herein is not
+sufficient.  The manual shall be expanded accordingly.
+
+*** Make Org export work with silos
+:PROPERTIES:
+:CUSTOM_ID: h:fed09992-7c43-4237-b48f-f654bc29d1d8
+:END:
+
+The Org export infrastructure is designed to ignore directory-local
+variables. This means that Denote silos, which depend on setting the
+local value of the variable ~denote-directory~, do not work as
+intended ([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directory silos for notes]]). More
+specifically, the Denote links do not resolve to the right file,
+because their path is changed during the export process.
+
+I brought this to the attention of the Org maintainer. The guidance
+from their side is to use the =#+bind= keyword to specify a local
+value for the ~denote-directory~: <https://lists.gnu.org/archive/html/emacs-orgmode/2024-06/msg00206.html>.
+The prerequisite is to set ~org-export-allow-bind-keywords~ to a
+non-nil value:
+
+#+begin_src emacs-lisp
+(setq org-export-allow-bind-keywords t)
+#+end_src
+
+I do not think this is an elegant solution, but here are two possible
+ways to go about it, anyway:
+
+1. Manually add the =#+bind= keyword to each file you want to export.
+   It has to be like this:
+
+   #+begin_src emacs-lisp
+   ,#+bind: denote-directory "/path/to/silo/"
+   #+end_src
+
+2. Alternatively, you can make the Org front matter that Denote uses
+   for new files automatically include the =#+bind= keyword with its
+   desired value. Here is a complete =.dir-locals.el= which (i)
+   defines the silo and (ii) modifies the ~denote-org-front-matter~
+   accordingly:
+
+   #+begin_src emacs-lisp
+   ;;; Directory Local Variables.  For more information evaluate:
+   ;;;
+   ;;;     (info "(emacs) Directory Variables")
+
+   ((nil . ((denote-directory . "/path/to/silo/")
+            (denote-org-front-matter .
+             "#+title:      %s
+,#+date:       %s
+,#+filetags:   %s
+,#+identifier: %s
+,#+bind:       denote-directory \"/path/to/silo/\"
+\n"))))
+   #+end_src
+
+   [ Note that if you are reading the Org source of this manual, you
+     need to use the command ~org-edit-special~ on the above code
+     blocks before copying the code. This is because Org automatically
+     prepends a comma to disambiguate those entries from actual
+     keywords of the current file. ]
+
+** Exclude certain files from file prompts
+:PROPERTIES:
+:CUSTOM_ID: h:53db09de-2cec-4670-b163-5cb791f997b4
+:END:
+
+#+vindex: denote-excluded-files-regexp
+The user option ~denote-excluded-files-regexp~ is a regular expression
+that matches files names which should be excluded from all Denote file
+prompts. Such prompts are present when linking to a file with one of
+the many commands, like ~denote-link~ ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]), or when trying
+to open a file that may or may not exist ([[#h:ad91ca39-cf10-4e16-b224-fdf78f093883][Open an existing note or create it if missing]]).
+
+Functions that check for files include ~denote-directory-files~ and
+~denote-file-prompt~.
+
+The match is performed with ~string-match-p~.
+
+[[#h:c916d8c5-540a-409f-b780-6ccbd90e088e][For developers or advanced users]].
+
+** Exclude certain directories from all operations
+:PROPERTIES:
+:CUSTOM_ID: h:8458f716-f9c2-4888-824b-2bf01cc5850a
+:END:
+
+#+vindex: denote-excluded-directories-regexp
+The user option ~denote-excluded-directories-regexp~ instructs all
+Denote functions that read or check file/directory names to omit
+directories that match the given regular expression.  The regexp needs
+to match only the name of the directory, not its full path.
+
+Affected operations include file prompts and functions that return the
+available files in the value of the user option ~denote-directory~
+([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directory silos for notes]]).
+
+File prompts are used by several commands, such as ~denote-link~ and
+~denote-subdirectory~.
+
+Functions that check for files include ~denote-directory-files~ and
+~denote-directory-subdirectories~.
+
+The match is performed with ~string-match-p~.
+
+[[#h:c916d8c5-540a-409f-b780-6ccbd90e088e][For developers or advanced users]].
+
+** Exclude certain keywords from being inferred
+:PROPERTIES:
+:CUSTOM_ID: h:69e518ee-ed43-40ab-a5f4-c780a23e5358
+:END:
+
+#+vindex: denote-excluded-keywords-regexp
+The user option ~denote-excluded-keywords-regexp~ omits keywords that
+match a regular expression from the list of inferred keywords.
+
+Keywords are inferred from file names and provided at relevant prompts
+as completion candidates when the user option ~denote-infer-keywords~
+is non-nil.
+
+The match is performed with ~string-match-p~.
+
+** Create a controlled vocabulary for keywords
+:PROPERTIES:
+:CUSTOM_ID: h:c0fb477f-4f99-4d76-9cce-132bcfcb351d
+:END:
+
+Denote has two ways to know about keywords: the predefined list of
+strings specified in the user option ~denote-known-keywords~ as well
+as all the keywords it finds in the files of the ~denote-directory~
+when the user option ~denote-infer-keywords~ is set to a non-nil value
+([[#h:69e518ee-ed43-40ab-a5f4-c780a23e5358][Exclude certain keywords from being inferred]]).
+
+While this is a viable setup, users may prefer to implement a
+"controlled vocabulary". This is a predefined set of keywords whose
+purpose is to avoid the creation of overly specific or inconsistent
+keywords.
+
+To establish such a controlled vocabulary, users need only have
+something like this in their configuration:
+
+#+begin_src emacs-lisp
+;; Do not read keywords from files.  The only source is the `denote-known-keywords'.
+(setq denote-infer-keywords nil)
+
+;; Define the list of keywords.  Each keyword is a string.
+(setq denote-known-keywords (list "politics" "economics" "emacs" "philosophy"))
+#+end_src
+
+** Use Denote commands from the menu bar or context menu
+:PROPERTIES:
+:CUSTOM_ID: h:c4290e15-e97e-4a9b-b8db-6b9738e37e78
+:END:
+
+Denote registers a submenu for the ~menu-bar-mode~.  Users will find
+the entry called "Denote".  From there they can use their pointer to
+select a command.  For a sample of how this looks, read the
+development log: <https://protesilaos.com/codelog/2023-03-31-emacs-denote-menu/>.
+
+#+findex: denote-menu-bar-mode
+The command ~denote-menu-bar-mode~ toggles the presentation of the
+menu. It is enabled by default.
+
+Emacs also provides support for operations through a context menu.
+This is typically the set of actions that are made available via a
+right mouse click.  Users who enable ~context-menu-mode~ can register
+the Denote entry for it by adding the following to their configuration
+file:
+
+#+begin_src emacs-lisp
+(add-hook 'context-menu-functions #'denote-context-menu)
+#+end_src
+
+* Renaming files
+:PROPERTIES:
+:CUSTOM_ID: h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca
+:END:
+
+Denote provides commands to rename files and update their front matter
+where relevant.  For Denote to work, only the file name needs to be in
+order, by following our naming conventions ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+The linking mechanism, in particular, needs just the identifier in the
+file name ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]).
+
+We write front matter in notes for the user's convenience and for other
+tools to make use of that information (e.g. Org's export mechanism).
+The renaming mechanism takes care to keep this data in sync with the
+file name, when the user performs a change.
+
+Renaming is useful for managing existing files created with Denote,
+but also for converting older text files to Denote notes.  Denote's
+file-naming scheme is not specific to notes or text files: it is
+relevant for all sorts of items, such as multimedia and PDFs that form
+part of the user's longer-term storage.  While Denote does not manage
+such files (e.g. doesn't create links to them), it already has all the
+mechanisms to facilitate the task of renaming them.
+
+#+vindex: denote-after-rename-file-hook
+All renaming commands run the ~denote-after-rename-file-hook~ after a
+succesful operation ([[#h:a947908e-1847-4471-ba07-377ee2f4b36c][Access the data of the latest note]]). They also
+construct the file name in accordance with the user option
+~denote-file-name-components-order~ ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+Apart from renaming files, Denote can also rename only the buffer.
+The idea is that the underlying file name is correct but it can be
+easier to use shorter buffer names when displaying them on the mode
+line or switching between then with commands like ~switch-to-buffer~.
+
+[[#h:3ca4db16-8f26-4d7d-b748-bac48ae32d69][Automatically rename Denote buffers]].
+
+[[#h:9051f15d-ea7e-4b17-adc2-bc6a749c721b][Find duplicate identifiers and put them in a Dired buffer]].
+
+** Rename a single file
+:PROPERTIES:
+:CUSTOM_ID: h:7cc9e000-806a-48da-945c-711bbc7426b0
+:END:
+
+#+findex: denote-rename-file
+The ~denote-rename-file~ command renames a file and updates existing
+front matter if appropriate. It is possible to do the same with
+multiple files ([[#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde][Rename multiple files interactively]]).
+
+It always renames the file where it is located in the file system:
+it never moves it to another directory.
+
+If in Dired, it considers =FILE= to be the one at point, else it
+prompts with minibuffer completion for one. When called from Lisp,
+=FILE= is a file system path represented as a string.
+
+If =FILE= has a Denote-compliant identifier, it retains it while
+updating components of the file name referenced by the user option
+~denote-prompts~ ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The ~denote-prompts~ option]]). By default, these are
+the =TITLE= and =KEYWORDS=. The =SIGNATURE= is another one. When
+called from Lisp, =TITLE= and =SIGNATURE= are strings, while
+=KEYWORDS= is a list of strings.
+
+If there is no identifier, ~denote-rename-file~ creates an identifier
+based on the following conditions:
+
+1. If the ~denote-prompts~ includes an entry for date prompts, then it
+   prompts for =DATE= and takes its input to produce a new identifier. For
+   use in Lisp, =DATE= must conform with ~denote-valid-date-p~.
+
+2. If =DATE= is nil (e.g. when ~denote-prompts~ does not include a
+   date entry), it uses the file attributes to determine the last
+   modified date of =FILE= and formats it as an identifier.
+
+3. As a fallback, it derives an identifier from the current date and
+   time.
+
+4. At any rate, if the resulting identifier is not unique among the
+   files in the variable ~denote-directory~, it increments it such
+   that it becomes unique.
+
+In interactive use, and assuming ~denote-prompts~ includes a title
+entry, the ~denote-rename-file~ makes the =TITLE= prompt have
+prefilled text in the minibuffer that consists of the current title of
+=FILE=. The current title is either retrieved from the front matter
+(such as the =#+title= in Org) or from the file name.
+
+The command does the same for the =SIGNATURE= prompt, subject to
+~denote-prompts~, by prefilling the minibuffer with the current
+signature of =FILE=, if any.
+
+Same principle for the =KEYWORDS= prompt: it converts the keywords in
+the file name into a comma-separated string and prefills the minibuffer
+with it (the =KEYWORDS= prompt accepts more than one keywords, each
+separated by a comma, else the ~crm-separator~).
+
+For all prompts, the ~denote-rename-file~ interprets an empty input as
+an instruction to remove that file name component. For example, if a
+=TITLE= prompt is available and =FILE= is =20240211T093531--some-title__keyword1.org=
+then it renames =FILE= to =20240211T093531__keyword1.org=.
+
+In interactive use, if there is no entry for a file name component in
+~denote-prompts~, keep it as-is ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The ~denote-prompts~ option]]).
+
+When called from Lisp, the special symbol `keep-current' can be
+used for the TITLE, KEYWORDS, SIGNATURE and DATE parameters to
+keep them as-is.
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input. The Emacs default setup accepts the empty
+  minibuffer contents as they are, though popular packages like
+  ~vertico~ use the first available completion candidate instead. For
+  ~vertico~, the user must either move one up to select the prompt and
+  then type =RET= there with empty contents, or use the command
+  ~vertico-exit-input~ with empty contents. That Vertico command is
+  bound to =M-RET= as of this writing on 2024-02-13 08:08 +0200. ]
+
+When renaming =FILE=, the command reads its file type extension (like
+=.org=) and preserves it through the renaming process. Files that have
+no extension are left without one.
+
+As a final step, ask for confirmation, showing the difference
+between old and new file names.  Do not ask for confirmation if
+the user option ~denote-rename-confirmations~ does not contain
+the symbol ~modify-file-name~ ([[#h:a2ae9090-c49e-4b32-bcf5-eb8944241fd7][The ~denote-rename-confirmations~ option]]).
+
+If =FILE= has front matter for =TITLE= and =KEYWORDS=, ask to rewrite
+their values in order to reflect the new input, unless
+~denote-rename-confirmations~ lacks ~rewrite-front-matter~. When the
+~denote-save-buffers~ is nil (the default), do not save the underlying
+buffer, thus giving the user the option to double-check the result,
+such as by invoking the command ~diff-buffer-with-file~. The rewrite
+of the =TITLE= and =KEYWORDS= in the front matter should not affect
+the rest of the front matter.
+
+If the file does not have front matter but is among the supported file
+types (per ~denote-file-type~), add front matter to the top of it and
+leave the buffer unsaved for further inspection ([[#h:13218826-56a5-482a-9b91-5b6de4f14261][Front matter]]). Save
+the buffer if ~denote-save-buffers~ is non-nil ([[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffers~ option]]).
+
+Construct the file name in accordance with the user option
+~denote-file-name-components-order~ ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+Run the ~denote-after-rename-file-hook~ after renaming =FILE= ([[#h:a947908e-1847-4471-ba07-377ee2f4b36c][Access the data of the latest note]]).
+
+This command is intended to (i) rename Denote files, (ii) convert
+existing supported file types to Denote notes, and (ii) rename
+non-note files (e.g. =PDF=) that can benefit from Denote's file-naming
+scheme.
+
+For a version of this command that works with multiple files
+one-by-one, use ~denote-dired-rename-files~ ([[#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde][Rename multiple files interactively]]).
+
+*** The ~denote-rename-confirmations~ option
+:PROPERTIES:
+:CUSTOM_ID: h:a2ae9090-c49e-4b32-bcf5-eb8944241fd7
+:END:
+
+#+vindex: denote-rename-confirmations
+The user option ~denote-rename-confirmations~ controls what kind of
+confirmation renaming commands ask for ([[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]).  Its value is
+a list of symbols.
+
+The value is either nil, in which case no confirmation is ever
+requested, or a list of symbols among the following:
+
+- ~modify-file-name~ means that renaming commands will ask for
+  confirmation before modifying the file name.
+
+- ~rewrite-front-matter~ means that renaming commands will ask for
+  confirmation before rewritting the front matter.
+
+- ~add-front-matter~ means that renaming commands will ask for
+  confirmation before adding new front matter to the file.
+
+The default behaviour of the ~denote-rename-file~ command (and others
+like it) is to ask for an affirmative answer as a final step before
+changing the file name and, where relevant, inserting or updating the
+corresponding front matter.
+
+Specialized commands that build on top of ~denote-rename-file~ (or
+related) may internally bind this user option to a non-nil value in
+order to perform their operation (e.g. ~denote-dired-rename-files~
+goes through each marked Dired file, prompting for the information to
+use, but carries out the renaming without asking for confirmation
+([[#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde][Rename multiple files interactively]])).
+
+** Rename a single file based on its front matter
+:PROPERTIES:
+:CUSTOM_ID: h:3ab08ff4-81fa-4d24-99cb-79f97c13a373
+:END:
+
+#+findex: denote-rename-file-using-front-matter
+In the previous section, we covered the more general mechanism of the
+command ~denote-rename-file~ ([[#h:7cc9e000-806a-48da-945c-711bbc7426b0][Rename a single file]]).  There is also a
+way to have the same outcome by making Denote read the data in the
+current file's front matter and use it to construct/update the file
+name.  The command for this is ~denote-rename-file-using-front-matter~.
+It is only relevant for files that (i) are among the supported file
+types, per ~denote-file-type~, and (ii) have the requisite front matter
+in place.
+
+Suppose you have an =.org= file with this front matter ([[#h:13218826-56a5-482a-9b91-5b6de4f14261][Front matter]]):
+
+#+begin_example
+#+title:      My sample note file
+#+date:       [2022-08-05 Fri 13:10]
+#+filetags:   :testing:
+#+identifier: 20220805T131044
+#+end_example
+
+Its file name reflects this information:
+
+: 20220805T131044--my-sample-note-file__testing.org
+
+You want to change its title and keywords manually, so you modify it thus:
+
+#+begin_example
+#+title:      My modified sample note file
+#+date:       [2022-08-05 Fri 13:10]
+#+filetags:   :testing:denote:emacs:
+#+identifier: 20220805T131044
+#+end_example
+
+At this stage, the file name still shows the old title and keywords.
+You now invoke ~denote-rename-file-using-front-matter~ and it updates
+the file name to:
+
+: 20220805T131044--my-modified-sample-note-file__testing_denote_emacs.org
+
+By default, the renaming is subject to a "yes or no" prompt that shows
+the old and new names, just so the user is certain about the change.
+Though this can be modified ([[#h:a2ae9090-c49e-4b32-bcf5-eb8944241fd7][The ~denote-rename-confirmations~ option]]).
+
+The identifier of the file, if any, is never modified even if it is
+edited in the front matter: Denote considers the file name to be the
+source of truth in this case, to avoid potential breakage with typos and
+the like.
+
+This command constructs the file name in accordance with the user option
+~denote-file-name-components-order~ ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+** Rename multiple files interactively
+:PROPERTIES:
+:CUSTOM_ID: h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde
+:END:
+
+#+findex: denote-dired-rename-files
+#+findex: denote-dired-rename-marked-files
+The command ~denote-dired-rename-files~ (alias ~denote-dired-rename-marked-files~)
+renames the files that are marked in a Dired buffer. Its behaviour is
+similar to the ~denote-rename-file~ in that it prompts for a title,
+keywords, and signature ([[#h:7cc9e000-806a-48da-945c-711bbc7426b0][Rename a single file]]). It does so over each
+marked file, renaming one after the other.
+
+Unlike ~denote-rename-file~, the command ~denote-dired-rename-files~
+does not ask to confirm the changes made to the files: it performs
+them outright (same as setting ~denote-rename-confirmations~ to a nil
+value). This is done to make it easier to rename multiple files
+without having to confirm each step. For an even more direct approach,
+check the command ~denote-dired-rename-marked-files-with-keywords~.
+
+- [[#h:f365ff7e-2140-4e14-a92f-666ae97382a4][Rename by writing only keywords]]
+- [[#h:ea5673cd-e6ca-4c42-a066-07dc6c9d57f8][Rename multiple files based on their front matter]]
+
+** Rename multiple files at once by asking only for keywords
+:PROPERTIES:
+:CUSTOM_ID: h:f365ff7e-2140-4e14-a92f-666ae97382a4
+:END:
+
+#+findex: denote-dired-rename-marked-files-with-keywords
+The ~denote-dired-rename-marked-files-with-keywords~ command renames
+marked files in Dired to conform with our file-naming scheme. It does
+so by writing keywords to them. Specifically, it does the following:
+
+- retains the file's existing name and makes it the =TITLE= field, per
+  Denote's file-naming scheme;
+
+- sluggifies the =TITLE= and adjusts its letter casing, according to
+  our conventions;
+
+- prepends an identifier to the =TITLE=, if one is missing;
+
+- preserves the file's extension, if any;
+
+- prompts once for =KEYWORDS= and applies the user's input to the
+  corresponding field in the file name, rewriting any keywords that
+  may exist while removing keywords that do exist if =KEYWORDS= is
+  empty;
+
+- adds or rewrites existing front matter to the underlying file, if it
+  is recognized as a Denote note (per the ~denote-file-type~ user
+  option), such that it includes the new keywords.
+
+[ Note that the affected buffers are not saved, unless the user option
+  ~denote-rename-no-confirm~ is non-nil. Users can thus check them to
+  confirm that the new front matter does not cause any problems (e.g.
+  with the ~diff-buffer-with-file~ command). Multiple buffers can be
+  saved in one go with the command ~save-some-buffers~ (read its doc
+  string). ]
+
+Construct the file name in accordance with the user option
+~denote-file-name-components-order~ ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+Run the ~denote-after-rename-file-hook~ after the renaming is done.
+
+#+findex: denote-dired-rename-marked-files-add-keywords
+#+findex: denote-dired-rename-marked-files-remove-keywords
+For more specialized versions of this command that only add or remove
+keywords, use ~denote-dired-rename-marked-files-add-keywords~ and
+~denote-dired-rename-marked-files-remove-keywords~, respectively.
+
+** Rename multiple files based on their front matter
+:PROPERTIES:
+:CUSTOM_ID: h:ea5673cd-e6ca-4c42-a066-07dc6c9d57f8
+:END:
+
+#+findex: denote-dired-rename-marked-files-using-front-matter
+As already noted, Denote can rename a file based on the data in its
+front matter ([[#h:3ab08ff4-81fa-4d24-99cb-79f97c13a373][Rename a single file based on its front matter]]).  The
+command ~denote-dired-rename-marked-files-using-front-matter~ extends
+this principle to a batch operation which applies to all marked files in
+Dired.
+
+Marked files must count as notes for the purposes of Denote, which
+means that they at least have an identifier in their file name and use
+a supported file type, per ~denote-file-type~. Files that do not meet
+this criterion are ignored, because Denote cannot know if they have
+front matter and what that may be. For such files, it is still
+possible to rename them interactively ([[#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde][Rename multiple files interactively]]).
+
+** Rename a file by changing only its file type
+:PROPERTIES:
+:CUSTOM_ID: h:85b65995-89fd-4978-bba3-7bb6c8d6f945
+:END:
+
+#+findex: denote-change-file-type-and-front-matter
+The command ~denote-change-file-type-and-front-matter~ provides the
+convenience of converting a note taken in one file type, say, =.txt=
+into another like =.org=. It presents a choice among the
+~denote-file-type~ options.
+
+The conversion does NOT modify the existing front matter.  Instead, it
+prepends new front matter to the top of the file.  We do this as a
+safety precaution since the user can, in principle, add arbitrary
+extras to their front matter that we would not want to touch.
+
+If in Dired, ~denote-change-file-type-and-front-matter~ operates on the
+file at point, else the current file, else it prompts with minibuffer
+completion for one.
+
+The title of the file is retrieved from a line starting with a title
+field in the file's front matter, depending on the previous file type
+(e.g.  =#+title= for Org).  The same process applies for keywords.
+
+As a final step, the command asks for confirmation, showing the
+difference between old and new file names.
+
+This command constructs the file name in accordance with the user option
+~denote-file-name-components-order~ ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+** Rename a file by adding or removing a title interactively
+:PROPERTIES:
+:CUSTOM_ID: h:a26e28c7-8222-4377-92e9-3b0a709010a5
+:END:
+
+#+findex: denote-rename-file-title
+The command ~denote-rename-file-title~ streamlines the process of
+interactively adding or removing a title to/from a file, while
+changing its file name accordingly. It asks for a title using the
+familiar minibuffer prompt ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]). It then renames
+the file. The command respect the values of
+~denote-rename-confirmations~ and ~denote-save-buffers~:
+
+- [[#h:a2ae9090-c49e-4b32-bcf5-eb8944241fd7][The ~denote-rename-confirmations~ option]].
+- [[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffers~ option]].
+
+Technically, ~denote-rename-file-title~ is a wrapper for
+~denote-rename-file~, doing all the things that does ([[#h:7cc9e000-806a-48da-945c-711bbc7426b0][Rename a single file]]).
+
+Concretely, this command can add or remove a title in one go. It
+does it by prepopulating the minibuffer prompt with the existing
+title. Users can then modify it. An empty input means to remove
+the title altogether ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input. The Emacs default setup accepts the empty
+  minibuffer contents as they are, though popular packages like
+  ~vertico~ use the first available completion candidate instead. For
+  ~vertico~, the user must either move one up to select the prompt and
+  then type =RET= there with empty contents, or use the command
+  ~vertico-exit-input~ with empty contents. That Vertico command is
+  bound to =M-RET= as of this writing on 2024-06-30 10:37 +0300. ]
+
+** Rename a file by adding or removing keywords interactively
+:PROPERTIES:
+:CUSTOM_ID: h:ad4dde4a-8e88-470a-97ae-e7b9d4b41fb4
+:END:
+
+#+findex: denote-rename-file-keywords
+The command ~denote-rename-file-keywords~ streamlines the process of
+interactively adding or removing keywords to a file, while changing
+its file name and front matter accordingly. It asks for keywords using
+the familiar minibuffer prompt ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]). It then
+renames the file ([[#h:3ab08ff4-81fa-4d24-99cb-79f97c13a373][Rename a single file based on its front matter]]).
+The command respect the values of ~denote-rename-confirmations~ and
+~denote-save-buffers~:
+
+- [[#h:a2ae9090-c49e-4b32-bcf5-eb8944241fd7][The ~denote-rename-confirmations~ option]].
+- [[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffers~ option]].
+
+Technically, ~denote-rename-file-keywords~ is a wrapper for
+~denote-rename-file~, doing all the things that does ([[#h:7cc9e000-806a-48da-945c-711bbc7426b0][Rename a single file]]).
+
+Concretely, this command can add or remove keywords in one go. It does
+it by prepopulating the minibuffer prompt with the existing keywords.
+Users can then use the ~crm-separator~ (normally a comma), to write
+new keywords or edit what is in the prompt to rewrite them
+accordingly. An empty input means to remove all keywords ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input. The Emacs default setup accepts the empty
+  minibuffer contents as they are, though popular packages like
+  ~vertico~ use the first available completion candidate instead. For
+  ~vertico~, the user must either move one up to select the prompt and
+  then type =RET= there with empty contents, or use the command
+  ~vertico-exit-input~ with empty contents. That Vertico command is
+  bound to =M-RET= as of this writing on 2024-06-30 10:37 +0300. ]
+
+** Rename a file by adding or removing a signature interactively
+:PROPERTIES:
+:CUSTOM_ID: h:b08a350f-b269-47ed-8c2a-b8ecf1b63c7f
+:END:
+
+#+findex: denote-rename-file-signature
+The command ~denote-rename-file-signature~ streamlines the process of
+interactively adding or removing a signature to/from a file, while
+changing its file name accordingly. It asks for a signature using the
+familiar minibuffer prompt ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]). It then renames
+the file. The command respect the values of
+~denote-rename-confirmations~ and ~denote-save-buffers~:
+
+- [[#h:a2ae9090-c49e-4b32-bcf5-eb8944241fd7][The ~denote-rename-confirmations~ option]].
+- [[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffers~ option]].
+
+Technically, ~denote-rename-file-signature~ is a wrapper for
+~denote-rename-file~, doing all the things that does ([[#h:7cc9e000-806a-48da-945c-711bbc7426b0][Rename a single file]]).
+
+Concretely, this command can add or remove a signature in one go. It
+does it by prepopulating the minibuffer prompt with the existing
+signature. Users can then modify it. An empty input means to remove
+the signature altogether ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input. The Emacs default setup accepts the empty
+  minibuffer contents as they are, though popular packages like
+  ~vertico~ use the first available completion candidate instead. For
+  ~vertico~, the user must either move one up to select the prompt and
+  then type =RET= there with empty contents, or use the command
+  ~vertico-exit-input~ with empty contents. That Vertico command is
+  bound to =M-RET= as of this writing on 2024-06-30 10:37 +0300. ]
+
+** Find duplicate identifiers and put them in a Dired buffer
+:PROPERTIES:
+:CUSTOM_ID: h:9051f15d-ea7e-4b17-adc2-bc6a749c721b
+:END:
+
+Denote takes care to create unique identifiers, though its mechanism
+relies on reading the existing identifiers in the ~denote-directory~
+or the current directory. When we are renaming files across different
+directories, there is a small chance that some files have the same
+attributes and are thus assigned identical identifiers. If those files
+ever make it into a consolidated ~denote-directory~, we will have
+duplicates, which break the linking mechanism.
+
+As this is an edge case, we do not include any code to address it in
+the Denote code base. Though here is a way to find duplicate
+identifiers inside the current directory:
+
+#+begin_src emacs-lisp
+(defun my-denote--get-files-in-dir (directory)
+  "Return file names in DIRECTORY."
+  (directory-files directory :full-paths directory-files-no-dot-files-regexp))
+
+(defun my-denote--same-identifier-p (file1 file2)
+  "Return non-nil if FILE1 and FILE2 have the same identifier."
+  (let ((id1 (denote-retrieve-filename-identifier file1))
+        (id2 (denote-retrieve-filename-identifier file2)))
+    (equal id1 id2)))
+
+(defun my-denote-find-duplicate-identifiers (directory)
+  "Find all files in DIRECTORY that need a new identifier."
+  (let* ((ids (my-denote--get-files-in-dir directory))
+         (unique-ids (seq-uniq ids #'my-denote--same-identifier-p)))
+    (seq-difference ids unique-ids #'equal)))
+
+(defun my-denote-dired-show-duplicate-identifiers (directory)
+  "Put duplicate identifiers from DIRECTORY in a dedicated Dired buffer."
+  (interactive
+   (list
+    (read-directory-name "Select DIRECTORY to check for duplicate identifiers: " default-directory)))
+  (if-let* ((duplicates (my-denote-find-duplicate-identifiers directory)))
+      (dired (cons (format "Denote duplicate identifiers" directory) duplicates))
+    (message "No duplicates identifiers in `%s'" directory)))
+#+end_src
+
+Evaluate this code and then call the command ~my-denote-dired-show-duplicate-identifiers~.
+If there are duplicates, it will put them in a dedicated Dired buffer.
+From there, you can view the file contents as usual, and manually edit
+the identifiers as you see fit (e.g. edit them one by one, or change
+to the writable Dired and record a keyboard macro that makes use of a
+counter to increment by 1---contact me if you need any help).
+
+** Faces used by rename commands
+:PROPERTIES:
+:CUSTOM_ID: h:ab3f355a-f763-43ae-a4c9-179d2d9265a5
+:END:
+
+These are the faces used by the various Denote rename commands to
+style or highlight the old/new/current file shown in the relevant
+minibuffer prompts:
+
+- ~denote-faces-prompt-current-name~
+- ~denote-faces-prompt-new-name~
+- ~denote-faces-prompt-old-name~
+
+* The file-naming scheme
+:PROPERTIES:
+:CUSTOM_ID: h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d
+:END:
+
+#+vindex: denote-directory
+Notes are stored in the ~denote-directory~.  The default path is
+=~/Documents/notes=.  The ~denote-directory~ can be a flat listing,
+meaning that it has no subdirectories, or it can be a directory tree.
+Either way, Denote takes care to only consider "notes" as valid
+candidates in the relevant operations and will omit other files or
+directories.
+
+Every note produced by Denote follows this pattern by default
+([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]):
+
+: DATE==SIGNATURE--TITLE__KEYWORDS.EXTENSION
+
+The =DATE= field represents the date in year-month-day format followed
+by the capital letter =T= (for "time") and the current time in
+hour-minute-second notation.  The presentation is compact:
+=20220531T091625=.  The =DATE= serves as the unique identifier of each
+note and, as such, is also known as the file's ID or identifier.
+
+File names can include an arbitrary string of alphanumeric characters
+in the =SIGNATURE= field. Signatures have no clearly defined purpose
+and are up to the user to define. They can serve as special labels,
+such as =part1= and =part2= of a large file, or as priority indicators
+like =a=, =b=, =c=, or even context/scope specifiers like =home= and
+=work=. Another use-case is to write sequences of thoughts, such that
+notes form a hierarchy, something we support with the optional and
+comprehensive extension =denote-sequence.el= ([[#h:d5ca722d-e7fa-46fa-9a57-6363b1d4186f][Write sequence notes or "folgezettel"]]).
+Signatures are an optional extension to Denote's file-naming scheme.
+In the simplest form, they can be added to newly created files on
+demand, with the command ~denote-signature~, or by modifying the value
+of the user option ~denote-prompts~ ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The ~denote-prompts~ option]]).
+
+The =TITLE= field is the title of the note, as provided by the user.
+It automatically gets downcased by default and is also hyphenated
+([[#h:ae8b19a1-7f67-4258-96b3-370a72c43f4e][Sluggification of file name components]]).  An entry about "Economics
+in the Euro Area" produces an =economics-in-the-euro-area= string for
+the =TITLE= of the file name.
+
+The =KEYWORDS= field consists of one or more entries demarcated by an
+underscore (the separator is inserted automatically).  Each keyword is
+a string provided by the user at the relevant prompt which broadly
+describes the contents of the entry.
+
+Each of the keywords is a single word, with multiple keywords providing
+the multi-dimensionality needed for advanced searches through Denote
+files.  Users who need to compose a keyword out of multiple words such
+as camelCase/CamelCase and are encouraged to use the
+~denote-file-name-slug-functions~ user option accordingly
+([[#h:ae8b19a1-7f67-4258-96b3-370a72c43f4e][Sluggification of file name components]]).
+
+#+vindex: denote-file-type
+The =EXTENSION= is the file type.  By default, it is =.org= (~org-mode~)
+though the user option ~denote-file-type~ provides support for Markdown
+with YAML or TOML variants (=.md= which runs ~markdown-mode~) and plain
+text (=.txt= via ~text-mode~).  Consult its doc string for the minutiae.
+While files end in the =.org= extension by default, the Denote code base
+does not actually depend on org.el and/or its accoutrements.
+
+Examples:
+
+: 20220610T043241--initial-thoughts-on-the-zettelkasten-method__notetaking.org
+: 20220610T062201--define-custom-org-hyperlink-type__denote_emacs_package.md
+: 20220610T162327--on-hierarchy-and-taxis__notetaking_philosophy.txt
+
+The different field separators, namely =--= and =__= introduce an
+efficient way to anchor searches (such as with Emacs commands like
+~isearch~ or from the command-line with ~find~ and related).  A query
+for =_word= always matches a keyword, while a regexp in the form of,
+say, ="\\([0-9T]+?\\)--\\(.*?\\)_"= captures the date in group =\1= and
+the title in =\2= (test any regular expression in the current buffer by
+invoking =M-x re-builder=).
+
+[[#h:1a953736-86c2-420b-b566-fb22c97df197][Features of the file-naming scheme for searching or filtering]].
+
+The ~denote-prompts~ can be configured in such ways to yield the
+following file name permutations:
+
+: DATE.EXT
+: DATE--TITLE.EXT
+: DATE__KEYWORDS.EXT
+: DATE==SIGNATURE.EXT
+: DATE==SIGNATURE--TITLE.EXT
+: DATE==SIGNATURE--TITLE__KEYWORDS.EXT
+: DATE==SIGNATURE__KEYWORDS.EXT
+
+When in doubt, stick to the default design, which is carefully
+considered and works well ([[#h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd][Change the order of file name components]]).
+
+While Denote is an Emacs package, notes should work long-term and not
+depend on the functionality of a specific program.  The file-naming
+scheme we apply guarantees that a listing is readable in a variety of
+contexts.  The Denote file-naming scheme is, in essence, an effective,
+low-tech invention.
+
+** Change the order of file name components
+:PROPERTIES:
+:CUSTOM_ID: h:dc8c40e0-233a-4991-9ad3-2cf5f05ef1cd
+:END:
+
+#+vindex: denote-file-name-components-order
+Our standard file-naming scheme prescribes a specific order for the
+file name components ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]). Though we provide the
+user option ~denote-file-name-components-order~ to let the user
+reorder them as they see fit.
+
+The value of this user option is a list of the following symbols:
+
+- ~identifier~: This is the combination of the date and time. When it
+  is the first on the list, it looks like =20240519T073456= and does
+  not have a component separator of its own due its unambiguous
+  format. When it is placed anywhere else in the file name, it is
+  prefixed with =@@=, so it looks like =@@20240519T073456=.
+
+- ~signature~: This is an arbitrary string that can be used to qualify
+  the file in some way, according to the user's methodology (e.g. to
+  add a sequence to notes). The string is always prefixed with the
+  ~==~ to remain unambiguous.
+
+- ~title~: This is an arbitrary string which describes the file. It is
+  always prefixed with =--= to be unambiguous.
+
+- ~keywords~: This is a series of one or more words that succinctly
+  group the file. Multiple keywords are separated by an underscore
+  prefixed to each of them. The file name component is always prefixed
+  with =__=.
+
+All four symbols must appear exactly once. Duplicates are ignored. Any
+missing symbol is added automatically.
+
+Some examples:
+
+#+begin_src emacs-lisp
+(setq denote-file-name-components-order '(identifier signature title keywords))
+;; => 20240519T07345==hello--this-is-the-title__denote_testing.org
+
+(setq denote-file-name-components-order '(signature identifier title keywords))
+;; => ==hello@@20240519T07345--this-is-the-title__denote_testing.org
+
+(setq denote-file-name-components-order '(title signature identifier keywords))
+;; => --this-is-the-title==hello@@20240519T07345__denote_testing.org
+
+(setq denote-file-name-components-order '(keywords title signature identifier))
+;; => __denote_testing--this-is-the-title==hello@@20240519T07345.org
+#+end_src
+
+Also see how to configure the Denote prompts, which affect which
+components are actually used in the order specified herein ([[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The ~denote-prompts~ option]]).
+
+Before deciding on this, please consider the longer-term implications
+of file names with varying patterns. Consistency makes things
+predictable and thus easier to find. So pick one order and never touch
+it again. When in doubt, leave the default file-naming scheme as-is.
+
+** Sluggification of file name components
+:PROPERTIES:
+:CUSTOM_ID: h:ae8b19a1-7f67-4258-96b3-370a72c43f4e
+:END:
+
+Files names can contain any character that the file system
+permits. Denote imposes a few additional restrictions:
+
++ The tokens "==", =__= and =--= are interpreted by Denote and should
+  appear only once.
+
++ The dot character is not allowed in a note's file name, except to
+  indicate the file type extension. Denote recognises two extensions
+  for encrypted files, like =.txt.gpg=.
+
+By default, Denote enforces other rules to file names through the user
+option ~denote-file-name-slug-functions~. These rules are applied to
+file names by default:
+
++ What we count as "illegal characters" are removed.
+
++ Input for a file title is hyphenated.  The original value is
+  preserved in the note's contents ([[#h:13218826-56a5-482a-9b91-5b6de4f14261][Front matter]]).
+
++ Spaces or other delimiters are removed from keywords, meaning that
+  =hello-world= becomes =helloworld=.  This is because hyphens in
+  keywords do not work everywhere, such as in Org. Plus, hyphens are
+  word separators in the title and we want to keep distinct separators
+  for each component to make search easier and semantic
+  ([[#h:1a953736-86c2-420b-b566-fb22c97df197][Features of the file-naming scheme for searching or filtering]]).
+
++ Signatures are like the above, but use the equals sign instead of
+  hyphens as a word separator.
+
++ All file name components are downcased. Further down we document how
+  to deviate from these rules, such as to accept input of the form
+  =helloWorld= or =HelloWorld= verbatim.
+
+Denote imposes these restrictions to enforce uniformity, which is
+helpful long-term as it keeps all files with the same predictable
+pattern. Too many permutations make searches more difficult to express
+accurately and be confident that the matches cover all files.
+Nevertheless, one of the principles of Denote is its flexibility or
+hackability and so users can deviate from the aforementioned
+([[#h:d375c6d2-92c7-425f-9d9d-219ff47ed2a3][User-defined sluggification of file name components]]).
+
+** User-defined sluggification of file name components
+:PROPERTIES:
+:CUSTOM_ID: h:d375c6d2-92c7-425f-9d9d-219ff47ed2a3
+:END:
+
+#+vindex: denote-file-name-slug-functions
+The user option ~denote-file-name-slug-functions~ controls the
+sluggification of file name components ([[#h:ae8b19a1-7f67-4258-96b3-370a72c43f4e][Sluggification of file name components]]).
+The default method is outlined above and in the previous section
+([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+The value of this user option is an alist where each element is a cons
+cell of the form =(COMPONENT . METHOD)=. For example, here is the
+default value:
+
+#+begin_example emacs-lisp
+'((title . denote-sluggify-title)
+  (signature . denote-sluggify-signature)
+  (keyword . denote-sluggify-keyword))
+#+end_example
+
+- The =COMPONENT= is an unquoted symbol among =title=, =signature=,
+  =keyword=, which refers to the corresponding component of the file
+  name.
+
+- The =METHOD= is a function to format the given component. This
+  function must take a string as its parameter and return the string
+  formatted for the file name. Note that even in the case of the
+  =keyword= component, the function receives one string representing a
+  single keyword and returns it formatted for the file name. Joining
+  the keywords together is handled internally by Denote.
+
+One commonly requested deviation from the sluggification rules is to
+not sluggify individual keywords, such that the user's input is taken
+as-is. This can be done as follows:
+
+#+begin_src emacs-lisp
+(setq denote-file-name-slug-functions
+      '((title . denote-sluggify-title)
+        (keyword . identity)
+        (signature . denote-sluggify-signature)))
+#+end_src
+
+The ~identity~ function simply returns the string it receives, thus
+not altering it in any way.
+
+Another approach is to keep the sluggification but not downcase the
+string. We can do this by modifying the original functions used by
+Denote. For example, we have this:
+
+#+begin_src emacs-lisp
+;; The original function for reference
+(defun denote-sluggify-title (str)
+  "Make STR an appropriate slug for title."
+  (downcase
+   (denote-slug-hyphenate
+    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" "" str))))
+
+;; Our variant of the above, which does the same thing except from
+;; downcasing the string.
+(defun my-denote-sluggify-title (str)
+  "Make STR an appropriate slug for title."
+  (denote-slug-hyphenate
+   (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" "" str)))
+
+;; Now we use our function to sluggify titles without affecting their
+;; letter casing.
+(setq denote-file-name-slug-functions
+      '((title . my-denote-sluggify-title) ; our function here
+        (signature . denote-sluggify-signature)
+        (keyword . denote-sluggify-keyword)))
+#+end_src
+
+Follow this principle for all the sluggification functions ([[#h:d1e4eb5b-e7f2-4a3b-9243-e1c653817a4a][Custom sluggification to remove non-ASCII characters]]).
+
+To access the source code, use either of the following built-in
+methods:
+
+1. Call the command ~find-library~ and search for ~denote~. Then
+   navigate to the symbol you are searching for.
+
+2. Invoke the command ~describe-symbol~, search for the symbol you are
+   interested in, and from the resulting Help buffer either click on
+   the first link or do =M-x help-view-source= (bound to =s= in Help
+   buffers, by default).
+
+Remember that deviating from the default file-naming scheme of Denote
+will make things harder to use in the future, as files can/will have
+permutations that create uncertainty. The sluggification scheme and
+concomitant restrictions we impose by default are there for a very
+good reason: they are the distillation of years of experience. Here we
+give you what you wish, but bear in mind it may not be what you need.
+You have been warned.
+
+*** Custom sluggification to remove non-ASCII characters
+:PROPERTIES:
+:CUSTOM_ID: h:d1e4eb5b-e7f2-4a3b-9243-e1c653817a4a
+:END:
+
+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
+problems with pattern matching, such as when searching through file
+names.
+
+By default, Denote does not remove Unicode characters because users
+may actually want them (e.g. Latin characters with accents). Those who
+do, however, wish to keep everything limited to the ASCII range can
+use the following in their Emacs configuration ([[#h:d375c6d2-92c7-425f-9d9d-219ff47ed2a3][User-defined sluggification of file name components]]).
+
+#+begin_src emacs-lisp
+;; These are the same as the default Denote sluggification functions,
+;; except they remove all non-ASCII characters.
+(defun my-denote-sluggify-title (str)
+  (downcase
+   (denote-slug-hyphenate
+    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" ""
+                              (denote-slug-keep-only-ascii str)))))
+
+(defun my-denote-sluggify-signature (str)
+  (downcase
+   (denote-slug-put-equals
+    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/-]*" ""
+                              (denote-slug-keep-only-ascii str)))))
+
+(defun my-denote-sluggify-keyword (str)
+  (downcase
+   (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/_ =-]*" ""
+                             (denote-slug-keep-only-ascii str))))
+
+(defcustom denote-file-name-slug-functions
+  '((title . my-denote-sluggify-title)
+    (signature . my-denote-sluggify-signature)
+    (keyword . my-denote-sluggify-keyword)))
+#+end_src
+
+** Features of the file-naming scheme for searching or filtering
+:PROPERTIES:
+:CUSTOM_ID: h:1a953736-86c2-420b-b566-fb22c97df197
+:END:
+
+By default, file names have three fields and two sets of field
+delimiters between them:
+
+: DATE--TITLE__KEYWORDS.EXTENSION
+
+When a signature is present, this becomes:
+
+: DATE==SIGNATURE--TITLE__KEYWORDS.EXTENSION
+
+Field delimiters practically serve as anchors for easier searching.
+Consider this example:
+
+: 20220621T062327==1a2--introduction-to-denote__denote_emacs.txt
+
+You will notice that there are two matches for the word =denote=: one
+in the title field and another in the keywords' field.  Because of the
+distinct field delimiters, if we search for =-denote= we only match
+the first instance while =_denote= targets the second one.  When
+sorting through your notes, this kind of specificity is
+invaluable---and you get it for free from the file names alone!
+Similarly, a search for ==1= will show all notes that are related to
+each other by virtue of their signature.
+
+Users can get a lot of value out of this simple yet effective
+arrangement, even if they have no knowledge of regular expressions.
+One thing to consider, for maximum effect, is to avoid using
+multi-word keywords as those can get hyphenated like the title and
+will thus interfere with the above: either set the user option
+~denote-allow-multi-word-keywords~ to nil or simply insert single
+words at the relevant prompts.
+
+* Front matter
+:PROPERTIES:
+:CUSTOM_ID: h:13218826-56a5-482a-9b91-5b6de4f14261
+:END:
+
+Notes have their own "front matter".  This is a block of data at the top
+of the file, with no empty lines between the entries, which is
+automatically generated at the creation of a new note.  The front matter
+includes the title and keywords (aka "tags" or "filetags", depending on
+the file type) which the user specified at the relevant prompt, as well
+as the date and unique identifier, which are derived automatically.
+
+This is how it looks for Org mode (when ~denote-file-type~ is nil or the
+=org= symbol):
+
+#+begin_example
+#+title:      This is a sample note
+#+date:       [2022-06-30 Thu 16:09]
+#+filetags:   :denote:testing:
+#+identifier: 20220630T160934
+#+end_example
+
+For Markdown with YAML (~denote-file-type~ has the =markdown-yaml=
+value), the front matter looks like this:
+
+#+begin_example
+---
+title:      "This is a sample note"
+date:       2022-06-30T16:09:58+03:00
+tags:       ["denote", "testing"]
+identifier: "20220630T160958"
+---
+#+end_example
+
+For Markdown with TOML (~denote-file-type~ has the =markdown-toml=
+value), it is:
+
+#+begin_example
++++
+title      = "This is a sample note"
+date       = 2022-06-30T16:10:13+03:00
+tags       = ["denote", "testing"]
+identifier = "20220630T161013"
++++
+#+end_example
+
+And for plain text (~denote-file-type~ has the =text= value), we have
+the following:
+
+#+begin_example
+title:      This is a sample note
+date:       2022-06-30
+tags:       denote  testing
+identifier: 20220630T161028
+---------------------------
+#+end_example
+
+#+vindex: denote-date-format
+The format of the date in the front matter is controlled by the user
+option ~denote-date-format~.  When nil, Denote uses a file-type-specific
+format:
+
+- For Org, an inactive timestamp is used, such as
+  =[2022-06-30 Wed 15:31]=.
+
+- For Markdown, the RFC3339 standard is applied:
+  =2022-06-30T15:48:00+03:00=.
+
+- For plain text, the format is that of ISO 8601: =2022-06-30=.
+
+If the value is a string, ignore the above and use it instead.  The
+string must include format specifiers for the date.  These are described
+in the doc string of ~format-time-string~..
+
+** Change the front matter format
+:PROPERTIES:
+:CUSTOM_ID: h:7f918854-5ed4-4139-821f-8ee9ba06ad15
+:END:
+
+Per Denote's design principles, the code is hackable.  All front matter
+is stored in variables that are intended for public use.  We do not
+declare those as "user options" because (i) they expect the user to have
+some degree of knowledge in Emacs Lisp and (ii) implement custom code.
+
+[ NOTE for tinkerers: code intended for internal use includes double
+  hyphens in its symbol.  "Internal use" means that it can be changed
+  without warning and with no further reference in the change log.  Do
+  not use any of it without understanding the consequences. ]
+
+The variables which hold the front matter format are:
+
+#+vindex: denote-org-front-matter
+- ~denote-org-front-matter~
+
+#+vindex: denote-text-front-matter
+- ~denote-text-front-matter~
+
+#+vindex: denote-toml-front-matter
+- ~denote-toml-front-matter~
+
+#+vindex: denote-yaml-front-matter
+- ~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
+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.
+
+When editing the value, make sure to:
+
+1. Not use empty lines inside the front matter block.
+
+2. Insert at least one empty line after the front matter block and do
+   not use any empty line before it.
+
+These help with consistency and might prove useful if we ever need to
+operate on the front matter as a whole.
+
+With those granted, below are some examples.  The approach is the same
+for all variables.
+
+#+begin_src emacs-lisp
+;; Like the default, but upcase the entries
+(setq denote-org-front-matter
+  "#+TITLE:      %s
+#+DATE:       %s
+#+FILETAGS:   %s
+#+IDENTIFIER: %s
+\n")
+
+;; Change the order (notice the %N$s notation)
+(setq denote-org-front-matter
+  "#+title:      %1$s
+#+filetags:   %3$s
+#+date:       %2$s
+#+identifier: %4$s
+\n")
+
+;; Remove the date
+(setq denote-org-front-matter
+  "#+title:      %1$s
+#+filetags:   %3$s
+#+identifier: %4$s
+\n")
+
+;; Remove the date and the identifier
+(setq denote-org-front-matter
+  "#+title:      %1$s
+#+filetags:   %3$s
+\n")
+#+end_src
+
+Note that ~setq~ has a global effect: it affects the creation of all new
+notes.  Depending on the workflow, it may be preferrable to have a
+custom command which ~let~ binds the different format.  We shall not
+provide examples at this point as this is a more advanced feature and we
+are not yet sure what the user's needs are.  Please provide feedback and
+we shall act accordingly.
+
+** Regenerate front matter
+:PROPERTIES:
+:CUSTOM_ID: h:54b48277-e0e5-4188-ad54-ef3db3b7e772
+:END:
+
+As part of version 4.0.0, the command ~denote-add-front-matter~ is
+superseded by ~denote-rename-file~ and related ([[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]). Those
+commands will add missing front matter or rewrite the modified lines
+of existing front matter.
+
+* Linking notes
+:PROPERTIES:
+:CUSTOM_ID: h:fc913d54-26c8-4c41-be86-999839e8ad31
+:END:
+
+Denote offers several commands for linking between notes. Those use
+the =denote:= hyperlink type. There are two types of links supported
+by Denote:
+
+- Direct links :: A direct link points to a file inside the
+  ~denote-directory~. The link is constructed by using the =denote:=
+  prefix and the target file's identifier ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+  This looks like =denote:20250328T075526=. The syntax of a link
+  depends on the file type. For example, in Org and plain text links look like
+  =[[denote:20250328T075526][The title of the target file]]=, while in
+  Markdown they are written as =[The title of the target file](denote:20250328T075526)=.
+
+- Query links :: The =denote:= hyperlink type also supports special
+  qualifiers that change how the target of the link is interpreted.
+  The qualifier is a special token than tells Denote how to treat the
+  target of the link. It is written thus =denote:TOKEN:QUERY=. There
+  are two kinds of tokens: =query-contents= and =query-filenames=.
+  Those determine how the query terms are used. As their names
+  suggest, these two tokens trigger a search in (i) the file contents
+  of all readable files or (ii) in the file names only. They are, in
+  other words, counterparts of the Unix ~grep~ and ~find~ programs,
+  respectively.
+
+The following sections cover all the details ([[#h:4f354db1-aa78-47fd-ac60-c3d1e0f0b0a4][Why are some Org links opening outside Emacs?]]).
+
+** Add a single direct link using a file name prompt
+:PROPERTIES:
+:CUSTOM_ID: h:5e5e3370-12ab-454f-ba09-88ff44214324
+:END:
+
+#+findex: denote-link
+#+findex: denote-insert-link
+The ~denote-link~ command (alias ~denote-insert-link~) inserts a link
+at point to a file selected at the minibuffer prompt. Links are
+formatted depending on the file type of the current note. In Org and
+plain text buffers, links are formatted thus: =[[denote:IDENTIFIER][DESCRIPTION]]=.
+While in Markdown they are expressed as =[DESCRIPTION](denote:IDENTIFIER)=.
+
+When ~denote-link~ is called with a prefix argument (=C-u= by
+default), it formats links like =[[denote:IDENTIFIER]]=, regardless of
+file type ([[#h:156c5ea3-147b-4f9d-a404-86a00558c60a][Fontify links in non-Org buffers]]). The user might prefer
+its simplicity.
+
+By default, the description of the link is determined thus:
+
+- If the region is active, its text becomes the description of the
+  link. In other words, the region text becomes the link.
+- If the region is active but has no text, the description is empty
+  and so the link is formatted the same way as if using the =C-u=
+  prefix argument.
+- If there is no region active, the description consists of the target
+  file's signature and title, using the former only if it is present.
+  The title is retrieved either from the front matter or the file
+  name.
+- If the target file has no signature, the title is used.
+
+To insert multiple such links at once, use the command
+~denote-add-links~ ([[#h:9bec2c83-36ca-4951-aefc-7187c5463f90][Insert links matching a regexp in their file name]]).
+
+If you want to directly link to a single file whose contents match a
+given query, then use the command ~denote-link-to-file-with-contents~
+([[#h:25a983ca-049e-43d4-8f6e-06a2325e2c3c][Adding a direct link to a file whose contents include the given query]]).
+
+#+vindex: denote-faces-link
+Links are styled with the ~denote-faces-link~ face, which looks
+exactly like an ordinary link by default.
+
+[ We optionally support direct links to a file followed by an extra
+  target to an Org headings ([[#h:d99de1fb-b1b7-4a74-8667-575636a4d6a4][The ~denote-org-store-link-to-heading~ user option]]).
+  Other file types do not have the features of Org, so we cannot
+  generalise this. ]
+
+** Add a direct link to a file whose contents include the given query
+:PROPERTIES:
+:CUSTOM_ID: h:25a983ca-049e-43d4-8f6e-06a2325e2c3c
+:END:
+
+#+findex: denote-link-to-file-with-contents
+The ~denote-link~ command that we covered before prompts to select a
+file among those in the ~denote-directory~ ([[#h:5e5e3370-12ab-454f-ba09-88ff44214324][Adding a single direct link using a file name prompt]]).
+The match is done against the file's name. Users may, however, be
+interested to create a link to a file whose contents include some
+text, regardless of how the file name is called. To this end, the
+command ~denote-link-to-file-with-contents~, (i) prompts for a query
+which is a plain string or regular expression, (ii) if there are
+matching files, asks to select one among them, and (iii) inserts the
+direct link at point.
+
+When called with an optional prefix argument (=C-u= by default), the
+command ~denote-link-to-file-with-contents~ creates a link that does
+not include a description for the target file: it just has the file's
+identifier (same as with ~denote-link~).
+
+The command ~denote-link-to-file-with-contents~ is the counterpart of
+~denote-link-to-all-files-with-contents~ ([[#h:299d3aeb-9946-489e-bd91-e06f8c4ae2a9][Insert links to all files matching a query in their contents]]).
+
+** Add a query link
+:PROPERTIES:
+:CUSTOM_ID: h:d9a84289-2f73-4ef9-b4f0-9a0aa3e9bf0d
+:END:
+
+As noted in the introduction to this section of the manual, the
+=denote:= hyperlink type supports query links ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]). Unlike
+direct links, they do not point to any given file. Instead, they
+trigger a search, whose results are displayed in a separate buffer.
+
+Query links are expressed as =denote:TOKEN:QUERY=, where =TOKEN= is
+either =query-contents= or =query-filenames=, while =QUERY= is a
+string or Emacs regular expression to search for.
+
+The exact syntax of a query link depends on the file type. In Org and
+plain text buffers, links are of the form =[[denote:TOKEN:QUERY][QUERY]]=.
+In Markdown, they are formatted as  =[QUERY](denote:TOKEN:QUERY)=. In
+all cases, the description of the link is the query text itself.
+
+#+findex: denote-query-contents-link
+The command ~denote-query-contents-link~ inserts a link at point that
+triggers a search in the file contents of all readable documents in
+the ~denote-directory~ ([[#h:435592bc-e896-429f-a599-9f1bcd5ab9b8][Interact with the links buffer]]). This is the
+equivalent of the Unix ~grep~ command and uses the built-in Emacs Xref
+interface ([[#h:893eec49-d7be-4603-bcff-fcc247244011][Speed up backlinks' or query links' buffer creation?]]).
+Matches are displayed in a separate buffer, highlighting the exact
+text while showing its context.
+
+#+findex: denote-query-filenames-link
+The command ~denote-query-filenames-link~ creates a link at point that
+initiates a search across file names in the ~denote-directory~. This
+is the equivalent of the Unix ~find~ command. Results are placed in a
+Dired buffer ([[#h:9fe01e63-f34f-4479-8713-f162a5ca865e][Display filtered and sorted files with ~denote-sort-dired~]]).
+
+#+vindex: denote-query-links-display-buffer-action
+The user option ~denote-query-links-display-buffer-action~ controls
+the placement of query link buffers. By default, they are designed to
+appear below the current window.
+
+#+vindex: denote-faces-query-link
+Query links are styled with the ~denote-faces-query-link~ face, which
+looks a bit different that ~denote-faces-link~ (though this depends on
+the active theme).
+
+** Insert links to all files matching a query in their file name
+:PROPERTIES:
+:CUSTOM_ID: h:9bec2c83-36ca-4951-aefc-7187c5463f90
+:END:
+
+#+findex: denote-add-links
+The command ~denote-add-links~ adds links at point to all file names
+in the ~denote-directory~ that match a regular expression or plain
+string. This is similar to the ~denote-link~ command, which
+establishes a direct link to a specified file ([[#h:5e5e3370-12ab-454f-ba09-88ff44214324][Adding a single direct link]]).
+Links to files whose names match the given search terms are inserted
+as a typographic list, such as:
+
+#+begin_example
+- link1
+- link2
+- link3
+#+end_example
+
+Each link is formatted according to the file type of the current note,
+as explained further above about the ~denote-link~ command.  The current
+note is excluded from the matching entries (adding a link to itself is
+pointless).
+
+When called with a prefix argument (=C-u=) ~denote-add-links~ will
+format all links as =[[denote:IDENTIFIER]]=, hence a typographic list:
+
+#+begin_example
+- [[denote:IDENTIFIER-1]]
+- [[denote:IDENTIFIER-2]]
+- [[denote:IDENTIFIER-3]]
+#+end_example
+
+Same examples of a regular expression that can be used with this
+command:
+
+- =journal= match all files which include =journal= anywhere in their
+  name.
+
+- =_journal= match all files which include =journal= as a keyword.
+
+- =^2022.*_journal= match all file names starting with =2022= and
+  including the keyword =journal=.
+
+- =\.txt= match all files including =.txt=.  In practical terms, this
+  only applies to the file extension, as Denote automatically removes
+  dots (and other characters) from the base file name.
+
+If files are created with ~denote-sort-keywords~ as non-nil (the
+default), then it is easy to write a regexp that includes multiple
+keywords in alphabetic order:
+
+- =_denote.*_package= match all files that include both the =denote= and
+  =package= keywords, in this order.
+
+- =\(.*denote.*package.*\)\|\(.*package.*denote.*\)= is the same as
+  above, but out-of-order.
+
+Remember that regexp constructs only need to be escaped once (like =\|=)
+when done interactively but twice when called from Lisp.  What we show
+above is for interactive usage.
+
+Links are created only for files which qualify as a "note" for our
+purposes ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]).
+
+** Insert links to all files matching a query in their contents
+:PROPERTIES:
+:CUSTOM_ID: h:299d3aeb-9946-489e-bd91-e06f8c4ae2a9
+:END:
+
+#+findex: denote-link-to-all-files-with-contents
+The aforementioned ~denote-add-links~ command takes a query that
+matches it against file names ([[#h:9bec2c83-36ca-4951-aefc-7187c5463f90][Insert links to all files matching a query in their file name]]).
+It then creates a typographic list (bullet list) with direct links to
+all the matching files. Users who wish to achieve the same result but
+have the query be matched against file contents (not file names), can
+use the command ~denote-link-to-all-files-with-contents~.
+
+The command ~denote-link-to-all-files-with-contents~ is the
+counterpart of ~denote-link-to-file-with-contents~ ([[#h:25a983ca-049e-43d4-8f6e-06a2325e2c3c][Add a direct link to a file whose contents include the given query]]).
+
+** The ~denote-open-link-function~ user option
+:PROPERTIES:
+:CUSTOM_ID: h:6aa22a2d-3338-433e-ab9f-ba272417aab9
+:END:
+
+#+vindex: denote-open-link-function
+The user option ~denote-open-link-function~ specifies the function
+used by Denote to open the file of a link. The default value opens the
+file in the other window. Another common value is the function
+~find-file~, which will open the file in the current window. Users may
+also specify a function of their choosing.
+
+Note that this is relevant in buffers other than Org mode because Org
+has its own mechanism for how to open links (read the documentation of
+the command ~org-open-at-point~).
+
+** The ~denote-org-store-link-to-heading~ user option
+:PROPERTIES:
+:CUSTOM_ID: h:d99de1fb-b1b7-4a74-8667-575636a4d6a4
+:END:
+
+#+vindex: denote-org-store-link-to-heading
+The user option ~denote-org-store-link-to-heading~ determines whether
+~org-store-link~ links to the current Org heading.
+
+[ Remember that what ~org-store-link~ does is merely collect a link.  To
+  actually insert it, use the command ~org-insert-link~.  Note that
+  ~org-capture~ uses ~org-store-link~ internally when it needs to store
+  a link.  ]
+
+When the value is nil, the Denote handler for ~org-store-link~ produces
+links only to the current file (by using the file's identifier).  For
+example:
+
+: [[denote:20240118T060608][Some test]]
+
+If the value is ~context~, the link consists of the file's identifier
+and the text of the current heading, like this:
+
+: [[denote:20240118T060608::*Heading text][Some test::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.
+
+If the value is ~id~ or, for backward-compatibility, any other non-nil
+value, then Denote will use the standard Org mechanism of the
+=CUSTOM_ID= property to create a unique link to the heading. If the
+heading does not have a =CUSTOM_ID=, it creates it and includes it in
+its =PROPERTIES= drawer. If a =CUSTOM_ID= exists, it takes it as-is.
+The result is like this:
+
+ : [[denote:20240118T060608::#h:eed0fb8e-4cc7-478f][Some test::Heading text]]
+
+The value of the =CUSTOM_ID= is determined by the Org user option
+~org-id-method~. The sample shown above uses the default UUID
+infrastructure (though I deleted a few characters to not get
+complaints from the byte compiler about long lines in the doc
+string...).
+
+Note that this option does not affect how Org behaves with regard to
+~org-id-link-to-org-use-id~. If that user option is set to create =ID=
+properties, then those will be created by Org even if the Denote link
+handler will take care to not use/store the =ID= value. Concretely,
+users who never want =ID= properties under their headings should keep
+~org-id-link-to-org-use-id~ in its nil value.
+
+Context links are easier to break than those with a =CUSTOM_ID= in
+cases where either the heading text changes or there is another
+heading that matches that text. The potential advantage of context
+links is that they do not require a =PROPERTIES= drawer.
+
+When visiting a link to a heading, Org opens the Denote file and then
+navigates to that heading.
+
+[ This feature only works in Org mode files, as other file types do
+  not have a linking mechanism that handles unique identifiers for
+  headings or other patterns to jump to. If ~org-store-link~ is
+  invoked in one such file, it captures only the Denote identifier of
+  the file, even if this user option is set to a non-nil value. ]
+
+** Adding direct links to files matching contents
+:PROPERTIES:
+:CUSTOM_ID: h:28cb8d14-cf56-4d73-b126-8ff269dbaa64
+:END:
+
+** Insert links from marked files in Dired
+:PROPERTIES:
+:CUSTOM_ID: h:9cbb692e-5d8a-44a6-9193-899a07872a07
+:END:
+
+#+findex: denote-link-dired-marked-notes
+The command ~denote-link-dired-marked-notes~ is similar to
+~denote-add-links~ in that it inserts in the buffer a typographic list
+of links to Denote notes ([[#h:9bec2c83-36ca-4951-aefc-7187c5463f90][Insert links matching a regexp]]).  Though
+instead of reading a regular expression, it lets the user mark files
+in Dired and link to them.  This should be easier for users of all
+skill levels, instead of having to write a potentially complex regular
+expression.
+
+If there are multiple buffers that visit a Denote note, this command
+will ask to select one among them, using minibuffer completion.  If
+there is only one buffer, it will operate in it outright.  If there are
+no buffers, it will produce an error.
+
+With optional =ID-ONLY= as a prefix argument (=C-u= by default), the
+command inserts links with just the identifier, which is the same
+principle as with ~denote-link~ and others ([[#h:5e5e3370-12ab-454f-ba09-88ff44214324][Adding a single link]]).
+
+The command ~denote-link-dired-marked-notes~ is meant to be used from a
+Dired buffer.
+
+As always, links are created only for files which qualify as a "note"
+for our purposes ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]).
+
+#+findex: denote-dired-link-marked-notes
+The ~denote-dired-link-marked-notes~ is an alias for ~denote-link-dired-marked-notes~.
+
+** Link to an existing note or create a new one
+:PROPERTIES:
+:CUSTOM_ID: h:b6056e6b-93df-4e6b-a778-eebd105bac46
+:END:
+
+In one's note-taking workflow, there may come a point where they are
+expounding on a certain topic but have an idea about another subject
+they would like to link to ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]).  The user can always rely on
+the other linking facilities we have covered herein to target files that
+already exist.  Though they may not know whether they already have notes
+covering the subject or whether they would need to write new ones.  To
+this end, Denote provides two convenience commands:
+
+#+findex: denote-link-after-creating
++ ~denote-link-after-creating~ :: Create new note in the background and
+  link to it directly.
+
+  Use ~denote~ interactively to produce the new note.  Its doc string or
+  this manual explains which prompts will be used and under what
+  conditions ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]).
+
+  With optional =ID-ONLY= as a prefix argument (this is the =C-u= key,
+  by default) create a link that consists of just the identifier.  Else
+  try to also include the file's title.  This has the same meaning as in
+  ~denote-link~ ([[#h:5e5e3370-12ab-454f-ba09-88ff44214324][Adding a single link]]).
+
+  IMPORTANT NOTE: Normally, ~denote~ does not save the buffer it
+  produces for the new note ([[#h:bf80f4cd-6f56-4f7c-a991-8573161e4511][The ~denote-save-buffer-after-creation~ option]]).
+  This is a safety precaution to not write to disk unless the user
+  wants it (e.g. the user may choose to kill the buffer, thus
+  cancelling the creation of the note). However, for this command the
+  creation of the note happens in the background and the user may miss
+  the step of saving their buffer. We thus have to save the buffer in
+  order to (i) establish valid links, and (ii) retrieve whatever front
+  matter from the target file.
+
+#+findex: denote-link-after-creating-with-command
++ ~denote-link-after-creating-with-command~ :: This command is like
+  ~denote-link-after-creating~ except it prompts for a note-creating
+  command ([[*Points of entry][Points of entry]]).  Use this to, for example, call
+  ~denote-signature~ so that the newly created note has a signature as
+  part of its file name.  Optional =ID-ONLY= has the same meaning as
+  in the command ~denote-link-after-creating~.
+
+#+findex: denote-link-or-create
++ ~denote-link-or-create~ :: Use ~denote-link~ on =TARGET= file,
+  creating it if necessary.
+
+  If =TARGET= file does not exist, call ~denote-link-after-creating~
+  which runs the ~denote~ command interactively to create the file.  The
+  established link will then be targeting that new file.
+
+  If =TARGET= file does not exist, add the user input that was used to
+  search for it to the history of the ~denote-file-prompt~.  The user
+  can then retrieve and possibly further edit their last input, using
+  it as the newly created note's actual title.  At the ~denote-file-prompt~
+  type =M-p= with the default key bindings, which calls ~previous-history-element~.
+
+  With optional =ID-ONLY= as a prefix argument create a link with just
+  the file's identifier.  This has the same meaning as in ~denote-link~.
+
+  This command has the alias ~denote-link-to-existing-or-new-note~,
+  which helps with discoverability.
+
+In all of the above, an optional prefix argument (=C-u= by default)
+creates a link that consists of just the identifier.  This has the
+same meaning as in the regular ~denote-link~ command.
+
+Denote provides similar functionality for opening an existing note or
+creating a new one ([[#h:ad91ca39-cf10-4e16-b224-fdf78f093883][Open an existing note or create it if missing]]).
+
+** The backlinks' buffer
+:PROPERTIES:
+:CUSTOM_ID: h:c73f1f68-e214-49d5-b369-e694f6a5d708
+:END:
+
+[ Older versions of Denote had two types of formatting for the
+  backlinks' buffer. As part of version =4.0.0=, we only support the
+  standard Xref view which shows matches in their context. The user
+  option ~denote-backlinks-show-context~ is thus removed. ]
+
+#+findex: denote-backlinks
+#+findex: denote-show-backlinks-buffer
+The command ~denote-backlinks~ (alias ~denote-show-backlinks-buffer~)
+produces a bespoke buffer which displays backlinks to the current note
+([[#h:435592bc-e896-429f-a599-9f1bcd5ab9b8][Interact with the links buffer]]). A "backlink" is a link back to the
+present entry. Backlinks can be generated for any file type that has a
+Denote file-naming scheme, such as PDFs, images, and videos, as well
+as the regular plain text files.
+
+The backlinks' buffer is, in essence, the equivalent of a Unix ~grep~
+command across the ~denote-directory~ ([[#h:893eec49-d7be-4603-bcff-fcc247244011][Speed up backlinks' buffer creation?]]).
+It groups matches by file name, while it displays the line on which a
+link to the current file occurs together with its context. It looks
+like this (plus the appropriate fontification):
+
+#+begin_example
+Backlinks to "On being honest" (20220614T130812)
+------------------------------------------------
+
+20220614T145606--let-this-glance-become-a-stare__journal.txt
+37: growing into it: [[denote:20220614T130812][On being honest]].
+64: As I said in [[denote:20220614T130812][On being honest]] I have never
+20220616T182958--feeling-butterflies-in-your-stomach__journal.txt
+62: indifference.  In [[denote:20220614T130812][On being honest]] I alluded
+#+end_example
+
+Note that the width of the lines in the context depends on the
+underlying file. In the above example, the lines are split at the
+~fill-column~. Long lines will show up just fine. Also note that the
+built-in user option ~xref-truncation-width~ can truncate long lines
+to a given maximum number of characters.
+
+As with query links, the backlinking facility uses Emacs' built-in
+Xref infrastructure ([[#h:d9a84289-2f73-4ef9-b4f0-9a0aa3e9bf0d][Adding a query link]]). On some operating systems,
+the user may need to add certain executables to the relevant
+environment variable ([[#h:42f6b07e-5956-469a-8294-17f9cf62eb2b][Why do I get "Search failed with status 1" when I search for backlinks?]]).
+
+#+vindex: denote-backlinks-display-buffer-action
+The placement of the backlinks' buffer is subject to the user option
+~denote-backlinks-display-buffer-action~. Due to the nature of the
+underlying ~display-buffer~ mechanism, this inevitably is a relatively
+advanced feature. By default, the backlinks' buffer is displayed below
+the current window.
+
+Backlinks to the current file can also be visited by using the
+minibuffer completion interface with the ~denote-find-backlink~
+command ([[#h:1bc2adad-dca3-4878-b9f0-b105d5dec6f4][Visiting linked files via the minibuffer]]).
+
+** Writing metanotes
+:PROPERTIES:
+:CUSTOM_ID: h:6060a7e6-f179-4d42-a9de-a9968aaebecc
+:END:
+
+A "metanote" is an entry that describes other entries who have something
+in common.  Writing metanotes can be part of a workflow where the user
+periodically reviews their work in search of patterns and deeper
+insights.  For example, you might want to read your journal entries from
+the past year to reflect on your experiences, evolution as a person, and
+the like.
+
+The commands ~denote-add-links~, ~denote-link-dired-marked-notes~ are
+suited for this task.
+
+[[#h:9bec2c83-36ca-4951-aefc-7187c5463f90][Insert links matching a regexp]].
+
+[[#h:9cbb692e-5d8a-44a6-9193-899a07872a07][Insert links from marked files in Dired]].
+
+You will create your metanote the way you use Denote ordinarily
+(metanotes may have the =metanote= keyword, among others), write an
+introduction or however you want to go about it, invoke the command
+which inserts multiple links at once (see the above-cited nodes), and
+continue writing.
+
+Metanotes can serve as entry points to groupings of individual notes.
+They are not the same as a filtered list of files, i.e. what you would
+do in Dired or the minibuffer where you narrow the list of notes to a
+given query.  Metanotes contain the filtered list plus your thoughts
+about it.  The act of purposefully grouping notes together and
+contemplating on their shared patterns is what adds value.
+
+Your future self will appreciate metanotes for the function they serve
+in encapsulating knowledge, while current you will be equipped with the
+knowledge derived from the deliberate self-reflection.
+
+** Visiting linked files via the minibuffer
+:PROPERTIES:
+:CUSTOM_ID: h:1bc2adad-dca3-4878-b9f0-b105d5dec6f4
+:END:
+
+#+findex: denote-find-link
+Denote has a major-mode-agnostic mechanism to collect all linked file
+references in the current buffer and return them as an appropriately
+formatted list.  This list can then be used in interactive commands.
+The ~denote-find-link~ is such a command.  It uses minibuffer
+completion to visit a file that is linked to from the current note.
+The candidates have the correct metadata, which is ideal for
+integration with other standards-compliant tools ([[#h:8ed2bb6f-b5be-4711-82e9-8bee5bb06ece][Extending Denote]]).
+For instance, a package such as =marginalia= will display accurate
+annotations, while the =embark= package will be able to work its magic
+such as in exporting the list into a filtered Dired buffer (i.e. a
+familiar Dired listing with only the files of the current minibuffer
+session).
+
+#+findex: denote-find-backlink
+To visit backlinks to the current note via the minibuffer, use
+~denote-find-backlink~.  This is an alternative to placing backlinks
+in a dedicated buffer ([[#h:c73f1f68-e214-49d5-b369-e694f6a5d708][The backlinks' buffer]]).
+
+** Fontify links in non-Org buffers
+:PROPERTIES:
+:CUSTOM_ID: h:156c5ea3-147b-4f9d-a404-86a00558c60a
+:END:
+
+#+findex: denote-fontify-links-mode
+Denote links are automatically fontified in Org buffers ([[#h:5e5e3370-12ab-454f-ba09-88ff44214324][Adding a single link]]).
+This means that Org recognises the link and applies the relevant
+properties to it to make it clickable/actionable. Other major modes,
+such as ~markdown-mode~ (for =.md= files) or ~text-mode~ (for =.txt=
+files) do not have this feature built into them. Users can still get
+the same behaviour as with Org by activating the ~denote-fontify-links-mode~.
+
+The ~denote-fontify-links-mode~ is a buffer-local minor mode. Users can enable
+it automatically in plain text files that correspond to denote notes with
+something like this:
+
+#+begin_src emacs-lisp
+(add-hook 'text-mode-hook #'denote-fontify-links-mode-maybe)
+#+end_src
+
+The ~text-mode-hook~ applies to all modes derived from ~text-mode~, including
+~markdown-mode~. Though a more explicit setup does no harm:
+
+#+begin_src emacs-lisp
+(add-hook 'markdown-mode-hook #'denote-fontify-links-mode-maybe)
+#+end_src
+
+Because Org already recognises =denote:= links, the function
+~denote-fontify-links-mode-maybe~ will not enable the mode
+~denote-fontify-links-mode~ in Org buffers.
+
+#+findex: denote-link-markdown-follow
+In files whose major mode is ~markdown-mode~, the default key binding
+=C-c C-o= (which calls the command ~markdown-follow-thing-at-point~)
+correctly resolves =denote:= links. Interested users can refer to the
+function ~denote-link-markdown-follow~ for the implementation details.
+
+** The ~denote-link-description-format~ to format link descriptions
+:PROPERTIES:
+:CUSTOM_ID: h:f634427c-b451-40e2-993e-e00ac627af68
+:END:
+
+The user option ~denote-link-description-format~ controls how the
+command ~denote-link~ and related functions create a link description
+by default.
+
+The value can be either a function or a string. If it is a function,
+it is called with one argument, the file, and should return a string
+representing the link description.
+
+The default is a function that returns the active region or the title of
+the note (with the signature if present).
+
+If the value is a string, it treats specially the following specifiers:
+
+- The =%t= is the Denote =TITLE= in the front matter or the file name.
+- The =%T= is the Denote =TITLE= in the file name.
+- The =%i= is the Denote =IDENTIFIER= of the file.
+- The =%I= is the identifier converted to =DAYNAME, DAYNUM MONTHNUM
+  YEAR=.
+- The =%d= is the same as =%i= (=DATE= mnemonic).
+- The =%D= is a "do what I mean" which behaves the same as =%t= and if
+  that returns nothing, it falls back to =%I=, then =%i=.
+- The =%d= is the same as =%i= (=DATE= mnemonic).
+- The =%s= is the Denote =SIGNATURE= of the file.
+- The =%k= is the Denote =KEYWORDS= of the file.
+- The =%%= is a literal percent sign.
+
+In addition, the following flags are available for each of the specifiers:
+
+- 0 :: Pad to the width, if given, with zeros instead of spaces.
+- - :: Pad to the width, if given, on the right instead of the left.
+- < :: Truncate to the width and precision, if given, on the left.
+- > :: Truncate to the width and precision, if given, on the right.
+- ^ :: Convert to upper case.
+- _ :: Convert to lower case.
+
+When combined all together, the above are written thus:
+
+: %<flags><width><precision>SPECIFIER-CHARACTER
+
+Any other text in the string it taken as-is. Users may want, for
+example, to include some text that makes Denote links stand out, such
+as a =[D]= prefix.
+
+If the region is active, its text is used as the link's description.
+
+* Choose which commands to prompt for
+:PROPERTIES:
+:CUSTOM_ID: h:98c732ac-da0e-4ebd-a0e3-5c47f9075e51
+:END:
+
+#+vindex: denote-commands-for-new-notes
+The user option ~denote-commands-for-new-notes~ specifies a list of
+commands that are available at the ~denote-command-prompt~.  This
+prompt is used by Denote commands that ask the user how to create a
+new note, as described elsewhere in this manual:
+
+- [[#h:ad91ca39-cf10-4e16-b224-fdf78f093883][Open an existing note or create it if missing]]
+- [[#h:b6056e6b-93df-4e6b-a778-eebd105bac46][Link to a note or create it if missing]]
+
+The default value includes all the basic file-creating commands
+([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]).  Users may customise this value if (i) they only
+want to see fewer options and/or (ii) wish to include their own custom
+command in the list ([[#h:11946562-7eb0-4925-a3b5-92d75f1f5895][Write your own convenience commands]]).
+
+* Fontification in Dired
+:PROPERTIES:
+:CUSTOM_ID: h:337f9cf0-9f66-45af-b73f-f6370472fb51
+:END:
+
+#+findex: denote-dired-mode
+One of the upsides of Denote's file-naming scheme is the predictable
+pattern it establishes, which appears as a near-tabular presentation in
+a listing of notes (i.e. in Dired).  The ~denote-dired-mode~ can help
+enhance this impression, by fontifying the components of the file name
+to make the date (identifier) and keywords stand out.
+
+There are two ways to set the mode.  Either use it for all directories,
+which probably is not needed:
+
+#+begin_src emacs-lisp
+(add-hook 'dired-mode-hook #'denote-dired-mode)
+#+end_src
+
+#+vindex: denote-dired-directories
+#+findex: denote-dired-mode-in-directories
+Or configure the user option ~denote-dired-directories~ and then set up
+the function ~denote-dired-mode-in-directories~:
+
+#+begin_src emacs-lisp
+;; We use different ways to specify a path for demo purposes.
+(setq denote-dired-directories
+      (list denote-directory
+            (thread-last denote-directory (expand-file-name "attachments"))
+            (expand-file-name "~/Documents/vlog")))
+
+(add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)
+#+end_src
+
+#+vindex: denote-dired-directories-include-subdirectories
+The user option ~denote-dired-directories-include-subdirectories~
+specifies whether the ~denote-dired-directories~ also cover their
+subdirectories. By default they do not. Set this option to ~t~ to
+include subdirectories as well.
+
+The faces we define for this purpose are:
+
+#+vindex: denote-faces-date
+#+vindex: denote-faces-delimiter
+#+vindex: denote-faces-extension
+#+vindex: denote-faces-keywords
+#+vindex: denote-faces-signature
+#+vindex: denote-faces-subdirectory
+#+vindex: denote-faces-time
+#+vindex: denote-faces-title
++ ~denote-faces-date~
++ ~denote-faces-delimiter~
++ ~denote-faces-extension~
++ ~denote-faces-keywords~
+- ~denote-faces-signature~
++ ~denote-faces-subdirectory~
++ ~denote-faces-time~
++ ~denote-faces-title~
+
+For more control, we also provide these:
+
+#+vindex denote-faces-year
+#+vindex denote-faces-month
+#+vindex denote-faces-day
+#+vindex denote-faces-hour
+#+vindex denote-faces-minute
+#+vindex denote-faces-second
++ ~denote-faces-year~
++ ~denote-faces-month~
++ ~denote-faces-day~
++ ~denote-faces-hour~
++ ~denote-faces-minute~
++ ~denote-faces-second~
+
+For the time being, the =diredfl= package is not compatible with this
+facility.
+
+The ~denote-dired-mode~ does not only fontify note files that were
+created by Denote: it covers every file name that follows our naming
+conventions ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).  This is particularly useful for
+scenaria where, say, one wants to organise their collection of PDFs and
+multimedia in a systematic way (and, perhaps, use them as attachments
+for the notes Denote produces if you are writing Org notes and are using
+its standand attachments' facility).
+
+* Automatically rename Denote buffers
+:PROPERTIES:
+:CUSTOM_ID: h:3ca4db16-8f26-4d7d-b748-bac48ae32d69
+:END:
+
+#+findex: denote-rename-buffer-mode
+The minor mode ~denote-rename-buffer-mode~ provides the means to
+automatically rename the buffer of a Denote file upon visiting the
+file. This applies both to existing Denote files as well as new ones
+([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]). Enable the mode thus:
+
+#+begin_src emacs-lisp
+(denote-rename-buffer-mode 1)
+#+end_src
+
+#+vindex: denote-rename-buffer-function
+#+findex: denote-rename-buffer
+#+vindex: denote-rename-buffer-format
+Buffers are named by applying the function specified in the user
+option ~denote-rename-buffer-function~. The default function is
+~denote-rename-buffer~: it renames the buffer based on the template
+set in the user option ~denote-rename-buffer-format~. By default, the
+formatting template targets only the =TITLE= component of the file
+name ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]). Other fields are explained elsewhere in
+this manual ([[#h:35507c18-35b1-41b9-9d80-52f54fcef3cb][The denote-rename-buffer-format]]).
+
+Note that renaming a buffer is not the same as renaming a file
+([[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]). The former is just for convenience inside of Emacs.
+Whereas the latter is for writing changes to disk, making them
+available to all programs.
+
+** The ~denote-rename-buffer-format~ option
+:PROPERTIES:
+:CUSTOM_ID: h:35507c18-35b1-41b9-9d80-52f54fcef3cb
+:END:
+
+The user option ~denote-rename-buffer-format~ controls how the
+function ~denote-rename-buffer~ chooses the name of the
+buffer-to-be-renamed.
+
+The value of this user option is a string. The following specifiers
+are placeholders for Denote file name components ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]):
+
+#+vindex: denote-rename-buffer-backlinks-indicator
+- The =%t= is the Denote =TITLE= in the front matter or the file name.
+- The =%T= is the Denote =TITLE= in the file name.
+- The =%i= is the Denote =IDENTIFIER= of the file.
+- The =%I= is the identifier converted to =DAYNAME, DAYNUM MONTHNUM
+  YEAR=.
+- The =%d= is the same as =%i= (=DATE= mnemonic).
+- The =%D= is a "do what I mean" which behaves the same as =%t= and if
+  that returns nothing, it falls back to =%I=, then =%i=.
+- The =%s= is the Denote =SIGNATURE= of the file.
+- The =%k= is the Denote =KEYWORDS= of the file.
+- The =%b= is an indicator of whether or not the file has backlinks
+  pointing to it. The indicator string is defined in the user option
+  ~denote-rename-buffer-backlinks-indicator~, alias
+  ~denote-buffer-has-backlinks-string~.
+- The =%%= is a literal percent sign.
+
+In addition, the following flags are available for each of the specifiers:
+
+- =0= :: Pad to the width, if given, with zeros instead of spaces.
+- =-= :: Pad to the width, if given, on the right instead of the left.
+- =<= :: Truncate to the width and precision, if given, on the left.
+- =>= :: Truncate to the width and precision, if given, on the right.
+- =^= :: Convert to upper case.
+- =_= :: Convert to lower case.
+
+When combined all together, the above are written thus:
+
+: %<flags><width><precision>SPECIFIER-CHARACTER
+
+Any other string it taken as-is.  Users may want, for example, to
+include some text that makes Denote buffers stand out, such as
+a =[D]= prefix.  Examples:
+
+#+begin_src emacs-lisp
+;; The following is the default value.  Use a literal [D] prefix,
+;; followed by the title and then the backlinks indicator.  If there
+;; is no title, use the identifier in its human-readable date
+;; representation, and if that is not possible, use the identifier
+;; as-is.
+(setq denote-rename-buffer-format "[D] %D%b")
+
+;; Customize what the backlink indicator looks like.  This two-faced
+;; arrow is the default.
+(setq denote-rename-buffer-backlinks-indicator  "<-->")
+
+;; Use just the title and keywords with some emoji in between, because
+;; why not?
+(setq denote-rename-buffer-format "%t 🤨 %k")
+
+;; Use the title with a literal "[D]" before it.
+(setq denote-rename-buffer-format "[D] %t")
+
+;; As above, but also add the `denote-rename-buffer-backlinks-indicator' at the end.
+(setq denote-rename-buffer-format "[D] %t%b")
+#+end_src
+
+Users who need yet more flexibility are best served by writing their
+own function and assigning it to the ~denote-rename-buffer-function~.
+
+* Use Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:8b542c50-dcc9-4bca-8037-a36599b22779
+:END:
+
+This section is about the external package ~denote-org~ (by
+Protesilaos). The code of ~denote-org~ used to be available as part of
+the main ~denote~ package, but we decided to keep each optional
+extension as a separate package to make things easier to maintain and
+to understand.
+
+Denote can optionally integrate with Org mode's "dynamic blocks"
+facility. This means that it can use special blocks that are evaluated
+with =C-c C-x C-u= (~org-dblock-update~) to generate their contents.
+
+Dynamic blocks are particularly useful for metanote entries that
+reflect on the status of earlier notes ([[#h:6060a7e6-f179-4d42-a9de-a9968aaebecc][Writing metanotes]]). The
+~denote-org~ package defines many of these Org dynamic blocks.
+
++ Package name (GNU ELPA): ~denote-org~
++ Official manual: <https://protesilaos.com/emacs/denote-org>
++ Git repository: <https://github.com/protesilaos/denote-org>
++ Backronym: Denote... Ordinarily Restricts Gyrations.
+
+* Display filtered and sorted files with ~denote-sort-dired~ or ~denote-dired~
+:PROPERTIES:
+:CUSTOM_ID: h:9fe01e63-f34f-4479-8713-f162a5ca865e
+:END:
+
+The =denote.el= file contains functions which empower user or
+developers to sort files by the given file name component ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+#+findex: denote-sort-dired
+#+findex: denote-dired
+The command ~denote-sort-dired~ (alias ~denote-dired~) produces a
+Dired file listing with a flat, filtered, and sorted set of files from
+the ~denote-directory~ ([[#h:c958e087-1d23-4a25-afdd-db7bf5606b4c][Define a sorting function per component]]). It
+does so by a series of prompts, which can be configured with the user
+option ~denote-sort-dired-extra-prompts~ ([[#h:a34228cb-484f-48fe-9cbc-8e41f313127b][Configure what extra prompts ~denote-sort-dired~ issues]]).
+
+Think of ~denote-sort-dired~ as the counterpart to the Unix ~find~
+command. While ~denote-grep~ corresponds to the Unix ~grep~ ([[#h:e71c9d14-7e88-4386-91d0-9ad249947077][Use ~denote-grep~ to search inside files]]).
+
+The out-of-the-box behaviour of ~denote-sort-dired~ is as follows:
+
+1. It first asks for a regular expression with which to match Denote
+   file names. Remember that due to Denote's efficient file-naming
+   scheme, you usually do not need to write some complex regular
+   expression. For example, something like =_journal= will match only
+   files with a =journal= keyword.
+2. Once the regular expression is provided, the command asks for a
+   Denote file name component to sort files by. This is a symbol among
+   =title=, =keywords=, =signature=, and =identifier= ([[#h:c958e087-1d23-4a25-afdd-db7bf5606b4c][Define a sorting function per component]]).
+3. Finally, it asks a "yes or no" on whether to reverse the sort order.
+
+The resulting listing is a regular Dired buffer, unlike that of
+~dired-virtual-mode~ ([[#h:d35d8d41-f51b-4139-af8f-9c8cc508e35b][Use ~dired-virtual-mode~ for arbitrary file listings]]).
+
+#+findex: denote-sort-files
+The sorting mechanism can be used by other packages to achieve their
+ends. As an example, the dynamic Org blocks that the ~denote-org~
+package (by Protesilaos) defines also use this feature internally by
+means of the non-interactive function ~denote-sort-files~.
+
+** Configure what extra prompts ~denote-sort-dired~ issues
+:PROPERTIES:
+:CUSTOM_ID: h:a34228cb-484f-48fe-9cbc-8e41f313127b
+:END:
+
+#+vindex: denote-sort-dired-extra-prompts
+By default, the ~denote-sort-dired~ command prompts for (i) a query to
+match file names, (ii) a file name component to sort by, and (iii)
+whether to reverse the sorting ([[#h:9fe01e63-f34f-4479-8713-f162a5ca865e][Display filtered and sorted files with denote-sort-dired]]).
+Users can configure the latter two by modifying the user option
+~denote-sort-dired-extra-prompts~.
+
+The ~denote-sort-dired-extra-prompts~ accepts either a nil value or a
+list of symbols among ~sort-by-component~, ~reverse-sort~, and
+~exclude-regexp~. The order those symbols appear in the list is
+significant, with the leftmost coming first.
+
+These symbols correspond to the following:
+
+- A choice to select the file name component to sort by.
+- A yes or no prompt on whether to reverse the sorting.
+- A string (or regular expression) of files to be excluded from the
+  results.
+
+#+vindex: denote-sort-dired-default-sort-component
+#+vindex: denote-sort-dired-default-reverse-sort
+In case of a nil value, those extra prompts will not happen, meaning
+that ~denote-sort-dired~ will fall back to using whatever is defined
+in the variables ~denote-sort-dired-default-sort-component~ and
+~denote-sort-dired-default-reverse-sort~.
+
+Here are some examples:
+
+#+begin_src emacs-lisp
+;; The default extra prompts...
+(setq denote-sort-dired-extra-prompts '(sort-by-component reverse-sort))
+
+;; When using `denote-sort-dired', ask whether to reverse the sort and
+;; then which file name component to sort by.  These are always done
+;; after the prompt to search for files matching a regexp.
+(setq denote-sort-dired-extra-prompts '(reverse-sort sort-by-component))
+
+;; Do not prompt for a reverse sort.  Just use the value of
+;; `denote-sort-dired-default-reverse-sort' (which is nil out-of-the-box).
+(setq denote-sort-dired-extra-prompts '(sort-by-component))
+
+;; Do not issue any extra prompts.  Always sort by the `title' file
+;; name component and never do a reverse sort.
+(setq denote-sort-dired-extra-prompts nil)
+(setq denote-sort-dired-default-sort-component 'title)
+(setq denote-sort-dired-default-reverse-sort nil)
+#+end_src
+
+** Define a sorting function per component
+:PROPERTIES:
+:CUSTOM_ID: h:c958e087-1d23-4a25-afdd-db7bf5606b4c
+:END:
+
+When sorting by =title=, =keywords=, or =signature= with the
+~denote-sort-dired~ command, Denote will internally apply a sorting
+function that is specific to each component ([[#h:a34228cb-484f-48fe-9cbc-8e41f313127b][Configure what extra prompts ~denote-sort-dired~ issues]]).
+These are subject to user configuration:
+
+#+vindex: denote-sort-identifier-comparison-function
+- ~denote-sort-identifier-comparison-function~
+
+#+vindex: denote-sort-title-comparison-function
+- ~denote-sort-title-comparison-function~
+
+#+vindex: denote-sort-keywords-comparison-function
+- ~denote-sort-keywords-comparison-function~
+
+#+vindex: denote-sort-signature-comparison-function
+- ~denote-sort-signature-comparison-function~
+
+By default, all these user options use the same sorting function,
+namely ~string-collate-lessp~. Users who have specific needs for any
+of those file name components can write their own sorting algorithms
+([[#h:95345870-4ccd-484f-9adf-de4747ad5760][Sort signatures that include Luhmann-style sequences]]).
+
+*** Sort signatures that include Luhmann-style sequences
+:PROPERTIES:
+:CUSTOM_ID: h:95345870-4ccd-484f-9adf-de4747ad5760
+:END:
+
+[ The ~denote-sequence~ package (by Protesilaos) covers this use-case
+  and many others ([[#h:d5ca722d-e7fa-46fa-9a57-6363b1d4186f][Write sequence notes or folgezettel]]). It is the
+  superior option for anyone interested in this functionality. We keep
+  the code below for reference, as there may be users of it who need
+  to revisit it. Though long-term, it is better to use ~denote-sequence~. ]
+
+Niklas Luhmann would edit notes to form sequences of thoughts with
+branching paths, such as =1.1=, =1.1a=, =1.2=, =1.2a=, =1.2b=, etc.
+With the Denote file-naming scheme, we make the word separator in each
+file name component use the same character as the entire field, so
+words in a title have a dash between them and signatures have the
+equals sign ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]). Thus, our Luhmann-style
+signature will be slightly different in their looks: ~1=1~, ~1=1a~,
+~1=2~, ~1=2a~, ~1=2b~.
+
+When using the ~denote-sort-dired~ command with default settings, our
+signatures will not sort in an intuitive way. This is because they
+combine numbers and letters, which require a different approach than
+what the default sorting function is using ([[#h:c958e087-1d23-4a25-afdd-db7bf5606b4c][Define a sorting function per component]]).
+In the following code block, we show a sorting algorithm that should
+do the right thing while dealing with Luhmann-style signatures.
+
+#+begin_src emacs-lisp
+(defun my-denote--split-luhman-sig (signature)
+  "Split numbers and letters in Luhmann-style SIGNATURE string."
+  (replace-regexp-in-string
+   "\\([a-zA-Z]+?\\)\\([0-9]\\)" "\\1=\\2"
+   (replace-regexp-in-string
+    "\\([0-9]+?\\)\\([a-zA-Z]\\)" "\\1=\\2"
+    signature)))
+
+(defun my-denote--pad-sig (signature)
+  "Create a new signature with padded spaces for all components"
+  (combine-and-quote-strings
+   (mapcar
+    (lambda (x)
+      (string-pad x 5 32 t))
+    (split-string (my-denote--split-luhman-sig signature) "=" t))
+   "="))
+
+(defun my-denote-sort-for-signatures (sig1 sig2)
+  "Return non-nil if SIG1 is smaller that SIG2.
+Perform the comparison with `string<'."
+  (string< (my-denote--pad-sig sig1) (my-denote--pad-sig sig2)))
+
+;; Change the sorting function only when we sort by signature.
+(setq denote-sort-signature-comparison-function #'my-denote-sort-for-signatures)
+#+end_src
+
+* Use ~denote-grep~ to search inside files
+:PROPERTIES:
+:CUSTOM_ID: h:e71c9d14-7e88-4386-91d0-9ad249947077
+:END:
+
+#+findex: denote-grep
+The command ~denote-grep~ searches for the given query across all
+readable files in the ~denote-directory~. It puts the collected
+results in an Xref buffer (just like with our backlinks and query
+links functionality). In this buffer, users can do =M-x describe-mode=
+(=C-h m= with default key bindings) to learn about all the actions
+they can perform and the keys they are bound to ([[#h:435592bc-e896-429f-a599-9f1bcd5ab9b8][Interact with the links buffer]]).
+
+Think of ~denote-grep~ as the counterpart to the Unix ~grep~ command.
+While ~denote-sort-dired~ corresponds to the Unix ~find~ ([[#h:9fe01e63-f34f-4479-8713-f162a5ca865e][Display filtered and sorted files with ~denote-sort-dired~]]).
+
+#+findex: denote-grep-marked-dired-files
+The command ~denote-grep-marked-dired-files~ is like ~denote-grep~ but
+operates on the files that are marked in a Dired buffer.
+
+#+findex: denote-grep-files-referenced-in-region
+The command ~denote-grep-files-referenced-in-region~ is like
+~denote-grep~ for any files referenced within the boundaries of the
+marked region. Files are referenced by their identifier. This includes
+links with just the identifier (as described in ~denote-link~ and
+related ([[#h:5e5e3370-12ab-454f-ba09-88ff44214324][Add a single direct link using a file name prompt]])), links
+written by an Org dynamic block (see the ~denote-org~ package ([[#h:8b542c50-dcc9-4bca-8037-a36599b22779][Use Org dynamic blocks]])),
+or even file listings such as those of ~dired~ and the command-line
+~ls~ program.
+
+#+vindex: denote-grep-display-buffer-action
+The user option ~denote-grep-display-buffer-action~ controls where the
+buffer with the search results is displayed at. By default, they appear in
+the same window where the command ~denote-grep~ is called from.
+
+* Interact with the links buffer
+:PROPERTIES:
+:CUSTOM_ID: h:435592bc-e896-429f-a599-9f1bcd5ab9b8
+:END:
+
+Denote commands, such as ~denote-grep~, ~denote-backlinks~, and
+~denote-query-contents-link~, produce an Xref buffer with search
+results ([[#h:893eec49-d7be-4603-bcff-fcc247244011][Speed up backlinks' or query links' buffer creation?]]).
+Matching lines are grouped by the file name they belong to.
+
+- [[#h:e71c9d14-7e88-4386-91d0-9ad249947077][Use ~denote-grep~ to search inside files]].
+- [[#h:c73f1f68-e214-49d5-b369-e694f6a5d708][The backlinks' buffer]].
+- [[#h:d9a84289-2f73-4ef9-b4f0-9a0aa3e9bf0d][Add a query link]].
+
+#+findex: denote-query-mode
+#+vindex: denote-query-mode-map
+This buffer uses the major mode ~denote-query-mode~. It binds commands
+to keys in the ~denote-query-mode-map~. Those allow users to filter
+the output of the last search. Here, "last search" refers to the list
+of files that were returned by whichever command produced the buffer
+(e.g. the last ~denote-grep~).
+
+#+findex: denote-query-focus-last-search
+- ~denote-query-focus-last-search~ :: Perform a search in the contents
+  of files that were matched by the last search.
+
+#+findex: denote-query-exclude-files
+- ~denote-query-exclude-files~ :: Exclude files from the last search
+  whose name matches the given input.
+
+#+findex: denote-query-only-include-files
+- ~denote-query-only-include-files~ :: Only keep files from the last
+  search whose name matches the given input.
+
+#+findex: denote-query-exclude-files-with-keywords
+- ~denote-query-exclude-files-with-keywords~ :: Exclude files from the
+  last search whose name includes the given keywords.
+
+#+findex: denote-query-only-include-files-with-keywords
+- ~denote-query-only-include-files-with-keywords~ :: Only keep files
+  from the last search whose name includes the given keywords.
+
+#+findex: denote-query-clear-all-filters
+- ~denote-query-clear-all-filters~ :: Clear all the applied filters.
+
+Remember that these are easy to use even without knowledge of regular
+expressions, thanks to the efficiency of the Denote file-naming scheme
+([[#h:1a953736-86c2-420b-b566-fb22c97df197][Features of the file-naming scheme for searching or filtering]]). For
+instance, to exclude notes with the keyword =philosophy= from current
+search buffer, use ~denote-query-exclude-files~ and then type
+=_philosophy= as your input.
+
+In addition to those filtering options, the ~denote-query-mode~ also
+allows provides an outline mechanism to hide or show the matches as
+these are grouped per file. There also are some of the default actions
+provided by the Xref infrastructure. Users can do =M-x describe-mode=
+(=C-h m= with default key bindings) to learn about all the actions
+they can perform.
+
+* Minibuffer histories
+:PROPERTIES:
+:CUSTOM_ID: h:82dc1203-d689-44b2-9a6c-b37776209651
+:END:
+
+Denote has a dedicated minibuffer history for each one of its prompts.
+This practically means that using =M-p= (~previous-history-element~) and
+=M-n= (~next-history-element~) will only cycle through the relevant
+record of inputs, such as your latest titles in the =TITLE= prompt, and
+keywords in the =KEYWORDS= prompt.
+
+The built-in =savehist= library saves minibuffer histories.  Sample
+configuration:
+
+#+begin_src emacs-lisp
+(require 'savehist)
+(setq savehist-file (locate-user-emacs-file "savehist"))
+(setq history-length 500)
+(setq history-delete-duplicates t)
+(setq savehist-save-minibuffer-history t)
+(add-hook 'after-init-hook #'savehist-mode)
+#+end_src
+
+* Packages that build on Denote
+:PROPERTIES:
+:CUSTOM_ID: h:08b14682-e73f-4b11-b2e2-be3b788c8572
+:END:
+
+This is a list of packages that extend Denote. If you are a package
+author, please let us know about your work and we will include it
+here (either use the Git repositories or email Protesilaos directly).
+
+** Use the ~consult-denote~ package for enhanced minibuffer interactions
+:PROPERTIES:
+:CUSTOM_ID: h:113a13e1-35da-46f1-9414-81e9be2facc1
+:END:
+
+The ~consult-denote~ package by me (Protesilaos) integrates Denote
+with Daniel Mendler's ~consult~ package: <https://github.com/protesilaos/consult-denote>.
+
+The idea is to preserve the familiar patterns of interaction with the
+various Denote commands but add to them an extra layer of
+functionality, such as the preview mechanism that Consult provides
+(e.g. preview the file you are about to link to).
+
+Additionally, ~consult-denote~ defines new "sources" for the
+~consult-buffer~ command. This command provides a single point of
+entry for buffers, recently opened files, and bookmarks. With
+~consult-denote~, it has a dedicated place for Denote-specific
+buffers, silos, and more (all of which are configurable).
+
+Unlike the ~consult-notes~ package by Colin McLear, ~consult-denote~
+uses the same presentation of data in the minibuffer to stay in sync
+with Denote and make its feature set entirely optional ([[#h:8907f4bc-992a-45bc-a60e-267ed1ce9c2d][Use the ~consult-notes~ package]]).
+It also only works with Denote.
+
+** Use the ~denote-sequence~ package to write sequence notes or "folgezettel"
+:PROPERTIES:
+:CUSTOM_ID: h:d5ca722d-e7fa-46fa-9a57-6363b1d4186f
+:ALT_TITLE: Sequence notes
+:END:
+
+This section is about the external package ~denote-sequence~ (by
+Protesilaos). The original idea was to include the code as part of the
+~denote~ package, but we decided to keep each optional extension as a
+separate package to make things easier to maintain and to understand.
+
+Denote defines an optional file name component called the =SIGNATURE=
+([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]). This is a free-form field that users can
+fill in with whatever text they want, such as to have a video split up
+into =part1= and =part2=, or to set some kind of priority like =a= and
+=b=, or even to have a special tag that stands out from the rest of
+the keywords.
+
+A more specialised use-case of the =SIGNATURE= is to define a
+hierarchical relationship between notes, such that the thoughts they
+expound on form sequences. For example, an article about the Labrador
+Retriever dog breed is a continuation of a thought process that
+extends something about dog breeds in general which, in turn, is a
+topic that belongs to the wider theme of dogs.
+
+The ~denote-sequence~ package has a manual that explains these
+concepts and relevant commands in further detail:
+
++ Package name (GNU ELPA): ~denote-sequence~
++ Official manual: <https://protesilaos.com/emacs/denote-sequence>
++ Git repository: <https://github.com/protesilaos/denote-sequence>
++ Backronym: Denote... Sequences Efficiently Queue Unsorted Entries
+  Notwithstanding Curation Efforts.
+
+** Use the ~denote-markdown~ package to better integrate Markdown with Denote
+:PROPERTIES:
+:CUSTOM_ID: h:79b614e7-d7a3-4953-b776-216e6e1ede77
+:END:
+
+The ~denote-markdown~ package (by Protesilaos) provides some
+convenience functions to better integrate Markdown with Deonte. This
+is mostly about converting links from one type to another so that they
+can work in different applications (because Markdown does not have a
+standardised way to define custom link types).
+
+The code of ~denote-markdown~ used to be bundled up with the ~denote~
+package before version =4.0.0= of the latter and was available in the
+file =denote-md-extras.el=. Users of the old code will need to adapt
+their setup to use the ~denote-markdown~ package. This can be done by
+replacing all instances of =denote-md-extras= with =denote-markdown=
+across their configuration.
+
++ Package name (GNU ELPA): ~denote-markdown~
++ Official manual: <https://protesilaos.com/emacs/denote-markdown>
++ Git repository: <https://github.com/protesilaos/denote-markdown>
++ Backronyms: Denote... Markdown's Ambitious Reimplimentations
+  Knowingly Dilute Obvious Widespread Norms; Denote... Markup
+  Agnosticism Requires Knowhow to Do Only What's Necessary.
+
+** Use the ~denote-journal~ package which was formerly =denote-journal-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:4a6d92dd-19eb-4fcc-a7b5-05ce04da3a92
+:END:
+
+The ~denote-journal~ package (by Protesilaos) makes it easier to use
+Denote for journaling. While it is possible to use the generic
+~denote~ command (and related) to maintain a journal, this package
+defines extra functionality to streamline the journaling workflow.
+
+The code of ~denote-journal~ used to be bundled up with the ~denote~
+package before version =4.0.0= of the latter and was available in the
+file =denote-journal-extras.el=. Users of the old code will need to
+adapt their setup to use the ~denote-journal~ package. This can be
+done by replacing all instances of =denote-journal-extras= with
+=denote-journal= across their configuration.
+
++ Package name (GNU ELPA): ~denote-journal~
++ Official manual: <https://protesilaos.com/emacs/denote-journal>
++ Git repository: <https://github.com/protesilaos/denote-journal>
++ Backronym: Denote... Journaling Obviously Utilises Reasonableness
+  Notwithstanding Affectionate Longing.
+
+** Use the ~denote-silo~ package which formerly was =denote-silo-extras.el=
+:PROPERTIES:
+:CUSTOM_ID: h:e43baf95-f201-4fec-8620-c0eb5eaa1c85
+:END:
+
+The ~denote-silo~ package (by Protesilaos) provides convenience
+functions for working with silos ([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directory silos for notes]]).
+
+The code of ~denote-silo~ used to be bundled up with the ~denote~
+package before version =4.0.0= of the latter and was available in the
+file =denote-silo-extras.el=. Users of the old code will need to adapt
+their setup to use the ~denote-silo~ package. This can be done by
+replacing all instances of =denote-silo-extras= with =denote-silo=
+across their configuration.
+
++ Package name (GNU ELPA): ~denote-silo~
++ Official manual: <https://protesilaos.com/emacs/denote-silo>
++ Git repository: <https://github.com/protesilaos/denote-silo>
++ Backronym: Denote... Silos Insulate Localised Objects.
+
+** Use the ~denote-search~ package as a search interface
+:PROPERTIES:
+:CUSTOM_ID: h:c905b733-e959-4aa4-8f2c-0ed9eba459df
+:END:
+
+[ As part of version =4.0.0=, Denote comes with the ~denote-grep~
+  command and related functionality ([[#h:e71c9d14-7e88-4386-91d0-9ad249947077][Use ~denote-grep~ to search inside files]]).
+  The core of this feature set was written by Lucas Quintana. ]
+
+The ~denote-search~ package by Lucas Quintana provides a search
+utility for Denote: <https://github.com/lmq-10/denote-search>.
+
+It allows you to search for a regular expression in the content of
+your notes. Its main advantages over other similar tools are the
+possibility of filtering the results by file name and doing further
+searches in the files matched previously. This allows for advanced
+usage (think about finding a note with two or three specific words in
+different lines and with a specific keyword). More features are
+described in its comprehensive manual. ~denote-search~ builds upon
+standard Emacs libraries, namely Xref, and so it doesn't have external
+dependencies other than Denote itself.
+
+** Use the ~denote-explore~ package to explore your notes
+:PROPERTIES:
+:CUSTOM_ID: h:110ae3a4-5fc6-45da-b9bb-0e294bd12981
+:END:
+
+Peter Prevos has developed the ~denote-explore~ package which provides
+four groups of Emacs commands to explore your Denote files:
+
+- Summary statistics :: Count notes, attachments and keywords.
+- Random walks :: Generate new ideas using serendipity.
+- Janitor :: Manage your denote collection.
+- Visualisations :: Visualise your Denote network.
+
+The package's documentation covers the details:
+<https://lucidmanager.org/productivity/denote-explore/>.
+
+** Use the ~citar-denote~ package for bibliography notes
+:PROPERTIES:
+:CUSTOM_ID: h:226d66e4-b7de-4617-87e2-a7f2d6f007dd
+:END:
+
+Peter Prevos has produced the ~citar-denote~ package which makes it
+possible to write notes on BibTeX entries with the help of the ~citar~
+package.  These notes have the citation's unique key associated with
+them in the file's front matter.  They also get a configurable keyword
+in their file name, making it easy to find them in Dired and/or
+retrieve them with the various Denote methods.
+
+With ~citar-denote~, the user leverages standard minibuffer completion
+mechanisms (e.g. with the help of the ~vertico~ and ~embark~ packages)
+to manage bibliographic notes and access those notes with ease.  The
+package's documentation covers the details: <https://lucidmanager.org/productivity/bibliographic-notes-in-emacs-with-citar-denote/>.
+
+** Use the ~consult-notes~ package
+:PROPERTIES:
+:CUSTOM_ID: h:8907f4bc-992a-45bc-a60e-267ed1ce9c2d
+:END:
+
+[ Also check the ~consult-denote~ package by me (Protesilaos):
+  [[#h:113a13e1-35da-46f1-9414-81e9be2facc1][Use the ~consult-denote~ package for enhanced minibuffer interactions]]. ]
+
+If you are using Daniel Mendler's ~consult~ (which is a brilliant
+package), you will most probably like its ~consult-notes~ extension,
+developed by Colin McLear.  It uses the familiar mechanisms of Consult
+to preview the currently selected entry and to filter searches via a
+prefix key.  For example:
+
+#+begin_src emacs-lisp
+(setq consult-notes-file-dir-sources
+      `(("Denote Notes"  ?d ,(denote-directory))
+        ("Books"  ?b "~/Documents/books/")))
+#+end_src
+
+With the above, =M-x consult-notes= will list the files in those two
+directories.  If you type =d= and space, it narrows the list to just
+the notes, while =b= does the same for books.
+
+The other approach is to enable the ~consult-notes-denote-mode~.  It
+takes care to add the ~denote-directory~ to the sources that
+~consult-notes~ reads from.  Denote notes are then filtered by the =d=
+prefix followed by a space.
+
+The minor mode has the extra feature of reformatting the title of
+notes shown in the minibuffer.  It isolates the =TITLE= component of
+each note and shows it without hyphens, while presenting keywords in
+their own column.  The user option ~consult-notes-denote-display-id~
+can be set to ~nil~ to hide the identifier.  Depending on how one
+searches through their notes, this refashioned presentation may be the
+best option ([[#h:1a953736-86c2-420b-b566-fb22c97df197][Features of the file-naming scheme for searching or filtering]]).
+
+** Use the ~denote-menu~ package
+:PROPERTIES:
+:CUSTOM_ID: h:472db709-27de-4a1f-a171-c3fe0a7a9be8
+:END:
+
+Denote's file-naming scheme is designed to be efficient and to provide
+valueable meta information about the file.  The cost, however, is that
+it is terse and harder to read, depending on how the user chooses to
+filter and process their notes.
+
+To this end, [[https://github.com/namilus/denote-menu][the ~denote-menu~ package by Mohamed Suliman]] provides the
+convenience of a nice tabular interface for all notes.  ~denote-menu~
+removes the delimiters that are found in Denote file names and
+presents the information in a human-readable format.  Furthermore, the
+package provides commands to interact with the list of notes, such as
+to filter them and to transition from the tabular list to Dired.  Its
+documentation expands on the technicalities.
+
+** Use the ~denote-zettel-interface~ package
+:PROPERTIES:
+:CUSTOM_ID: h:b57f73fc-ac4d-4df2-bd7a-8d47cb202647
+:END:
+
+The [[https://github.com/krisbalintona/denote-zettel-interface][~denote-zettel-interface~ package by Kristoffer Balintona]] is
+designed for those who want to use Denote while adhering to a strict
+Zettelkasten methodology of sequence notes (Folgezettel). This method
+leverages the optional =SIGNATURE= file name component of Denote ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+The package provides a point of entry to one's note by visualising
+them in a tabulated (grid) interface. Files are sorted by their
+Folgezettel index. Users can then use a number of commands to filter
+their files, navigate around, and the like.
+
+Note that the package is in early development as of this writing
+(2024-12-03 10:18 +0200).
+
+* Extending Denote
+:PROPERTIES:
+:CUSTOM_ID: h:8ed2bb6f-b5be-4711-82e9-8bee5bb06ece
+:END:
+
+Denote is a tool with a narrow scope: create notes and link between
+them, based on the aforementioned file-naming scheme. For other common
+operations the user is advised to rely on standard Emacs facilities or
+specialised third-party packages ([[#h:08b14682-e73f-4b11-b2e2-be3b788c8572][Packages that build on Denote]]). This
+section covers the details.
+
+** Access the data of the latest note
+:PROPERTIES:
+:CUSTOM_ID: h:a947908e-1847-4471-ba07-377ee2f4b36c
+:END:
+
+#+vindex: denote-current-data
+The variable ~denote-current-data~ is updated each time a new note is
+created as well as after a rename operation.
+
+This is an alist where each ~car~ is one among ~title~, ~keywords~,
+~signature~, ~directory~, ~date~, ~id~, ~file-type~, ~template~. The
+value each of them contains is the unprocessed input (e.g. the title
+before it is sluggified).
+
+Users who need to access this data as part of their custom code can
+rely on the hooks ~denote-after-new-note-hook~ and
+~denote-after-rename-file-hook~.
+
+** Create a new note in any directory
+:PROPERTIES:
+:CUSTOM_ID: h:c9d7c157-85a6-4bb7-bd21-d00bccf5e799
+:END:
+
+The commands that create new files are designed to write to the
+~denote-directory~. The idea is that the linking mechanism can find
+any file by its identifier if it is in the ~denote-directory~
+(searching the entire file system would be cumbersome).
+
+However, these are cases where the user needs to create a new note in
+an arbitrary directory. The following command can do this. Put the
+code in your configuration file and evaluate it. Then call the command
+by its name with =M-x=.
+
+#+begin_src emacs-lisp
+(defun my-denote-create-note-in-any-directory ()
+  "Create new Denote note in any directory.
+Prompt for the directory using minibuffer completion."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-directory (read-directory-name "New note in: " nil nil :must-match)))
+    (call-interactively 'denote)))
+#+end_src
+
+** Find empty notes and put them in a Dired buffer
+:PROPERTIES:
+:CUSTOM_ID: h:bbc7a769-19e8-4598-a2b7-06e1d673ae80
+:END:
+
+[ This feature is based on the command ~denote-sort-dired~ ([[#h:9fe01e63-f34f-4479-8713-f162a5ca865e][Sort files by component]]). ]
+
+Users may have a workflow where they use the commands
+~denote-link-or-create~ or ~denote-link-after-creating~ (and related)
+to produce new notes that they plan to elaborate on later ([[#h:b6056e6b-93df-4e6b-a778-eebd105bac46][Link to an existing note or create a new one]]).
+
+To help users find those empty notes, we document the following
+commands:
+
+- ~my-denote-sort-dired-empty-files~
+- ~my-denote-sort-dired-without-empty-files~
+- ~my-denote-sort-dired-all-empty-files~
+- ~my-denote-sort-dired-without-all-empty-files~
+
+#+begin_src emacs-lisp
+(require 'denote-sort)
+
+(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
+has no contents or has only the front matter."
+  (and (denote-file-is-note-p file)
+       (or (denote--file-with-temp-buffer file
+             (re-search-forward "^$" nil t)
+             (if (re-search-forward "[^\s\t\n\r]+" nil t)
+                 nil
+               t))
+           ;; This must come later because here we consider a file
+           ;; "empty" even if it only has front matter.
+           (denote--file-empty-p file))))
+
+(defun my-denote-sort-dired-empty-files (files-matching-regexp sort-by-component reverse)
+  "Like `denote-sort-dired' but only cover empty files.
+Empty files are those that satisfy `my-denote--note-has-no-contents-p'."
+  (interactive
+   (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts)))
+  (let ((component (or sort-by-component
+                       denote-sort-dired-default-sort-component
+                       'identifier))
+        (reverse-sort (or reverse
+                          denote-sort-dired-default-reverse-sort
+                          nil)))
+    (if-let* ((default-directory (denote-directory))
+              (files (denote-sort-get-directory-files files-matching-regexp component reverse-sort))
+              (empty-files (seq-filter #'my-denote--note-has-no-contents-p files))
+              ;; NOTE 2023-12-04: Passing the FILES-MATCHING-REGEXP as
+              ;; buffer-name produces an error if the regexp contains a
+              ;; wildcard for a directory. I can reproduce this in emacs
+              ;; -Q and am not sure if it is a bug. Anyway, I will report
+              ;; it upstream, but even if it is fixed we cannot use it
+              ;; for now (whatever fix will be available for Emacs 30+).
+              (denote-sort-dired-buffer-name (format "Denote sort `%s' by `%s'" files-matching-regexp component))
+              (buffer-name (format "Denote sort by `%s' at %s" component (format-time-string "%T"))))
+        (let ((dired-buffer (dired (cons buffer-name (mapcar #'file-relative-name empty-files)))))
+          (setq denote-sort--dired-buffer dired-buffer)
+          (with-current-buffer dired-buffer
+            (setq-local revert-buffer-function
+                        (lambda (&rest _)
+                          (kill-buffer dired-buffer)
+                          (denote-sort-dired files-matching-regexp component reverse-sort))))
+          ;; Because of the above NOTE, I am printing a message.  Not
+          ;; what I want, but it is better than nothing...
+          (message denote-sort-dired-buffer-name))
+      (message "No matching files for: %s" files-matching-regexp))))
+
+(defun my-denote-sort-dired-without-empty-files (files-matching-regexp sort-by-component reverse)
+  "Like `denote-sort-dired' but only cover empty files.
+Empty files are those that satisfy `my-denote--note-has-no-contents-p'."
+  (interactive
+   (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts)))
+  (let ((component (or sort-by-component
+                       denote-sort-dired-default-sort-component
+                       'identifier))
+        (reverse-sort (or reverse
+                          denote-sort-dired-default-reverse-sort
+                          nil)))
+    (if-let* ((default-directory (denote-directory))
+              (files (denote-sort-get-directory-files files-matching-regexp component reverse-sort))
+              (empty-files (seq-remove #'my-denote--note-has-no-contents-p files))
+              ;; NOTE 2023-12-04: Passing the FILES-MATCHING-REGEXP as
+              ;; buffer-name produces an error if the regexp contains a
+              ;; wildcard for a directory. I can reproduce this in emacs
+              ;; -Q and am not sure if it is a bug. Anyway, I will report
+              ;; it upstream, but even if it is fixed we cannot use it
+              ;; for now (whatever fix will be available for Emacs 30+).
+              (denote-sort-dired-buffer-name (format "Denote sort `%s' by `%s'" files-matching-regexp component))
+              (buffer-name (format "Denote sort by `%s' at %s" component (format-time-string "%T"))))
+        (let ((dired-buffer (dired (cons buffer-name (mapcar #'file-relative-name empty-files)))))
+          (setq denote-sort--dired-buffer dired-buffer)
+          (with-current-buffer dired-buffer
+            (setq-local revert-buffer-function
+                        (lambda (&rest _)
+                          (kill-buffer dired-buffer)
+                          (denote-sort-dired files-matching-regexp component reverse-sort))))
+          ;; Because of the above NOTE, I am printing a message.  Not
+          ;; what I want, but it is better than nothing...
+          (message denote-sort-dired-buffer-name))
+      (message "No matching files for: %s" files-matching-regexp))))
+
+(defun my-denote-sort-dired-all-empty-files ()
+  "List all empty files in a Dired buffer.
+This is the same as calling `my-denote-sort-dired' with a
+FILES-MATCHING-REGEXP of \".*\"."
+  (declare (interactive-only t))
+  (interactive)
+  (let* ((other-prompts (denote-sort-dired--prompts))
+         (sort-key (nth 1 other-prompts))
+         (reverse (nth 2 other-prompts)))
+    (funcall-interactively #'my-denote-sort-dired-empty-files ".*" sort-key reverse)))
+
+(defun my-denote-sort-dired-without-all-empty-files ()
+  "List all empty files in a Dired buffer.
+This is the same as calling `my-denote-sort-dired' with a
+FILES-MATCHING-REGEXP of \".*\"."
+  (declare (interactive-only t))
+  (interactive)
+  (let* ((other-prompts (denote-sort-dired--prompts))
+         (sort-key (nth 1 other-prompts))
+         (reverse (nth 2 other-prompts)))
+    (funcall-interactively #'my-denote-sort-dired-without-empty-files ".*" sort-key reverse)))
+#+end_src
+
+[ In the above snippet, I am purposefully duplicating code to make it
+  easier for users to pick the ones they need. ]
+
+** Automatically rename the note after saving it
+:PROPERTIES:
+:CUSTOM_ID: h:c7d4dd3a-38bb-4f1c-a36e-989ec0bc79a6
+:END:
+
+While experimenting with Denote, users may need to try different
+workflows to figure out what works for them. Those might involve
+changing keywords and specifying titles in a particular way. The
+following sample can be used:
+
+#+begin_src emacs-lisp
+(defun my-denote-always-rename-on-save-based-on-front-matter ()
+  "Rename the current Denote file, if needed, upon saving the file.
+Rename the file based on its front matter, checking for changes in the
+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))
+      (ignore-errors (denote-rename-file-using-front-matter buffer-file-name))
+      (message "Buffer saved; Denote file renamed"))))
+
+(add-hook 'after-save-hook #'my-denote-always-rename-on-save-based-on-front-matter)
+#+end_src
+
+** Narrow the list of files in Dired
+:PROPERTIES:
+:CUSTOM_ID: h:ea173a01-69ef-4574-89a7-6e60ede02f13
+:END:
+
+Emacs' standard file manager (or directory editor) can read a regular
+expression to mark the matching files.  This is the command
+~dired-mark-files-regexp~, which is bound to =% m= by default.  For
+example, =% m _denote= will match all files that have the =denote=
+keyword ([[#h:1a953736-86c2-420b-b566-fb22c97df197][Features of the file-naming scheme for searching or filtering]]).
+
+Once the files are matched, the user has two options: (i) narrow the
+list to the matching items or (ii) exclude the matching items from the
+list.
+
+For the former, we want to toggle the marks by typing =t= (calls the
+command ~dired-toggle-marks~ by default) and then hit the letter =k=
+(for ~dired-do-kill-lines~).  The remaining files are those that match
+the regexp that was provided earlier.
+
+For the latter approach of filtering out the matching items, simply
+involves the use of the =k= command (~dired-do-kill-lines~) to omit the
+marked files from the list.
+
+These sequences can be combined to incrementally narrow the list.  Note
+that ~dired-do-kill-lines~ does not delete files: it simply hides them
+from the current view.
+
+Revert to the original listing with =g= (~revert-buffer~).
+
+For a convenient wrapper, consider this example:
+
+#+begin_src emacs-lisp
+(defvar prot-dired--limit-hist '()
+  "Minibuffer history for `prot-dired-limit-regexp'.")
+
+;;;###autoload
+(defun prot-dired-limit-regexp (regexp omit)
+  "Limit Dired to keep files matching REGEXP.
+
+With optional OMIT argument as a prefix (\\[universal-argument]),
+exclude files matching REGEXP.
+
+Restore the buffer with \\<dired-mode-map>`\\[revert-buffer]'."
+  (interactive
+   (list
+    (read-regexp
+     (concat "Files "
+             (when current-prefix-arg
+               (propertize "NOT " 'face 'warning))
+             "matching PATTERN: ")
+     nil 'prot-dired--limit-hist)
+    current-prefix-arg))
+  (dired-mark-files-regexp regexp)
+  (unless omit (dired-toggle-marks))
+  (dired-do-kill-lines))
+#+end_src
+
+** Use ~dired-virtual-mode~ for arbitrary file listings
+:PROPERTIES:
+:CUSTOM_ID: h:d35d8d41-f51b-4139-af8f-9c8cc508e35b
+:END:
+
+Emacs' Dired is a powerful file manager that builds its functionality
+on top of the Unix =ls= command.  As noted elsewhere in this manual,
+the user can update the =ls= flags that Dired uses to display its
+contents ([[#h:a7fd5e0a-78f7-434e-aa2e-e150479c16e2][I want to sort by last modified, why won't Denote let me?]]).
+
+What Dired cannot do is parse the output of a result that is produced
+by piped commands, such as =ls -l | sort -t _ -k2=.  This specific
+example targets the second underscore-separated field of the file
+name, per our conventions ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).  Conceretely, it
+matches the "alpha" as the sorting key in something like this:
+
+#+begin_src emacs-lisp
+20220929T200432--testing-file-one__alpha.txt
+#+end_src
+
+Consider then, how Dired will sort those files by their identifier:
+
+#+begin_src emacs-lisp
+20220929T200432--testing-file-one__alpha.txt
+20220929T200532--testing-file-two__beta.txt
+20220929T200632--testing-file-three__alpha.txt
+20220929T200732--testing-file-four__beta.txt
+#+end_src
+
+Whereas on the command line, we can get the following:
+
+#+begin_example
+$ ls | sort -t _ -k 2
+20220929T200432--testing-file-one__alpha.txt
+20220929T200632--testing-file-three__alpha.txt
+20220929T200532--testing-file-two__beta.txt
+20220929T200732--testing-file-four__beta.txt
+#+end_example
+
+This is where ~dired-virtual-mode~ shows its utility.  If we tweak our
+command-line invocation to include =ls -l=, this mode can behave like
+Dired on the listed files.  (We omit the output of the =-l= flag from
+this tutorial, as it is too verbose.)
+
+What we now need is to capture the output of =ls -l | sort -t _ -k 2=
+in an Emacs buffer and then enable ~dired-virtual-mode~.  To do that,
+we can rely on either =M-x shell= or =M-x eshell= and then manually
+copy the relevant contents.
+
+For the user's convenience, I share what I have for Eshell to quickly
+capture the last command's output in a dedicated buffer:
+
+#+begin_src emacs-lisp
+(defcustom prot-eshell-output-buffer "*Exported Eshell output*"
+  "Name of buffer with the last output of Eshell command.
+Used by `prot-eshell-export'."
+  :type 'string
+  :group 'prot-eshell)
+
+(defcustom prot-eshell-output-delimiter "* * *"
+  "Delimiter for successive `prot-eshell-export' outputs.
+This is formatted internally to have newline characters before
+and after it."
+  :type 'string
+  :group 'prot-eshell)
+
+(defun prot-eshell--command-prompt-output ()
+  "Capture last command prompt and its output."
+  (let ((beg (save-excursion
+               (goto-char (eshell-beginning-of-input))
+               (goto-char (point-at-bol)))))
+    (when (derived-mode-p 'eshell-mode)
+      (buffer-substring-no-properties beg (eshell-end-of-output)))))
+
+;;;###autoload
+(defun prot-eshell-export ()
+  "Produce a buffer with output of the last Eshell command.
+If `prot-eshell-output-buffer' does not exist, create it.  Else
+append to it, while separating multiple outputs with
+`prot-eshell-output-delimiter'."
+  (interactive)
+  (let ((eshell-output (prot-eshell--command-prompt-output)))
+    (with-current-buffer (get-buffer-create prot-eshell-output-buffer)
+      (let ((inhibit-read-only t))
+        (goto-char (point-max))
+        (unless (eq (point-min) (point-max))
+          (insert (format "\n%s\n\n" prot-eshell-output-delimiter)))
+        (goto-char (point-at-bol))
+        (insert eshell-output)
+        (switch-to-buffer-other-window (current-buffer))))))
+#+end_src
+
+Bind ~prot-eshell-export~ to a key in the ~eshell-mode-map~ and give
+it a try (I use =C-c C-e=).  In the produced buffer, activate the
+~dired-virtual-mode~.
+
+** Use Embark to collect minibuffer candidates
+:PROPERTIES:
+:CUSTOM_ID: h:edf9b651-86eb-4d5f-bade-3c9e270082f0
+:END:
+
+=embark= is a remarkable package that lets you perform relevant,
+context-dependent actions using a prefix key (simplifying in the
+interest of brevity).
+
+For our purposes, Embark can be used to produce a Dired listing
+directly from the minibuffer.  Suppose the current note has links to
+three other notes.  You might use the ~denote-find-link~ command to
+pick one via the minibuffer.  But why not turn those three links into
+their own Dired listing?  While in the minibuffer, invoke ~embark-act~
+which you may have already bound to =C-.= and then follow it up with
+=E= (for the ~embark-export~ command).
+
+This pattern can be repeated with any list of candidates, meaning that
+you can narrow the list by providing some input before eventually
+exporting the results with Embark.
+
+Overall, this is very powerful and you might prefer it over doing the
+same thing directly in Dired, since you also benefit from all the power
+of the minibuffer ([[#h:ea173a01-69ef-4574-89a7-6e60ede02f13][Narrow the list of files in Dired]]).
+
+** Search file contents
+:PROPERTIES:
+:CUSTOM_ID: h:76198fab-d6d2-4c67-9ccb-7a08cc883952
+:END:
+
+[ Users of ~consult~ can use the ~consult-denote~ package instead
+  ([[#h:113a13e1-35da-46f1-9414-81e9be2facc1][Use the ~consult-denote~ package for enhanced minibuffer interactions]]). ]
+
+Emacs provides built-in commands which are wrappers of standard Unix
+tools: =M-x grep= lets the user input the flags of a ~grep~ call and
+pass a regular expression to the =-e= flag.
+
+The author of Denote uses this thin wrapper instead:
+
+#+begin_src emacs-lisp
+(defvar prot-search--grep-hist '()
+  "Input history of grep searches.")
+
+;;;###autoload
+(defun prot-search-grep (regexp &optional recursive)
+  "Run grep for REGEXP.
+
+Search in the current directory using `lgrep'.  With optional
+prefix argument (\\[universal-argument]) for RECURSIVE, run a
+search starting from the current directory with `rgrep'."
+  (interactive
+   (list
+    (read-from-minibuffer (concat (if current-prefix-arg
+                                      (propertize "Recursive" 'face 'warning)
+                                    "Local")
+                                  " grep for PATTERN: ")
+                          nil nil nil 'prot-search--grep-hist)
+    current-prefix-arg))
+  (unless grep-command
+    (grep-compute-defaults))
+  (if recursive
+      (rgrep regexp "*" default-directory)
+    (lgrep regexp "*" default-directory)))
+#+end_src
+
+Rather than maintain custom code, consider using the excellent =consult=
+package: it provides commands such as ~consult-grep~ and ~consult-find~
+which provide live results and are generally easier to use than the
+built-in commands.
+
+** Bookmark the directory with the notes
+:PROPERTIES:
+:CUSTOM_ID: h:1bba4c1e-6812-4749-948f-57df4fd49b36
+:END:
+
+Part of the reason Denote does not reinvent existing functionality is to
+encourage you to learn more about Emacs.  You do not need a bespoke
+"jump to my notes" directory because such commands do not scale well.
+Will you have a "jump to my downloads" then another for multimedia and
+so on?  No.
+
+Emacs has a built-in framework for recording persistent markers to
+locations.  Visit the ~denote-directory~ (or any dir/file for that
+matter) and invoke the ~bookmark-set~ command (bound to =C-x r m= by
+default).  It lets you create a bookmark.
+
+The list of bookmarks can be reviewed with the ~bookmark-bmenu-list~
+command (bound to =C-x r l= by default).  A minibuffer interface is
+available with ~bookmark-jump~ (=C-x r b=).
+
+If you use the =consult= package, its default ~consult-buffer~ command
+has the means to group together buffers, recent files, and bookmarks.
+Each of those types can be narrowed to with a prefix key.  The package
+=consult-dir= is an extension to =consult= which provides useful extras
+for working with directories, including bookmarks.
+
+** Treat your notes as a project
+:PROPERTIES:
+:CUSTOM_ID: h:fad3eb08-ddc7-43e4-ba28-210d89668037
+:END:
+
+Emacs has a built-in library for treating a directory tree as a
+"project".  This means that the contents of this tree are seen as part
+of the same set, so commands like ~project-switch-to-buffer~ (=C-x p b=
+by default) will only consider buffers in the current project
+(e.g. three notes that are currently being visited).
+
+Normally, a "project" is a directory tree whose root is under version
+control.  For our purposes, all you need is to navigate to the
+~denote-directory~ (for the shell or via Dired) and use the command-line
+to run this (requires the =git= executable):
+
+: git init
+
+From Dired, you can type =M-!= which invokes ~dired-smart-shell-command~
+and then run the git call there.
+
+The project can then be registered by invoking any project-related
+command inside of it, such as ~project-find-file~ (=C-x p f=).
+
+It is a good idea to keep your notes under version control, as that
+gives you a history of changes for each file.  We shall not delve into
+the technicalities here, though suffice to note that Emacs' built-in
+version control framework or the exceptionally well-crafted =magit=
+package will get the job done (VC can work with other backends besides
+Git).
+
+** Use the tree-based file prompt for select commands
+:PROPERTIES:
+:CUSTOM_ID: h:8f9e0971-8b30-4e7b-af79-8fed257dbcfa
+:END:
+
+Older versions of Denote had a file prompt that resembled that of the
+standard ~find-file~ command (bound to =C-x C-f= by default).  This
+means that it used a tree-based method of navigating the filesystem by
+selecting the specific directory and then the given file.
+
+Currently, Denote flattens the file prompt so that every file in the
+~denote-directory~ and its subdirectories can be matched from anywhere
+using the power of Emacs' minibuffer completion (such as with the help
+of the ~orderless~ package in addition to built-in options).
+
+Users who need the old behaviour on a per-command basis can define
+their own wrapper functions as shown in the following code block.
+
+#+begin_src emacs-lisp
+;; This is the old `denote-file-prompt' that we renamed to
+;; `denote-file-prompt-original' for clarity.
+(defun denote-file-prompt-original (&optional initial-text)
+  "Prompt for file with identifier in variable `denote-directory'.
+With optional INITIAL-TEXT, use it to prepopulate the minibuffer."
+  (read-file-name "Select note: " (denote-directory) nil nil initial-text
+                  (lambda (f)
+                    (or (denote-file-has-identifier-p f)
+                        (file-directory-p f)))))
+
+;; Our wrapper command that changes the current `denote-file-prompt'
+;; to the functionality of `denote-file-prompt-original' only when
+;; this command is used.
+(defun my-denote-link ()
+  "Call `denote-link' but use Denote's original file prompt.
+See `denote-file-prompt-original'."
+  (interactive)
+  (cl-letf (((symbol-function 'denote-file-prompt) #'denote-file-prompt-original))
+    (call-interactively #'denote-link)))
+#+end_src
+
+** Rename files with Denote in the Image Dired thumbnails buffer
+:PROPERTIES:
+:CUSTOM_ID: h:e666ced6-da75-4bdb-9be3-82c2f4455ee9
+:END:
+
+[[#h:2d5ee9bf-e8f2-426c-8bf7-bf78bc88d1ee][Rename files with Denote using ~dired-preview~]]
+
+Just as with the ~denote-dired-rename-marked-files-with-keywords~,
+we can use Denote in the Image Dired buffer ([[#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde][Rename multiple files at once]]).
+Here is the custom code:
+
+#+begin_src emacs-lisp
+(autoload 'image-dired--with-marked "image-dired")
+(autoload 'image-dired-original-file-name "image-dired-util")
+
+(defun my-denote-image-dired-rename-marked-files (keywords)
+  "Like `denote-dired-rename-marked-files-with-keywords' but for Image Dired.
+Prompt for KEYWORDS and rename all marked files in the Image
+Dired buffer to have a Denote-style file name with the given
+KEYWORDS.
+
+IMPORTANT NOTE: if there are marked files in the corresponding
+Dired buffers, those will be targeted as well.  This is not the
+fault of Denote: it is how Dired and Image Dired work in tandem.
+To only rename the marked thumbnails, start by unmarking
+everything in Dired.  Then mark the items in Image Dired and
+invoke this command."
+  (interactive (list (denote-keywords-prompt)) image-dired-thumbnail-mode)
+  (image-dired--with-marked
+   (when-let* ((file (image-dired-original-file-name))
+               (dir (file-name-directory file))
+               (id (or (denote-retrieve-filename-identifier file) ""))
+               (file-type (denote-filetype-heuristics file))
+               (title (denote--retrieve-title-or-filename file file-type))
+               (signature (or (denote-retrieve-filename-signature file) "")
+               (extension (file-name-extension file t))
+               (new-name (denote-format-file-name dir id keywords title extension signature))
+               (default-directory dir))
+     (denote-rename-file-and-buffer file new-name))))
+#+end_src
+
+While the ~my-denote-image-dired-rename-marked-files~ renames files in
+the helpful Denote-compliant way, users may still need to not prepend
+a unique identifier and not sluggify (hyphenate and downcase) the
+image's existing file name.  To this end, the following custom command
+can be used instead:
+
+#+begin_src emacs-lisp
+(defun my-image-dired-rename-marked-files (keywords)
+  "Like `denote-dired-rename-marked-files-with-keywords' but for Image Dired.
+Prompt for keywords and rename all marked files in the Image
+Dired buffer to have Denote-style keywords, but none of the other
+conventions of Denote's file-naming scheme."
+  (interactive (list (denote-keywords-prompt)) image-dired-thumbnail-mode)
+  (image-dired--with-marked
+   (when-let* ((file (image-dired-original-file-name))
+               (dir (file-name-directory file))
+               (file-type (denote-filetype-heuristics file))
+               (title (denote--retrieve-title-or-filename file file-type))
+               (extension (file-name-extension file t))
+               (kws (denote--keywords-combine keywords))
+               (new-name (concat dir title "__" kws extension))
+               (default-directory dir))
+     (denote-rename-file-and-buffer file new-name))))
+#+end_src
+
+** Rename files with Denote using ~dired-preview~
+:PROPERTIES:
+:CUSTOM_ID: h:2d5ee9bf-e8f2-426c-8bf7-bf78bc88d1ee
+:END:
+
+The ~dired-preview~ package (by me/Protesilaos) automatically displays
+a preview of the file at point in Dired.  This can be helpful in
+tandem with Denote when we want to rename multiple files by taking a
+quick look at their contents.
+
+The command ~denote-dired-rename-marked-files-with-keywords~
+will generate Denote-style file names based on the keywords it prompts
+for. Identifiers are derived from each file's modification date
+([[#h:1b6b2c78-42f0-45b8-9ef0-6de21a8b2cde][Rename multiple files at once]]). There is no need for any custom code
+in this scenario.
+
+As noted in the section about Image Dired, the user may sometimes not
+need a fully fledged Denote-style file name but only append Denote-like
+keywords to each file name (e.g. =Original Name__denote_test.jpg=
+instead of =20230710T195843--original-name__denote_test.jpg=).
+
+[[#h:e666ced6-da75-4bdb-9be3-82c2f4455ee9][Rename files with Denote in the Image Dired thumbnails buffer]]
+
+In such a workflow, it is unlikely to be dealing with ordinary text
+files where front matter can be helpful.  A custom command does not
+need to behave like what Denote provides out-of-the-box, but can
+instead append keywords to file names without conducting any further
+actions.  We thus have:
+
+#+begin_src emacs-lisp
+(defun my-denote-dired-rename-marked-files-keywords-only ()
+  "Like `denote-dired-rename-marked-files-with-keywords' but only for keywords in file names.
+
+Prompt for keywords and rename all marked files in the Dired
+buffer to only have Denote-style keywords, but none of the other
+conventions of Denote's file-naming scheme."
+  (interactive nil dired-mode)
+  (if-let* ((marks (dired-get-marked-files)))
+      (let ((keywords (denote-keywords-prompt)))
+        (dolist (file marks)
+          (let* ((dir (file-name-directory file))
+                 (file-type (denote-filetype-heuristics file))
+                 (title (denote--retrieve-title-or-filename file file-type))
+                 (extension (file-name-extension file t))
+                 (kws (denote--keywords-combine keywords))
+                 (new-name (concat dir title "__" kws extension)))
+            (denote-rename-file-and-buffer file new-name)))
+        (revert-buffer))
+    (user-error "No marked files; aborting")))
+#+end_src
+
+** Avoid duplicate identifiers when exporting Denote notes
+:PROPERTIES:
+:CUSTOM_ID: h:4a8c4546-26b3-4195-8b2c-b08a519986a4
+:END:
+
+When exporting Denote notes to, for example, an HTML or PDF file,
+there is a high probability that the same file name is used with a new
+extension.  This is problematic because it creates files with
+duplicate identifiers.  The =20230515T085612--example__keyword.org=
+produces a =20230515T085612--example__keyword.pdf=.  Any link to the
+=20230515T085612= will thus break: it does not honor Denote's
+expectation of finding unique identifiers.  This is not the fault of
+Denote: exporting is done by the user without Denote's involvement.
+
+Org Mode and Markdown use different approaches to exporting files.  No
+recommended method is available for plain text files as there is no
+standardised export functionality for this format (the user can always
+create a new note using the file type they want on a case-by-case
+basis: [[#h:887bdced-9686-4e80-906f-789e407f2e8f][Convenience commands for note creation]]).
+
+*** Export Denote notes with Org Mode
+:PROPERTIES:
+:CUSTOM_ID: h:67669d9d-17c3-45bd-8227-da57d8bc3b73
+:END:
+
+Org Mode has a built-in configurable export engine.  You can prevent
+duplicate identifiers when exporting manually for each exported file
+or by advising the Org export function.
+
+The ~denote-org~ package (by Protesilaos) also provides commands to
+convert =denote:= links to their =file:= equivalent, in case this is a
+required pre-processing step for export purposes.
+
+**** Manually configure Org export
+:PROPERTIES:
+:CUSTOM_ID: h:bf791e28-73e5-4ed8-88bc-e4e9b3ebaedb
+:END:
+
+Insert =#+export_file_name: FILENAME= in the front matter before
+exporting to force a filename called whatever the value of =FILENAME=
+is.  The =FILENAME= does not specify the file type extension, such as
+=.pdf=.  This is up to the export engine.  For example, a Denote note
+with a complete file name of =20230515T085612--example__keyword.org=
+and a front matter entry of =#+export_file_name: hello= will be
+exported as =hello.pdf=.
+
+The advantage of this manual method is that it gives the user full
+control over the resulting file name.  The disadvantage is that it
+depends on the user's behaviour.  Forgetting to add a new name can
+lead to duplicate identifiers, as already noted in the introduction to
+this section ([[#h:4a8c4546-26b3-4195-8b2c-b08a519986a4][Export Denote notes]]).
+
+**** Automatically store Org exports in another folder
+:PROPERTIES:
+:CUSTOM_ID: h:7a61a370-78e5-42a1-9650-98fee140723f
+:END:
+
+It is possible to automatically place all exports in another folder by
+making Org's function ~org-export-output-file-name~ create the target
+directory if needed and move the exported file there.  Remember that
+advising Elisp code must be handled with care, as it might break the
+original function in subtle ways.
+
+#+begin_src emacs-lisp
+(defvar my-org-export-output-directory-prefix "./export_"
+  "Prefix of directory used for org-mode export.
+
+The single dot means that the directory is created on the same
+level as the one where the Org file that performs the exporting
+is.  Use two dots to place the directory on a level above the
+current one.
+
+If this directory is part of `denote-directory', make sure it is
+not read by Denote.  See `denote-excluded-directories-regexp'.
+This way there will be no known duplicate Denote identifiers
+produced by the Org export mechanism.")
+
+(defun my-org-export-create-directory (fn extension &rest args)
+  "Move Org export file to its appropriate directory.
+
+Append the file type EXTENSION of the exported file to
+`my-org-export-output-directory-prefix' and, if absent, create a
+directory named accordingly.
+
+Install this as advice around `org-export-output-file-name'.  The
+EXTENSION is supplied by that function.  ARGS are its remaining
+arguments."
+  (let ((export-dir (format "%s%s" my-org-export-output-directory-prefix extension)))
+    (unless (file-directory-p export-dir)
+      (make-directory export-dir)))
+  (apply fn extension args))
+
+(advice-add #'org-export-output-file-name :around #'my-org-export-create-directory)
+#+end_src
+
+The target export directory should not be a subdirectory of
+~denote-directory~, as that will result in duplicate identifiers.
+Exclude it with the ~denote-excluded-directories-regexp~ user option
+([[#h:8458f716-f9c2-4888-824b-2bf01cc5850a][Exclude certain directories from all operations]]).
+
+[ NOTE: I (Protesilaos) am not a LaTeX user and cannot test the
+  following. ]
+
+Using a different directory will require some additional configuration
+when exporting using LaTeX.  The export folder cannot be inside the
+path of the ~denote-directory~ to prevent Denote from recognising it
+as an attachment:
+<https://emacs.stackexchange.com/questions/45751/org-export-to-different-directory>.
+
+**** Org Mode Publishing
+:PROPERTIES:
+:CUSTOM_ID: h:2f3451ed-2fc4-4f36-bcf2-112939963e20
+:END:
+
+Org Mode also has a publishing tool for exporting a collection of
+files. Some user might apply this approach to convert their note
+collection to a public or private website.
+
+The ~org-publish-project-alist~ variable drives the publishing
+process, including the publishing directory.
+
+The publishing directory should not be a subdirectory of
+~denote-directory~, as that will result in duplicate identifiers.
+Exclude it with the ~denote-excluded-directories-regexp~ user option
+([[#h:8458f716-f9c2-4888-824b-2bf01cc5850a][Exclude certain directories from all operations]]).
+
+*** Export Denote notes with Markdown
+:PROPERTIES:
+:CUSTOM_ID: h:44c6a34a-e9ad-4f43-a24f-12f2c5a8467e
+:END:
+
+Exporting from Markdown requires an external processor (e.g.,
+Markdown.pl, Pandoc, or MultiMarkdown).  The ~markdown-command~
+variable defines the command line used in export, for example:
+
+#+begin_src emacs-lisp
+(setq markdown-command "multimarkdown")
+#+end_src
+
+The export process thus occurs outside of Emacs.  Users need to read
+the documentation of their preferred processor to prevent the creation
+of duplicate Denote identifiers.
+
+** Set up your workflow for daily or weekly meeting notes
+:PROPERTIES:
+:CUSTOM_ID: h:00998f94-0194-43ef-b349-260106ef7177
+:END:
+
+Perhaps as part of work, we meet with certain people on a regular
+basis. During the meeting we may discuss a variety of topics. How best
+to approach with the help of Denote?
+
+One option is to write a new file for each meeting, giving it the
+appropriate keywords each time ([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]). This is what Denote
+does by default and does not need any further tweaks. If we need to
+review those notes, we can use the command ~denote-sort-dired~
+([[#h:9fe01e63-f34f-4479-8713-f162a5ca865e][Sort files by component]]), or one of the Org dynamic blocks we provide
+([[#h:8b542c50-dcc9-4bca-8037-a36599b22779][Use Org dynamic blocks]]), among other options.
+
+Another approach is to write one file per person with the regular
+~denote~ command (or related), give it the name of the person as a
+title and, optionally, use some relevant keywords. Inside each file,
+write a top-level heading with the date of the meeting, and then
+produce the meeting notes below as paragraphs and subheadings. This
+can all be done without any changes to Denote, though we can
+streamline it by incorporating the following code in our setup.
+Configure ~my-denote-colleagues~ and then use the command
+~my-denote-colleagues-new-meeting~ to see how it works.
+
+#+begin_src emacs-lisp
+(defvar my-denote-colleagues '("Prot" "Protesilaos")
+  "List of names I collaborate with.
+There is at least one file in the variable `denote-directory' that has
+the name of this person.")
+
+(defvar my-denote-colleagues-prompt-history nil
+  "Minibuffer history for `my-denote-colleagues-new-meeting'.")
+
+(defun my-denote-colleagues-prompt ()
+  "Prompt with completion for a name among `my-denote-colleagues'.
+Use the last input as the default value."
+  (let ((default-value (car my-denote-colleagues-prompt-history)))
+    (completing-read
+     (format-prompt "New meeting with COLLEAGUE" default-value)
+     my-denote-colleagues
+     nil :require-match nil
+     'my-denote-colleagues-prompt-history
+     default-value)))
+
+(defun my-denote-colleagues-get-file (name)
+  "Find file in variable `denote-directory' for NAME colleague.
+If there are more than one files, prompt with completion for one among
+them.
+
+NAME is one among `my-denote-colleagues'."
+  (if-let* ((files (denote-directory-files name))
+            (length-of-files (length files)))
+      (cond
+       ((= length-of-files 1)
+        (car files))
+       ((> length-of-files 1)
+        (completing-read "Select a file: " files nil :require-match)))
+    (user-error "No files for colleague with name `%s'" name)))
+
+(defun my-denote-colleagues-new-meeting ()
+  "Prompt for the name of a colleague and insert a timestamped heading therein.
+The name of a colleague corresponds to at least one file in the variable
+`denote-directory'.  In case there are multiple files, prompt to choose
+one among them and operate therein."
+  (declare (interactive-only t))
+  (interactive)
+  (let* ((name (my-denote-colleagues-prompt))
+         (file (my-denote-colleagues-get-file name))
+         (time (format-time-string "%F %a %R")))  ; remove %R if you do not want the time
+    (with-current-buffer (find-file file)
+      (goto-char (point-max))
+      ;; Here I am assuming we are in `org-mode', hence the leading
+      ;; asterisk for the heading.  Adapt accordingly.
+      (insert (format "* [%s]\n\n" time)))))
+#+end_src
+
+* For developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:c916d8c5-540a-409f-b780-6ccbd90e088e
+:END:
+
+Denote is in a stable state and can be relied upon as the basis for
+custom extensions ([[#h:08b14682-e73f-4b11-b2e2-be3b788c8572][Packages that build on Denote]]). Further below is a
+list with the functions or variables we provide for public usage.
+Those are in addition to all user options and commands that are
+already documented in the various sections of this manual.
+
+In this context "public" is any form with single hyphens in its symbol,
+such as ~denote-directory-files~.  We expressly support those, meaning
+that we consider them reliable and commit to documenting any changes in
+their particularities (such as through ~make-obsolete~, a record in the
+change log, a blog post on the maintainer's website, and the like).
+
+By contradistinction, a "private" form is declared with two hyphens in
+its symbol such as ~denote--file-extension~.  Do not use those as we
+might change them without further notice.
+
+The following sections cover the specifics.
+
+** Common building blocks for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:c98aed45-341a-40a0-91ce-347a29c98ab4
+:END:
+
+#+vindex: denote-id-format
++ Variable ~denote-id-format~ :: Format of ID prefix of a note's
+  filename.  The note's ID is derived from the date and time of its
+  creation ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+#+vindex: denote-id-regexp
++ Variable ~denote-id-regexp~ :: Regular expression to match
+  ~denote-id-format~.
+
+#+vindex: denote-signature-regexp
++ Variable ~denote-signature-regexp~ :: Regular expression to match
+  the =SIGNATURE= field in a file name.
+
+#+vindex: denote-title-regexp
++ Variable ~denote-title-regexp~ :: Regular expression to match the
+  =TITLE= field in a file name ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+#+vindex: denote-keywords-regexp
++ Variable ~denote-keywords-regexp~ :: Regular expression to match the
+  =KEYWORDS= field in a file name ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+#+findex: denote-identifier-p
++ Function ~denote-identifier-p~ :: Return non-nil if =IDENTIFIER=
+  string is a Denote 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.
+
+#+findex: denote-file-has-denoted-filename-p
++ Function ~denote-file-has-denoted-filename-p~ :: Return non-nil if
+  =FILE= respects the file-naming scheme of Denote. This tests the
+  rules of Denote's file-naming scheme. Sluggification is ignored. It
+  is done by removing all file name components and validating what
+  remains.
+
+#+findex: denote-file-has-signature-p
++ Function ~denote-file-has-signature-p~ :: Return non-nil if =FILE=
+  has a signature.
+
+#+findex: denote-file-has-supported-extension-p
++ Function ~denote-file-has-supported-extension-p~ :: Return non-nil
+  if =FILE= has supported extension.  Also account for the possibility
+  of an added =.gpg= suffix. Supported extensions are those implied by
+  ~denote-file-type~.
+
+#+findex: denote-file-is-writable-and-supported-p
++ Function ~denote-file-is-writable-and-supported-p~ :: Return non-nil
+  if =FILE= is writable and has supported extension.
+
+#+findex: denote-file-type-extensions
++ Function ~denote-file-type-extensions~ :: Return all file type
+  extensions in ~denote-file-types~.
+
+#+vindex: denote-encryption-file-extensions
++ Variable ~denote-encryption-file-extensions~ :: List of strings
+  specifying file extensions for encryption.
+
+#+findex: denote-file-type-extensions-with-encryption
++ Function ~denote-file-type-extensions-with-encryption~ :: Derive
+  ~denote-file-type-extensions~ plus ~denote-encryption-file-extensions~.
+
+#+findex: denote-get-file-extension
++ Function ~denote-get-file-extension~ :: Return extension of =FILE=
+  with dot included.  Account for ~denote-encryption-file-extensions~.
+  In other words, return something like =.org.gpg= if it is part of
+  the file, else return =.org=.
+
+#+findex: denote-get-file-extension-sans-encryption
++ Function ~denote-get-file-extension-sans-encryption~ :: Return
+  extension of =FILE= with dot included and without the encryption
+  part.  Build on top of ~denote-get-file-extension~ though always
+  return something like =.org= even if the actual file extension is
+  =.org.gpg=.
+
+#+findex: denote-infer-keywords-from-files
++ Functions ~denote-infer-keywords-from-files~ :: Return list of
+  keywords in ~denote-directory-files~. With optional
+  =FILES-MATCHING-REGEXP=, only extract keywords from the matching
+  files. Otherwise, do it for all files. Keep any duplicates. Users
+  who do not want duplicates should refer to the functions
+  ~denote-keywords~.
+
+#+findex: denote-keywords
++ Function ~denote-keywords~ :: Return appropriate list of keyword
+  candidates. If ~denote-infer-keywords~ is non-nil, infer keywords
+  from existing notes and combine them into a list with
+  ~denote-known-keywords~. Else use only the latter set of keywords
+  ([[#h:6a92a8b5-d766-42cc-8e5b-8dc255466a23][Standard note creation]]). In the case of keyword inferrence, use
+  optional =FILES-MATCHING-REGEXP=, to extract keywords only from the
+  matching files. Otherwise, do it for all files. Filter inferred
+  keywords with the user option ~denote-excluded-keywords-regexp~.
+
+#+findex: denote-keywords-sort
++ Function ~denote-keywords-sort~ :: Sort =KEYWORDS= if
+  ~denote-sort-keywords~ is non-nil.  =KEYWORDS= is a list of strings,
+  per ~denote-keywords-prompt~.
+
+#+findex: denote-keywords-combine
++ Function ~denote-keywords-combine~ :: Combine =KEYWORDS= list of
+  strings into a single string. Keywords are separated by the
+  underscore character, per the Denote file-naming scheme.
+
+#+findex: denote-valid-date-p
++ Function ~denote-valid-date-p~ :: Return =DATE= as a valid date. A
+  valid =DATE= is a value that can be parsed by either ~decode-time~
+  or ~date-to-time~ .Those functions signal an error if =DATE= is a
+  value they do not recognise. If =DATE= is nil, return nil.
+
+#+findex: denote-directory
++ Function ~denote-directory~ :: Return path of the variable
+  ~denote-directory~ as a proper directory, also because it accepts a
+  directory-local value for what we internally refer to as "silos"
+  ([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directories for notes]]).  Custom Lisp code can
+  ~let~ bind the value of the variable ~denote-directory~
+  to override what this function returns.
+
+#+findex: denote-directory-files
++ Function ~denote-directory-files~ :: Return list of absolute file
+  paths in variable ~denote-directory~. Files that match
+  ~denote-excluded-files-regexp~ are excluded from the list. Files
+  only need to have an identifier. The return value may thus include
+  file types that are not implied by ~denote-file-type~. With optional
+  =FILES-MATCHING-REGEXP=, restrict files to those matching the given
+  regular expression. With optional =OMIT-CURRENT= as a non-nil value,
+  do not include the current Denote file in the returned list. With
+  optional =TEXT-ONLY= as a non-nil value, limit the results to text
+  files that satisfy ~denote-file-is-note-p~. With optional
+  =EXCLUDE-REGEXP= exclude the files that match the given regular
+  expression. This is done after =FILES-MATCHING-REGEXP= and
+  =OMIT-CURRENT= have been applied.
+
+#+findex: denote-directory-subdirectories
++ Function ~denote-directory-subdirectories~ :: Return list of
+  subdirectories in variable ~denote-directory~. Omit dotfiles (such
+  as .git) unconditionally.  Also exclude whatever matches
+  ~denote-excluded-directories-regexp~.  Note that the
+  ~denote-directory~ accepts a directory-local value for what we call
+  "silos" ([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directories for notes]]).
+
+** File path interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:08e696e4-c9e1-48b4-8349-e53451aed1df
+:END:
+
+#+findex: denote-file-name-relative-to-denote-directory
++ Function ~denote-file-name-relative-to-denote-directory~ :: Return
+  name of =FILE= relative to the variable ~denote-directory~.  =FILE=
+  must be an absolute path.
+
+#+findex: denote-slug-keep-only-ascii
++ Function ~denote-slug-keep-only-ascii~ :: Remove all non-ASCII
+  characters from =STR= and replace them with spaces. This is useful
+  as a helper function to construct ~denote-file-name-slug-functions~
+  ([[#h:d1e4eb5b-e7f2-4a3b-9243-e1c653817a4a][Custom sluggification to remove non-ASCII characters]]).
+
+#+findex: denote-sluggify
++ Function ~denote-sluggify~ :: Make =STR= an appropriate slug for
+  file name =COMPONENT= ([[#h:ae8b19a1-7f67-4258-96b3-370a72c43f4e][Sluggification of file name components]]).
+  Apply the function specified in ~denote-file-name-slug-function~ to
+  =COMPONENT= which is one of =title=, =signature=, =keyword=. If the
+  resulting string still contains consecutive =-=,=_= or ~=~, they are
+  replaced by a single occurence of the character, if necessary
+  according to =COMPONENT=. If =COMPONENT= is ~keyword~, remove
+  underscores from =STR= as they are used as the keywords separator in
+  file names.
+
+#+findex: denote-sluggify-keyword
++ Function ~denote-sluggify-keyword~ :: Sluggify =STR= while joining
+  separate words.
+
+#+findex: denote-sluggify-signature
++ Function ~denote-sluggify-signature~ :: Make =STR= an appropriate
+  slug for signatures ([[#h:ae8b19a1-7f67-4258-96b3-370a72c43f4e][Sluggification of file name components]]).
+
+#+findex: denote-sluggify-keywords
++ Function ~denote-sluggify-keywords~ :: Sluggify =KEYWORDS=, which is
+  a list of strings ([[#h:ae8b19a1-7f67-4258-96b3-370a72c43f4e][Sluggification of file name components]]).
+
+#+findex: denote-use-date
++ Function ~denote-use-date~ :: The date to be used in a note creation
+  command. See the documentation of ~denote~ for acceptable values.
+  This variable is ignored if nil. Only ever ~let~ bind this,
+  otherwise the title will always be the same and the title prompt
+  will be skipped.
+
+#+findex: denote-use-directory
++ Function ~denote-use-directory~ :: The directory to be used in a
+  note creation command. See the documentation of ~denote~ for
+  acceptable values. This variable is ignored if nil. Only ever ~let~
+  bind this, otherwise the title will always be the same and the title
+  prompt will be skipped.
+
+#+findex: denote-use-file-type
++ Function ~denote-use-file-type~ :: The file type to be used in a
+  note creation command. See the documentation of ~denote~ for
+  acceptable values. This variable is ignored if nil. Only ever ~let~
+  bind this, otherwise the title will always be the same and the title
+  prompt will be skipped.
+
+#+findex: denote-use-keywords
++ Function ~denote-use-keywords~ :: The keywords to be used in a note
+  creation command. See the documentation of ~denote~ for acceptable
+  values. This variable is ignored if ~default~. Only ever ~let~ bind this,
+  otherwise the title will always be the same and the title prompt
+  will be skipped.
+
+#+findex: denote-use-signature
++ Function ~denote-use-signature~ :: The signature to be used in a
+  note creation command. See the documentation of ~denote~ for
+  acceptable values. This variable is ignored if nil. Only ever ~let~
+  bind this, otherwise the title will always be the same and the title
+  prompt will be skipped.
+
+#+findex: denote-use-template
++ Function ~denote-use-template~ :: The template to be used in a note
+  creation command. See the documentation of ~denote~ for acceptable
+  values. This variable is ignored if nil. Only ever ~let~ bind this,
+  otherwise the title will always be the same and the title prompt
+  will be skipped.
+
+#+findex: denote-use-title
++ Function ~denote-use-title~ :: The title to be used in a note
+  creation command. See the documentation of ~denote~ for acceptable
+  values. This variable is ignored if nil. Only ever ~let~ bind this,
+  otherwise the title will always be the same and the title prompt
+  will be skipped.
+
+#+findex: denote-format-file-name
++ Function ~denote-format-file-name~ :: Format file name. =DIR-PATH=,
+  =ID=, =KEYWORDS=, =TITLE=, =EXTENSION= and =SIGNATURE= are expected to
+  be supplied by ~denote~ or equivalent command.
+
+  =DIR-PATH= is a string pointing to a directory. It ends with a
+  forward slash (the function ~denote-directory~ makes sure this is
+  the case when returning the value of the variable ~denote-directory~).
+  =DIR-PATH= cannot be nil or an empty string.
+
+  =ID= is a string holding the identifier of the note. It can be an
+  empty string, in which case its respective file name component is
+  not added to the base file name.
+
+  =DIR-PATH= and =ID= form the base file name.
+
+  =KEYWORDS= is a list of strings that is reduced to a single string
+  by ~denote-keywords-combine~. =KEYWORDS= can be an empty list or a
+  nil value, in which case the relevant file name component is not
+  added to the base file name.
+
+  =TITLE= and =SIGNATURE= are strings. They can be an empty string, in
+  which case their respective file name component is not added to the
+  base file name.
+
+  =EXTENSION= is a string that contains a dot followed by the file
+  type extension. It can be an empty string or a nil value, in which
+  case it is not added to the base file name.
+
+** Data retrieval interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:9b32bf7d-1569-4495-801c-8835f022d72e
+:END:
+
+#+findex: denote-get-path-by-id
++ 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
+  Denote-style file name where keywords are prefixed with an
+  underscore.  If =PATH= has no such keywords, which is possible,
+  return nil ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming scheme]]).
+
+#+findex: denote-extract-id-from-string
++ Function ~denote-extract-id-from-string~ :: Return existing Denote
+  identifier in =STRING=, else nil.
+
+#+findex: denote-retrieve-filename-identifier
++ Function ~denote-retrieve-filename-identifier~ :: Extract identifier
+  from =FILE= name, if present, else return nil. To create a new one
+  from a date, refer to the ~denote-get-identifier~ function.
+
+#+findex: denote-retrieve-filename-title
++ Function ~denote-retrieve-filename-title~ ::  Extract Denote title
+  component from =FILE= name, if present, else return nil.
+
+#+findex: denote-retrieve-filename-keywords
++ Function ~denote-retrieve-filename-keywords~ ::  Extract keywords
+  from =FILE= name, if present, else return nil. Return
+  matched keywords as a single string.
+
+#+findex: denote-retrieve-filename-signature
++ Function ~denote-retrieve-filename-signature~ :: Extract signature
+  from =FILE= name, if present, else return nil.
+
+#+findex: denote-retrieve-title-or-filename
++ Function ~denote-retrieve-title-or-filename~ :: Return appropriate
+  title for =FILE= given its =TYPE=. This is a wrapper for
+  ~denote-retrieve-front-matter-title-value~ and
+  =denote-retrieve-filename-title=.
+
+#+findex: denote-get-identifier
++ Function ~denote-get-identifier~ :: Convert =DATE= into a Denote
+  identifier using ~denote-id-format~. If =DATE= is nil, return an
+  empty string as the identifier.
+
+#+findex: denote-retrieve-front-matter-title-value
++ Function ~denote-retrieve-front-matter-title-value~ :: Return title value from
+  =FILE= front matter per =FILE-TYPE=.
+
+#+findex: denote-retrieve-front-matter-title-line
++ Function ~denote-retrieve-front-matter-title-line~ :: Return title line from
+  =FILE= front matter per =FILE-TYPE=.
+
+#+findex: denote-retrieve-front-matter-keywords-value
++ Function ~denote-retrieve-front-matter-keywords-value~ :: Return keywords value
+  from =FILE= front matter per =FILE-TYPE=. The return value is a list
+  of strings.
+
+#+findex: denote-retrieve-front-matter-keywords-line
++ Function ~denote-retrieve-front-matter-keywords-line~ :: Return keywords line
+  from =FILE= front matter per =FILE-TYPE=.
+
+** Prompt interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:e9d05541-bd00-43b9-8146-8c4445f78f07
+:END:
+
+#+findex: denote-add-prompts
++ Function ~denote-add-prompts~ :: Add list of =ADDITIONAL-PROMPTS= to
+  ~denote-prompts~. This is best done inside of a ~let~ to create a
+  wrapper function around ~denote~, ~denote-rename-file~, and
+  generally any command that consults the value of ~denote-prompts~.
+
+#+findex: denote-signature-prompt
++ Function ~denote-signature-prompt~ :: Prompt for signature string.
+  With optional =INITIAL-SIGNATURE= use it as the initial minibuffer
+  text. With optional =PROMPT-TEXT= use it in the minibuffer instead
+  of the default prompt. Previous inputs at this prompt are available
+  for minibuffer completion if the user option ~denote-history-completion-in-prompts~
+  is set to a non-nil value ([[#h:403422a7-7578-494b-8f33-813874c12da3][The ~denote-history-completion-in-prompts~ option]]).
+
+#+findex: denote-file-prompt
++ Function ~denote-file-prompt~ :: Prompt for file in variable
+  ~denote-directory~. Files that match ~denote-excluded-files-regexp~
+  are excluded from the list. With optional =FILES-MATCHING-REGEXP=,
+  filter the candidates per the given regular expression. With
+  optional =PROMPT-TEXT=, use it instead of the default call to select
+  a file. With optional =NO-REQUIRE-MATCH= accept the given input
+  as-is. Return the absolute path to the matching file.
+
+#+findex: denote-keywords-prompt
++ Function ~denote-keywords-prompt~ :: Prompt for one or more keywords.
+  Read entries as separate when they are demarcated by the
+  ~crm-separator~, which typically is a comma. With optional
+  =PROMPT-TEXT=, use it to prompt the user for keywords. Else use a
+  generic prompt. With optional =INITIAL-KEYWORDS= use them as the
+  initial minibuffer text.
+
+#+findex: denote-title-prompt
++ Function ~denote-title-prompt~ :: Prompt for title string. With
+  optional =INITIAL-TITLE= use it as the initial minibuffer text. With
+  optional =PROMPT-TEXT= use it in the minibuffer instead of the
+  default prompt. Previous inputs at this prompt are available
+  for minibuffer completion if the user option ~denote-history-completion-in-prompts~
+  is set to a non-nil value ([[#h:403422a7-7578-494b-8f33-813874c12da3][The ~denote-history-completion-in-prompts~ option]]).
+
+#+vindex: denote-title-prompt-current-default
++ Variable ~denote-title-prompt-current-default~ :: Currently bound
+  default title for ~denote-title-prompt~.  Set the value of this
+  variable within the lexical scope of a command that needs to supply
+  a default title before calling ~denote-title-prompt~ and use
+  ~unwind-protect~ to set its value back to nil.
+
+#+findex: denote-file-type-prompt
++ Function ~denote-file-type-prompt~ :: Prompt for ~denote-file-type~.
+  Note that a non-nil value other than ~text~, ~markdown-yaml~, and
+  ~markdown-toml~ falls back to an Org file type.  We use ~org~ here
+  for clarity.
+
+#+findex: denote-date-prompt
++ Function ~denote-date-prompt~ :: Prompt for date, expecting
+  =YYYY-MM-DD= or that plus =HH:MM= (or even =HH:MM:SS=). Use Org's
+  more advanced date selection utility if the user option
+  ~denote-date-prompt-use-org-read-date~ is non-nil. It requires Org
+  ([[#h:e7ef08d6-af1b-4ab3-bb00-494a653e6d63][The denote-date-prompt-use-org-read-date option]]). With optional
+  =INITIAL-DATE= use it as the initial minibuffer text. With optional
+  =PROMPT-TEXT= use it in the minibuffer instead of the default
+  prompt. =INITIAL-DATE= is a string that can be processed by
+  ~denote-valid-date-p~, a value that can be parsed by ~decode-time~
+  or nil.
+
+#+findex: denote-command-prompt
++ Function ~denote-command-prompt~ ::  Prompt for command among
+  ~denote-commands-for-new-notes~ ([[#h:17896c8c-d97a-4faa-abf6-31df99746ca6][Points of entry]]).
+
+#+vindex: denote-prompts-with-history-as-completion
++ Variable ~denote-prompts-with-history-as-completion~ :: Prompts that
+  conditionally perform completion against their history. These are
+  minibuffer prompts that ordinarily accept a free form string input,
+  as opposed to matching against a predefined set. These prompts can
+  optionally perform completion against their own minibuffer history
+  when the user option ~denote-history-completion-in-prompts~ is set
+  to a non-nil value ([[#h:403422a7-7578-494b-8f33-813874c12da3][The ~denote-history-completion-in-prompts~ option]]).
+
+#+findex: denote-files-matching-regexp-prompt
++ Function ~denote-files-matching-regexp-prompt~ ::  Prompt for
+  =REGEXP= to filter Denote files by. With optional =PROMPT-TEXT= use
+  it instead of a generic prompt.
+
+#+findex: denote-prompt-for-date-return-id
++ Function ~denote-prompt-for-date-return-id~ :: Use
+  ~denote-date-prompt~ and return it as ~denote-id-format~.
+
+#+findex: denote-template-prompt
++ Function ~denote-template-prompt~ :: Prompt for template key in
+  ~denote-templates~ and return its value.
+
+#+findex: denote-subdirectory-prompt
++ Function ~denote-subdirectory-prompt~ :: Prompt for subdirectory of
+  the variable ~denote-directory~.  The table uses the ~file~
+  completion category (so it works with packages such as ~marginalia~
+  and ~embark~).
+
+** Front matter interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:80ddc044-5c64-4fb3-b4f4-2eaf6bceda3b
+:END:
+
+#+findex: denote-filetype-heuristics
++ Function ~denote-filetype-heuristics~ :: Return likely file type of
+  =FILE=. If in the process of ~org-capture~, consider the file type to
+  be that of Org. Otherwise, use the file extension to detect the file
+  type of =FILE=.
+
+  If more than one file type correspond to this file extension, use
+  the first file type for which the :title-key-regexp in
+  ~denote-file-types~ matches in the file.
+
+  Return nil if the file type is not recognized.
+
+#+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]])
+
+#+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]])
+
+#+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]])
+
+#+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]])
+
+#+findex: denote-date-org-timestamp
++ Function ~denote-date-org-timestamp~ :: Format =DATE= using the Org
+  inactive timestamp notation.
+
+#+findex: denote-date-rfc3339
++ Function ~denote-date-rfc3339~ :: Format =DATE= using the RFC3339
+  specification.
+
+#+findex: denote-date-iso-8601
++ Function ~denote-date-iso-8601~ :: Format =DATE= according to ISO
+  8601 standard.
+
+#+findex: denote-trim-whitespace
++ Function ~denote-trim-whitespace~ :: Trim whitespace around string
+  =S=.  This can be used in ~denote-file-types~ to format front
+  mattter.
+
+#+findex: denote-trim-whitespace-then-quotes
++ Function ~denote-trim-whitespace-then-quotes~ :: Trim whitespace
+  then quotes around string =S=.  This can be used in
+  ~denote-file-types~ to format front mattter.
+
+#+findex: denote-format-string-for-org-front-matter
++ Function ~denote-format-string-for-org-front-matter~ :: Return
+  string =S= as-is for Org or plain text front matter. If =S= is not a
+  string, return an empty string.
+
+#+findex: denote-format-string-for-md-front-matter
++ Function ~denote-format-string-for-md-front-matter~ :: Surround
+  string =S= with quotes. If =S= is not a string, return a literal
+  emptry string. This can be used in ~denote-file-types~ to format
+  front mattter.
+
+#+findex: denote-format-keywords-for-md-front-matter
++ Function ~denote-format-keywords-for-md-front-matter~ :: Format
+  front matter =KEYWORDS= for markdown file type.  =KEYWORDS= is a
+  list of strings.  Consult the ~denote-file-types~ for how this is
+  used.
+
+#+findex: denote-format-keywords-for-text-front-matter
++ Function ~denote-format-keywords-for-text-front-matter~ :: Format
+  front matter =KEYWORDS= for text file type.  =KEYWORDS= is a list of
+  strings.  Consult the ~denote-file-types~ for how this is used.
+
+#+findex: denote-format-keywords-for-org-front-matter
++ Function ~denote-format-keywords-for-org-front-matter~ :: Format
+  front matter =KEYWORDS= for org file type.  =KEYWORDS= is a list of
+  strings.  Consult the ~denote-file-types~ for how this is used.
+
+#+findex: denote-extract-keywords-from-front-matter
++ Function ~denote-extract-keywords-from-front-matter~ :: Format front
+  matter =KEYWORDS= for org file type.  =KEYWORDS= is a list of
+  strings.  Consult the ~denote-file-types~ for how this is used.
+
+#+vindex: denote-file-types
++ Variable ~denote-file-types~ :: Alist of ~denote-file-type~ and
+  their format properties.
+
+  Each element is of the form =(SYMBOL PROPERTY-LIST)=.  =SYMBOL= is
+  one of those specified in ~denote-file-type~ or an arbitrary symbol
+  that defines a new file type.
+
+  =PROPERTY-LIST= is a plist that consists of the following elements:
+
+  1. =:extension= is a string with the file extension including the
+     period.
+
+  2. =:date-function= is a function that can format a date.  See the
+     functions ~denote--date-iso-8601~, ~denote--date-rfc3339~, and
+     ~denote--date-org-timestamp~.
+
+  3. =:front-matter= is either a string passed to ~format~ or a
+     variable holding such a string.  The ~format~ function accepts
+     four arguments, which come from ~denote~ in this order: =TITLE=,
+     =DATE=, =KEYWORDS=, =IDENTIFIER=.  Read the doc string of
+     ~format~ on how to reorder arguments.
+
+  4. =:title-key-regexp= is a regular expression that is used to
+     retrieve the title line in a file.  The first line matching this
+     regexp is considered the title line.
+
+  5. =:title-value-function= is the function used to format the raw
+     title string for inclusion in the front matter (e.g. to surround
+     it with quotes).  Use the ~identity~ function if no further
+     processing is required.
+
+  6. =:title-value-reverse-function= is the function used to retrieve
+     the raw title string from the front matter.  It performs the
+     reverse of =:title-value-function=.
+
+  7. =:keywords-key-regexp= is a regular expression used to retrieve
+     the keywords' line in the file.  The first line matching this
+     regexp is considered the keywords' line.
+
+  8. =:keywords-value-function= is the function used to format the
+     keywords' list of strings as a single string, with appropriate
+     delimiters, for inclusion in the front matter.
+
+  9. =:keywords-value-reverse-function= is the function used to retrieve
+     the keywords' value from the front matter.  It performs the reverse
+     of the =:keywords-value-function=.
+
+  10. =:link= is a string, or variable holding a string, that
+      specifies the format of a link.  See the variables
+      ~denote-org-link-format~, ~denote-md-link-format~.
+
+  11. =:link-in-context-regexp= is a regular expression that is used
+      to match the aforementioned link format.  See the variables
+      ~denote-org-link-in-context-regexp~, ~denote-md-link-in-context-regexp~.
+
+  If ~denote-file-type~ is nil, use the first element of this list for
+  new note creation.  The default is ~org~.
+
+** Link interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:97b8eb9e-07e1-4992-8b59-2a0e3b65574b
+:END:
+
+#+vindex: denote-org-link-format
++ Variable ~denote-org-link-format~ :: Format of Org link to note.
+  The value is passed to ~format~ with =IDENTIFIER= and =TITLE=
+  arguments, in this order.  Also see ~denote-org-link-in-context-regexp~.
+
+#+vindex: denote-md-link-format
++ Variable ~denote-md-link-format~ :: Format of Markdown link to note.
+  The =%N$s= notation used in the default value is for ~format~ as the
+  supplied arguments are =IDENTIFIER= and =TITLE=, in this order.
+  Also see ~denote-md-link-in-context-regexp~.
+
+#+vindex: denote-id-only-link-format
++ Variable ~denote-id-only-link-format~ :: Format of identifier-only
+  link to note.  The value is passed to ~format~ with =IDENTIFIER= as
+  its sole argument.    Also see ~denote-id-only-link-in-context-regexp~.
+
+#+vindex: denote-org-link-in-context-regexp
++ Variable ~denote-org-link-in-context-regexp~ :: Regexp to match an
+  Org link in its context.  The format of such links is ~denote-org-link-format~.
+
+#+vindex: denote-md-link-in-context-regexp
++ Variable ~denote-md-link-in-context-regexp~ :: Regexp to match an
+  Markdown link in its context.  The format of such links is ~denote-md-link-format~.
+
+#+vindex: denote-id-only-link-in-context-regexp
++ Variable ~denote-id-only-link-in-context-regexp~ :: Regexp to match
+  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
+  file among =FILES=.
+
+#+findex: denote-link-return-links
++ Function ~denote-link-return-links~ :: Return list of links in
+  current or optional =FILE=.  Also see ~denote-link-return-backlinks~.
+
+#+findex: denote-link-return-backlinks
++ Function ~denote-link-return-backlinks~ :: Return list of backlinks
+  in current or optional =FILE=.  Also see ~denote-link-return-links~.
+
+#+findex: denote-link-description-with-signature-and-title
++ Function ~denote-link-description-with-signature-and-title~ :: Return
+  link description for =FILE=.  Produce a description as follows:
+
+  - If the region is active, use it as the description.
+
+  - If =FILE= as a signature, then use the
+    ~denote-link-signature-format~.  By default, this looks like
+    "signature title".
+
+  - If =FILE= does not have a signature, then use its title as the
+    description.
+
+#+vindex: denote-link-description-function
++ Variable ~denote-link-description-function~ :: Function to use to
+  create the description of links. The function specified should take
+  a =FILE= argument and should return the description as a string. By
+  default, the title of the file is returned as the description.
+
+** Xref interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:e824c215-1c31-4b26-b994-7df67341d075
+:END:
+
+- Function ~denote-retrieve-groups-xref-query~ :: Access location of
+  xrefs for =QUERY= and group them per file. Limit the search to text
+  files.
+
+- Function ~denote-retrieve-files-xref-query~ :: Return sorted,
+  deduplicated file names with matches for =QUERY= in their contents.
+  Limit the search to text files.
+
+- Function ~denote-retrieve-xref-alist~ :: Return xref alist of files
+  with location of matches for =QUERY=. With optional
+  =FILES-MATCHING-REGEXP=, limit the list of files accordingly (per
+  ~denote-directory-files~). At all times limit the search to text
+  files.
+
+** Renaming files interface for developers or advanced users
+:PROPERTIES:
+:CUSTOM_ID: h:66d31f42-6092-493a-97db-83b217db9d96
+:END:
+
+#+findex: denote-rename-file-prompt
+- Function ~denote-rename-file-prompt~ :: Prompt to rename file named
+  =OLD-NAME= to =NEW-NAME=. If ~denote-rename-confirmations~ does not
+  contain ~modify-file-name~, return t without prompting.
+
+#+findex: denote-rename-file-and-buffer
++ Function ~denote-rename-file-and-buffer~ :: Rename file named
+  =OLD-NAME= to =NEW-NAME=, updating buffer name.
+
+#+findex: denote-prepend-front-matter
++ Function ~denote-prepend-front-matter~ :: Prepend front matter to
+  =FILE=. The =TITLE=, =KEYWORDS=, =DATE=, =ID=, =SIGNATURE=, and
+  =FILE-TYPE= are passed from the renaming command and are used to
+  construct a new front matter block if appropriate.
+
+#+findex: denote-rewrite-front-matter
++ Function ~denote-rewrite-front-matter~ :: Rewrite front matter of
+  note after ~denote-rename-file~ (or related). The =FILE=, =TITLE=,
+  =KEYWORDS=, =SIGNATURE=, =DATE=, =IDENTIFIER=, and =FILE-TYPE=
+  arguments are given by the renaming command and are used to construct
+  new front matter values if appropriate. If ~denote-rename-confirmations~
+  contains ~rewrite-front-matter~, prompt to confirm the rewriting of
+  the front matter. Otherwise produce a ~y-or-n-p~ prompt to that
+  effect.
+
+#+findex: denote-add-front-matter-prompt
++ Function ~denote-add-front-matter-prompt~ :: Prompt to add a
+  front-matter to =FILE=. Return non-nil if a new front matter should
+  be added. If ~denote-rename-confirmations~ does not contain
+  ~add-front-matter~, return t without prompting.
+
+#+findex: denote-rewrite-keywords
++ Function ~denote-rewrite-keywords~ :: Rewrite =KEYWORDS= in =FILE=
+  outright according to =FILE-TYPE=. Do the same as
+  ~denote-rewrite-front-matter~ for keywords, but do not ask for
+  confirmation. With optional =SAVE-BUFFER=, save the buffer
+  corresponding to =FILE=. This function is for use in the commands
+  ~denote-keywords-add~, ~denote-keywords-remove~,
+  ~denote-dired-rename-files~, or related.
+
+#+findex: denote-update-dired-buffers
++ Function ~denote-update-dired-buffers~ :: Update Dired buffers of
+  variable ~denote-directory~. Also revert the current Dired buffer
+  even if it is not inside the ~denote-directory~. Note that the
+  ~denote-directory~ accepts a directory-local value for what we
+  internally refer to as "silos" ([[#h:15719799-a5ff-4e9a-9f10-4ca03ef8f6c5][Maintain separate directories for notes]]).
+
+* Troubleshoot Denote in a pristine environment
+:PROPERTIES:
+:CUSTOM_ID: h:9c4467d5-6480-4681-80fb-cd9717bf8b3b
+:END:
+
+Sometimes we get reports on bugs that may not be actually caused by
+some error in the Denote code base.  To help gain insight into what
+the problem is, we need to be able to reproduce the issue in a minimum
+viable system.  Below is one way to achieve this.
+
+1. Find where your =denote.el= file is stored on your filesystem.
+
+2. Assuming you have already installed the package, one way to do this
+   is to invoke =M-x find-library= and search for ~denote~.  It will
+   take you to the source file.  There do =M-x eval-expression=, which
+   will bring up a minibuffer prompt.  At the prompt evaluate:
+
+#+begin_example emacs-lisp
+(kill-new (expand-file-name (buffer-file-name)))
+#+end_example
+
+3. The above will save the full file system path to your kill ring.
+
+4. In a terminal emulator or an =M-x shell= buffer execute:
+
+#+begin_example
+emacs -Q
+#+end_example
+
+5. This will open a new instance of Emacs in a pristine environment.
+   Only the default settings are loaded.
+
+6. In the =*scratch*= buffer of =emacs -Q=, add your configurations
+   like the following and try to reproduce the issue:
+
+#+begin_example emacs-lisp
+(require 'denote "/full/path/to/what/you/got/denote.el")
+
+;; Your configurations here
+#+end_example
+
+Then try to see if your problem still occurs.  If it does, then the
+fault is with Denote.  Otherwise there is something external to it
+that we need to account for.  Whatever the case, this exercise helps
+us get a better sense of the specifics.
+
+* Contributing
+:PROPERTIES:
+:CUSTOM_ID: h:1ebe4865-c001-4747-a6f2-0fe45aad71cd
+:END:
+
+Denote is a GNU ELPA package. As such, any significant change to the
+code requires copyright assignment to the Free Software Foundation
+(more below).
+
+You do not need to be a programmer to contribute to this package.
+Sharing an idea or describing a workflow is equally helpful, as it
+teaches us something we may not know and might be able to cover either
+by extending Denote or expanding this manual. If you prefer to write a
+blog post, make sure you share it with us: we can add a section herein
+referencing all such articles. Everyone gets acknowledged
+([[#h:f8126820-3b59-49fa-bcc2-73bd60132bb9][Acknowledgements]]). There is no such thing as an "insignificant
+contribution"---they all matter.
+
++ Package name (GNU ELPA): ~denote~
++ Official manual: <https://protesilaos.com/emacs/denote>
++ Change log: <https://protesilaos.com/emacs/denote-changelog>
++ Git repositories:
+  + GitHub: <https://github.com/protesilaos/denote>
+  + GitLab: <https://gitlab.com/protesilaos/denote>
+
+If our public media are not suitable, you are welcome to contact me
+(Protesilaos) in private: <https://protesilaos.com/contact>.
+
+Copyright assignment is a prerequisite to sharing code. It is a simple
+process. Check the request form below (please adapt it accordingly).
+You must write an email to the address mentioned in the form and then
+wait for the FSF to send you a legal agreement. Sign the document and
+file it back to them. This could all happen via email and take about a
+week. You are encouraged to go through this process. You only need to
+do it once. It will allow you to make contributions to Emacs in
+general.
+
+#+begin_example text
+Please email the following information to assign@gnu.org, and we
+will send you the assignment form for your past and future changes.
+
+Please use your full legal name (in ASCII characters) as the subject
+line of the message.
+
+REQUEST: SEND FORM FOR PAST AND FUTURE CHANGES
+
+[What is the name of the program or package you're contributing to?]
+
+GNU Emacs
+
+[Did you copy any files or text written by someone else in these changes?
+Even if that material is free software, we need to know about it.]
+
+Copied a few snippets from the same files I edited.  Their author,
+Protesilaos Stavrou, has already assigned copyright to the Free Software
+Foundation.
+
+[Do you have an employer who might have a basis to claim to own
+your changes?  Do you attend a school which might make such a claim?]
+
+
+[For the copyright registration, what country are you a citizen of?]
+
+
+[What year were you born?]
+
+
+[Please write your email address here.]
+
+
+[Please write your postal address here.]
+
+
+
+
+
+[Which files have you changed so far, and which new files have you written
+so far?]
+
+#+end_example
+
+** Wishlist of what we can do to extend Denote
+:PROPERTIES:
+:CUSTOM_ID: h:044a6a0f-e382-4013-8279-8bf4e64e73c0
+:END:
+
+These are various ideas to extend Denote. Whether they should be in
+the core package or a separate extension is something we can discuss.
+I, Protesilaos, am happy to help anyone who wants to do any of this.
+
+- denote-embark.el :: Provide integration with the ~embark~ package.
+  This can be for doing something with the identifier/link at point.
+  For example, it could provide an action to produce backlinks for the
+  identifier/file we are linking to, not just the current one.
+
+- denote-transient.el :: The ~transient~ package is built into Emacs
+  29 (Denote supports Emacs 28 though). We can use it to define an
+  alternative to what we have for the menu bar. Perhaps this interface
+  can used to toggle various options, such as to call ~denote~ with a
+  different set of prompts.
+
+- A ~denote-directories~ user option :: This can be either an
+  extension of the ~denote-directory~ (accept a list of file paths
+  value) or a new variable. The idea is to let the user define
+  separate Denote directories which do know about the presence of each
+  other (unlike silos). This way, a user can have an entry in
+  =~/Documents/notes/= link to something =~/Git/projects/= and
+  everything work as if the ~denote-directory~ is set to the =~/=
+  (with the status quo as of 2024-02-18 08:27 +0200).
+
+- Encode the day in the identifier :: The idea is to use some coded
+  reference for Monday, Tuesday, etc. instead of having the generic
+  =T= in the identifier. For example, Monday is =A= so the identifier
+  for it is something like =20240219A101522= instead of what we now
+  have as =20240219T101522=. The old method should still be supported.
+  Apart from changing a few regular expressions, this does not seem
+  too complex to me. We would need a user option to opt in to such a
+  feature. Then tweak the relevant parts. The tricky issue is to
+  define a mapping of day names to letters/symbols that works for
+  everyone. Do all countries have a seven-day week, for example? We
+  need something universally applicable here.
+
+Anything else? You are welcome to discuss these and/or add to the
+list.
+
+* Publications about Denote
+:PROPERTIES:
+:CUSTOM_ID: h:ca0c38f9-fa3e-4901-947e-1b589335781d
+:END:
+
+The Emacs community is putting Denote to great use.  This section
+includes publications that show how people configure their note-taking
+setup.  If you have a blog post, video, or configuration file about
+Denote, feel welcome to tell us about it ([[#h:1ebe4865-c001-4747-a6f2-0fe45aad71cd][Contributing]]).
+
++ David Wilson (SystemCrafters): /Generating a Blog Site from Denote
+  Entries/, 2022-09-09, <https://www.youtube.com/watch?v=5R7ad5xz5wo>
+
++ David Wilson (SystemCrafters): /Trying Out Prot's Denote, an Org
+  Roam Alternative?/, 2022-07-15, <https://www.youtube.com/watch?v=QcRY_rsX0yY>
+
++ Jack Baty: /Keeping my Org Agenda updated based on Denote keywords/,
+  2022-11-30, <https://baty.net/2022/keeping-my-org-agenda-updated>
+
++ Jeremy Friesen: /Denote Emacs Configuration/, 2022-10-02,
+  <https://takeonrules.com/2022/10/09/denote-emacs-configuration/>
+
++ Jeremy Friesen: /Exploring the Denote Emacs Package/, 2022-10-01,
+  <https://takeonrules.com/2022/10/01/exploring-the-denote-emacs-package/>
+
++ Jeremy Friesen: /Migration Plan for Org-Roam Notes to Denote/,
+  2022-10-02, <https://takeonrules.com/2022/10/02/migration-plan-for-org-roam-notes-to-denote/>
+
++ Jeremy Friesen: /Project Dispatch Menu with Org Mode Metadata,
+  Denote, and Transient/, 2022-11-19,
+  <https://takeonrules.com/2022/11/19/project-dispatch-menu-with-org-mode-metadata-denote-and-transient/>
+
++ Mohamed Suliman: /Managing a bibliography of BiBTeX entries with
+  Denote/, 2022-12-20, <https://www.scss.tcd.ie/~sulimanm/posts/denote-bibliography.html>
+
++ Peter Prevos: /Simulating Text Files with R to Test the Emacs Denote
+  Package/, 2022-07-28, <https://lucidmanager.org/productivity/testing-denote-package/>
+
++ Peter Prevos: /Emacs Writing Studio/, 2023-10-19. A configuration for authors, using Denote for taking notes, literature reviews and manage collections of images:
+  - <https://lucidmanager.org/productivity/taking-notes-with-emacs-denote/>
+  - <https://lucidmanager.org/productivity/denote-explore/>
+  - <https://lucidmanager.org/productivity/bibliographic-notes-in-emacs-with-citar-denote/>
+  - <https://lucidmanager.org/productivity/using-emacs-image-dired/>
+
++ Stefan Thesing: /Denote as a Zettelkasten/, 2023-03-02,
+  <https://www.thesing-online.de/blog/denote-as-a-zettelkasten>
+
++ Summer Emacs: /An explanation of how I use Emacs/, 2023-05-04,
+  <https://github.com/summeremacs/howiuseemacs/blob/main/full-explanation-of-how-i-use-emacs.org>
+
+* Alternatives to Denote
+:PROPERTIES:
+:CUSTOM_ID: h:dbb51a1b-90b8-48e8-953c-e2fb3e36981e
+:END:
+
+What follows is a list of Emacs packages for note-taking.  I
+(Protesilaos) have not used any of them, as I was manually applying my
+file-naming scheme beforehand and by the time those packages were
+available I was already hacking on the predecessor of Denote as a means
+of learning Emacs Lisp (a package which I called "Unassuming Sidenotes
+of Little Significance", aka "USLS" which is pronounced as "U-S-L-S" or
+"useless").  As such, I cannot comment at length on the differences
+between Denote and each of those packages, beside what I gather from
+their documentation.
+
++ [[https://github.com/org-roam/org-roam][org-roam]] :: The de facto standard in the Emacs milieu---and rightly
+  so!  It has a massive community, is featureful, and should be an
+  excellent companion to anyone who is invested in the Org ecosystem
+  and/or knows what "Roam" is (I don't).  It has been explained to me
+  that Org Roam uses a database to store a cache about your notes.  It
+  otherwise uses standard Org files.  The cache helps refer to the same
+  node through aliases which can provide lots of options.  Personally, I
+  follow a single-topic-per-note approach, so anything beyond that is
+  overkill.  If the database is only for a cache, then maybe that has no
+  downside, though I am careful with any kind of specialised program as
+  it creates a dependency.  If you ask me about database software in
+  particular, I have no idea how to use one, let alone debug it or
+  retrieve data from it if something goes awry (I could learn, but that
+  is beside the point).
+
++ [[https://github.com/localauthor/zk][zk (or zk.el)]] :: Reading its documentation makes me think that this is
+  Denote's sibling---the two projects have a lot of things in common,
+  including the preference to rely on plain files and standard tools.
+  The core difference is that Denote has a strict file-naming scheme.
+  Other differences in available features are, in principle, matters of
+  style or circumstance: both packages can have them.  As its initials
+  imply, ZK enables a zettelkasten-like workflow.  It does not enforce
+  it though, letting the user adapt the method to their needs and
+  requirements.
+
++ [[https://github.com/ymherklotz/emacs-zettelkasten][zettelkasten]] :: This is another one of Denote's relatives, at least
+  insofar as the goal of simplicity is concerned.  The major difference
+  is that according to its documentation "the name of the file that is
+  created is just a unique ID".  This is not consistent with our
+  file-naming scheme which is all about making sense of your files by
+  their name alone and being able to visually parse a listing of them
+  without any kind of specialised tool (e.g. =ls -l= or =ls -C= on the
+  command-line from inside the ~denote-directory~ give you a
+  human-readable set of files names, while =find * -maxdepth 0 -type f=
+  is another approach).
+
++ [[https://github.com/EFLS/zetteldeft][zetteldeft]] :: This is a zettelkasten note-taking system built on top
+  of the =deft= package.  Deft provides a search interface to a
+  directory, in this case the one holding the user's =zetteldeft= notes.
+  Denote has no such dependency and is not opinionated about how the
+  user prefers to search/access their notes: use Dired, Grep, the
+  =consult= package, or whatever else you already have set up for all
+  things Emacs, not just your notes.
+
+Searching through =M-x list-packages= for "zettel" brings up more
+matches.  =zetteldesk= is an extension to Org Roam and, as such, I
+cannot possibly know what Org Roam truly misses and what the added-value
+of this package is.  =neuron-mode= builds on top of an external program
+called =neuron=, which I have never used.
+
+Searching for "note" gives us a few more results.  =notes-mode= has
+precious little documentation and I cannot tell what it actually does
+(as I said in my presentation for LibrePlanet 2022, inadequate docs are
+a bug).  =side-notes= differs from what we try to do with Denote, as it
+basically gives you the means to record your thoughts about some other
+project you are working on and keep them on the side: so it and Denote
+should not be mutually exclusive.
+
+If I missed something, please let me know.
+
+** Alternative implementations and further reading
+:PROPERTIES:
+:CUSTOM_ID: h:188c0986-f2fa-444f-b493-5429356e75cf
+:END:
+
+This section covers blog posts and implementations from the Emacs
+community about the topic of note-taking and file organization.  They
+may refer to some of the packages covered in the previous section or
+provide their custom code ([[#h:dbb51a1b-90b8-48e8-953c-e2fb3e36981e][Alternatives to Denote]]).  The list is
+unsorted.
+
++ José Antonio Ortega Ruiz (aka "jao") explains a note-taking method
+  that is simple like Denote but differs in other ways.  An interesting
+  approach overall: https://jao.io/blog/simple-note-taking.html.
+
++ Jethro Kuan (the main =org-roam= developer) explains their note-taking
+  techniques: https://jethrokuan.github.io/org-roam-guide/.  Good ideas
+  all round, regardless of the package/code you choose to use.
+
++ Karl Voit's tools [[https://github.com/novoid/date2name][date2name]], [[https://github.com/novoid/filetags/][filetags]], [[https://github.com/novoid/appendfilename/][appendfilename]], and
+  [[https://github.com/novoid/move2archive][move2archive]] provide a Python-based implementation to organize
+  individual files which do not require Emacs.  His approach ([[https://karl-voit.at/managing-digital-photographs/][blog
+  post]] and his [[https://www.youtube.com/watch?v=rckSVmYCH90][presentation at GLT18]]) has been complemented by [[https://github.com/novoid/memacs][memacs]]
+  to process e.g., the date of creation of photographs, or the log of
+  a phone call in a format compatible to org.
+
+[ Development note: help expand this list. ]
+
+* Frequently Asked Questions
+:PROPERTIES:
+:CUSTOM_ID: h:da2944c6-cde6-4c65-8f2d-579305a159bb
+:END:
+
+I (Protesilaos) answer some questions I have received or might get.  It
+is assumed that you have read the rest of this manual: I will not go
+into the specifics of how Denote works.
+
+** Why develop Denote when PACKAGE already exists?
+:PROPERTIES:
+:CUSTOM_ID: h:b875450a-ae22-4899-ac23-c10fa9c279bb
+:END:
+
+I wrote Denote because I was using a variant of Denote's file-naming
+scheme before I was even an Emacs user (I switched to Emacs from
+Tmux+Vim+CLI in the summer of 2019).  I was originally inspired by
+Jekyll, the static site generator, which I started using for my website
+in 2016 (was on WordPress before).  Jekyll's files follow the
+=YYYY-MM-DD-TITLE.md= pattern.  I liked its efficiency relative to the
+unstructured mess I had before.  Eventually, I started using that scheme
+outside the confines of my website's source code.  Over time I refined
+it and here we are.
+
+Note-taking is something I take very seriously, as I am a prolific
+writer (just check my website, which only reveals the tip of the
+iceberg).  As such, I need a program that does exactly what I want and
+which I know how to extend.  I originally tried to use Org capture
+templates to create new files with a Denote-style file-naming scheme but
+never managed to achieve it.  Maybe because ~org-capture~ has some
+hard-coded assumptions or I simply am not competent enough to hack on
+core Org facilities.  Whatever the case, an alternative was in order.
+
+The existence of PACKAGE is never a good reason for me not to conduct my
+own experiments for recreational, educational, or practical purposes.
+When the question arises of "why not contribute to PACKAGE instead?" the
+answer is that without me experimenting in the first place, I would lack
+the skills for such a task.  Furthermore, contributing to another
+package does not guarantee I get what I want in terms of workflow.
+
+Whether you should use Denote or not is another matter altogether:
+choose whatever you want.
+
+** Why not rely exclusively on Org?
+:PROPERTIES:
+:CUSTOM_ID: h:b9831849-5c71-484e-b444-bac19cc13151
+:END:
+
+I think Org is one of Emacs' killer apps.  I also believe it is not the
+right tool for every job.  When I write notes, I want to focus on
+writing.  Nothing more.  I thus have no need for stuff like org-babel,
+scheduling to-do items, clocking time, and so on.  The more "mental
+dependencies" you add to your workflow, the heavier the burden you carry
+and the less focused you are on the task at hand: there is always that
+temptation to tweak the markup, tinker with some syntactic construct,
+obsess about what ought to be irrelevant to writing as such.
+
+In technical terms, I also am not fond of Org's code base (I understand
+why it is the way it is---just commenting on the fact).  Ever tried to
+read it?  You will routinely find functions that are tens-to-hundreds of
+lines long and have all sorts of special casing.  As I am not a
+programmer and only learnt to write Elisp through trial and error, I
+have no confidence in my ability to make Org do what I want at that
+level, hence =denote= instead of =org-denote= or something.
+
+Perhaps the master programmer is one who can deal with complexity and
+keep adding to it.  I am of the opposite view, as language---code
+included---is at its communicative best when it is clear and accessible.
+
+Make no mistake: I use Org for the agenda and also to write technical
+documentation that needs to be exported to various formats, including
+this very manual.
+
+** Why care about Unix tools when you use Emacs?
+:PROPERTIES:
+:CUSTOM_ID: h:da1e2469-8f04-450b-a379-a854efa80a36
+:END:
+
+My notes form part of my longer-term storage.  I do not want to have to
+rely on a special program to be able to read them or filter them.  Unix
+is universal, at least as far as I am concerned.
+
+Denote streamlines some tasks and makes things easier in general, which
+is consistent with how Emacs provides a layer of interactivity on top of
+Unix.  Still, Denote's utilities can, in principle, be implemented as
+POSIX shell scripts (minus the Emacs-specific parts like fontification
+in Dired or the buttonization of links).
+
+Portability matters.  For example, in the future I might own a
+smartphone, so I prefer not to require Emacs, Org, or some other
+executable to access my files on the go.
+
+Furthermore, I might want to share those files with someone.  If I make
+Emacs a requirement, I am limiting my circle to a handful of relatively
+advanced users.
+
+Please don't misinterpret this: I am using Emacs full-time for my
+computing and maintain a growing list of packages for it.  This is just
+me thinking long-term.
+
+** Why many small files instead of few large ones?
+:PROPERTIES:
+:CUSTOM_ID: h:7d2e7b8a-d484-4c1d-8688-17f70f242ad7
+:END:
+
+I have read that Org favours the latter method.  If true, I strongly
+disagree with it because of the implicit dependency it introduces and
+the way it favours machine-friendliness over human-readability in terms
+of accessing information.  Notes are long-term storage.  I might want to
+access them on (i) some device with limited features, (ii) print on
+paper, (iii) share with another person who is not a tech wizard.
+
+There are good arguments for few large files, but all either prioritize
+machine-friendliness or presuppose the use of sophisticated tools like
+Emacs+Org.
+
+Good luck using =less= on a generic TTY to read a file with a zillion
+words, headings, sub-headings, sub-sub-headings, property drawers, and
+other constructs!  You will not get the otherwise wonderful folding of
+headings the way you do in Emacs---do not take such features for
+granted.
+
+My point is that notes should be atomic to help the user---and
+potentially the user's family, friends, acquaintances---make sense of
+them in a wide range of scenaria.  The more program-agnostic your file
+is, the better for you and/or everyone else you might share your
+writings with.
+
+Human-readability means that we optimize for what matters to us.  If (a)
+you are the only one who will ever read your notes, (b) always have
+access to good software like Emacs+Org, (c) do not care about printing
+on paper, then Denote's model is not for you.  Maybe you need to tweak
+some ~org-capture~ template to append a new entry to one mega file (I do
+that for my Org agenda, by the way, as I explained before about using
+the right tool for the job).
+
+** Does Denote perform well at scale?
+:PROPERTIES:
+:CUSTOM_ID: h:863f812a-aac7-42ea-83b3-fbbdb58e08d7
+:END:
+
+Denote does not do anything fancy and has no special requirements: it
+uses standard tools to accomplish ordinary tasks.  If Emacs can cope
+with lots of files, then that is all you need to know: Denote will work.
+
+To put this to the test, Peter Prevos is running simulations with R that
+generate large volumes of notes.  You can read the technicalities here:
+<https://lucidmanager.org/productivity/testing-denote-package/>.
+Excerpt:
+
+#+begin_quote
+Using this code I generated ten thousands notes and used this to test
+the Denote package to see it if works at a large scale. This tests shows
+that Prot's approach is perfectly capable of working with thousands of
+notes.
+#+end_quote
+
+Of course, we are always prepared to make refinements to the code, where
+necessary, without compromising on the project's principles.
+
+** I add TODOs to my notes; will many files slow down the Org agenda?
+:PROPERTIES:
+:CUSTOM_ID: h:63c2f8d4-79ed-4c55-b3ef-e048a05802c0
+:END:
+
+Yes, many files will slow down the agenda due to how that works.  Org
+collects all files specified in the ~org-agenda-files~, searches through
+their contents for timestamped entries, and then loops through all days
+to determine where each entry belongs.  The more days and more files,
+the longer it takes to build the agenda.  Doing this with potentially
+hundreds of files will have a noticeable impact on performance.
+
+This is not a deficiency of Denote.  It happens with generic Org files.
+The way the agenda is built is heavily favoring the use of a single file
+that holds all your timestamped entries (or at least a few such files).
+Tens or hundreds of files are inefficient for this job.  Plus doing so
+has the side-effect of making Emacs open all those files, which you
+probably do not need.
+
+If you want my opinion though, be more forceful with the separation of
+concerns.  Decouple your knowledge base from your ephemeral to-do list:
+Denote (and others) can be used for the former, while you let standard
+Org work splendidly for the latter---that is what I do, anyway.
+
+Org has a powerful linking facility, whether you use ~org-store-link~ or
+do it via an ~org-capture~ template.  If you want a certain note to be
+associated with a task, just store the task in a single =tasks.org= (or
+however you name it) and link to the relevant context.
+
+Do not mix your knowledge base with your to-do items.  If you need help
+figuring out the specifics of this workflow, you are welcome to ask for
+help in our relevant channels ([[#h:1ebe4865-c001-4747-a6f2-0fe45aad71cd][Contributing]]).
+
+** I want to sort by last modified in Dired, why won't Denote let me?
+:PROPERTIES:
+:CUSTOM_ID: h:a7fd5e0a-78f7-434e-aa2e-e150479c16e2
+:END:
+
+Denote does not control how Dired sorts files. I encourage you to read
+the manpage of the =ls= executable. It will help you in general, while
+it applies to Emacs as well via Dired. The gist is that you can update
+the =ls= flags that Dired uses on-the-fly: type =C-u M-x
+dired-sort-toggle-or-edit= (=C-u s= by default) and append
+=--sort=time= at the prompt. To reverse the order, add the =-r= flag.
+The user option ~dired-listing-switches~ sets your default preference.
+
+For an on-demand sorted and filtered Dired listing of Denote files,
+use the command ~denote-sort-dired~ ([[#h:9fe01e63-f34f-4479-8713-f162a5ca865e][Sort files by component]]).
+
+** How do you handle the last modified case?
+:PROPERTIES:
+:CUSTOM_ID: h:764b5e87-cd22-4937-b5fc-af3892d6b3d8
+:END:
+
+Denote does not insert any meta data or heading pertaining to edits in
+the file.  I am of the view that these either do not scale well or are
+not descriptive enough.  Suppose you use a "lastmod" heading with a
+timestamp: which lines where edited and what did the change amount to?
+
+This is where an external program can be helpful.  Use a Version Control
+System, such as Git, to keep track of all your notes.  Every time you
+add a new file, record the addition.  Same for post-creation edits.
+Your VCS will let you review the history of those changes.  For
+instance, Emacs' built-in version control framework has a command that
+produces a log of changes for the current file: =M-x vc-print-log=,
+bound to =C-x v l= by default.  From there one can access the
+corresponding diff output (use =M-x describe-mode= (=C-h m=) in an
+unfamiliar buffer to learn more about it).  With Git in particular,
+Emacs users have the option of the all-round excellent =magit= package.
+
+In short: let Denote (or equivalent) create notes and link between them,
+the file manager organise and provide access to files, search programs
+deal with searching and narrowing, and version control software handle
+the tracking of changes.
+
+** Why are some Org links opening outside Emacs?
+:PROPERTIES:
+:CUSTOM_ID: h:4f354db1-aa78-47fd-ac60-c3d1e0f0b0a4
+:END:
+
+Org has its own mechanism to determine how best to open a link. This
+affects the =file:= link type, but also the =denote:= one (which is
+designed to be as close to =file:= as possible).
+
+When following a link, Org usually displays the data in an Emacs
+buffer, though it might launch an external application instead. The
+idea is to use a specialised program when that is relevant, such as to
+display a video. Though there can be scenaria the user does not like,
+such as when Org decides to load =.md= or =.html= files with an
+external app. To compound the problem, users can name any file type
+using the Denote file-naming scheme, including images, PDFs, videos,
+and more ([[#h:532e8e2a-9b7d-41c0-8f4b-3c5cbb7d4dca][Renaming files]]).
+
+To instruct Org to stay in Emacs for such cases, the user needs to
+modify the variable ~org-file-apps~, which is not specific to Denote.
+As one use-case, ~org-file-apps~ associates a regular expression to
+match file names with a method on how to display them (do =M-x
+describe-variable= and then search for ~org-file-apps~ to read its
+documentation). Thus, the user can use something like the following
+in their Org or Denote configuration:
+
+#+begin_src emacs-lisp
+;; Tell Org to use Emacs when opening files that end in .md
+(add-to-list 'org-file-apps '("\\.md\\'" . emacs))
+
+;; Do the same for .html
+(add-to-list 'org-file-apps '("\\.html\\'" . emacs))
+#+end_src
+
+Each of these adds a new entry to the existing value of that user
+option. Replace =md= or =html= with the desired file type extension.
+
+** Speed up backlinks' or query links' buffer creation?
+:PROPERTIES:
+:CUSTOM_ID: h:893eec49-d7be-4603-bcff-fcc247244011
+:END:
+
+Denote leverages the built-in =xref= library to search for the
+identifier of the current file and return any links to it.  For users
+of Emacs version 28 or higher, there exists a user option to specify
+the program that performs this search: ~xref-search-program~.  The
+default is =grep=, which can be slow, though one may opt for =ugrep=,
+=ripgrep=, or even specify something else (read the doc string of that
+user option for the details).
+
+Try either for these for better results:
+
+#+begin_src emacs-lisp
+(setq xref-search-program 'ripgrep)
+
+;; OR
+
+(setq xref-search-program 'ugrep)
+#+end_src
+
+To use whatever executable is available on your system, use something
+like this:
+
+#+begin_src emacs-lisp
+;; Prefer ripgrep, then ugrep, and fall back to regular grep.
+(setq xref-search-program
+      (cond
+       ((or (executable-find "ripgrep")
+            (executable-find "rg"))
+        'ripgrep)
+       ((executable-find "ugrep")
+        'ugrep)
+       (t
+        'grep)))
+#+end_src
+
+** Why do I get "Search failed with status 1" when I search for backlinks?
+:PROPERTIES:
+:CUSTOM_ID: h:42f6b07e-5956-469a-8294-17f9cf62eb2b
+:END:
+
+Denote uses [[info:emacs#Xref][Emacs' Xref]] to find backlinks.  Xref requires ~xargs~ and
+one of ~grep~ or ~ripgrep~, depending on your configuration.
+
+This is usually not an issue on *nix systems, but the necessary
+executables are not available on Windows Emacs distributions.  Please
+ensure that you have both ~xargs~ and either ~grep~ or ~ripgrep~
+available within your ~PATH~ environment variable.
+
+If you have ~git~ on Windows installed, then you may use the following
+code (adjust the git's installation path if necessary):
+#+begin_src emacs-lisp
+  (setenv "PATH" (concat (getenv "PATH") ";" "C:\\Program Files\\Git\\usr\\bin"))
+#+end_src
+
+** Why do I get a double =#+title= in Doom Emacs?
+:PROPERTIES:
+:CUSTOM_ID: h:0f737b7d-40e6-46a7-b1db-117c0ffcbfef
+:END:
+
+Doom Emacs provides a set of bespoke templates for Org. One of those
+prefills any new Org file with a =#+title= field. So when Denote
+creates a new Org file and inserts front matter to it, it inevitably
+adds an extra title to the existing one.
+
+This is not a Denote problem. We can only expect a new file to be
+empty by default. Check how to disable the relevant module in your
+Doom Emacs configuration file.
+
+* Acknowledgements
+:PROPERTIES:
+:CUSTOM_ID: h:f8126820-3b59-49fa-bcc2-73bd60132bb9
+:END:
+#+cindex: Contributors
+
+Denote is meant to be a collective effort.  Every bit of help matters.
+
++ Author/maintainer :: Protesilaos Stavrou.
+
++ Contributions to code or the manual :: Abdul-Lateef Haji-Ali, Abin
+  Simon, Adam Růžička, Alan Schmitt, Alexandre Rousseau, Ashton
+  Wiersdorf, Aziz, Benjamin Kästner, Bruno Boal, Charanjit Singh,
+  Claudio Migliorelli, Clemens Radermacher, Colin McLear, Damien
+  Cassou, Eduardo Grajeda, Elias Storms, Eshel Yaron, Florian, Glenna
+  D., Graham Marlow, Hilde Rhyne, Ivan Sokolov, Jack Baty, Jakub
+  Szczerbowski, 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 Lemon, Noboru Ota (nobiot), Norwid Behrnd, Octavian, Peter
+  Prevos, Philip Kaludercic, Quiliro Ordóñez, Stephen R. Kifer, Stefan
+  Monnier, Stefan Thesing, Thibaut Benjamin, Tomasz Hołubowicz,
+  TomoeMami , Vedang Manerikar, Wesley Harvey, Zhenxu Xu, arsaber101,
+  bryanrinders, eum3l, ezchi, jarofromel, leinfink (Henrik), l-o-l-h
+  (Lincoln), mattyonweb, maxbrieiev, mentalisttraceur, 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, 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,
+  Kolmas, Lukas C. Bossert, M. Hadi Timachi, Maikol Solis, Mark Olson,
+  Mirko Hernandez, Niall Dooley, Nick Bell, Oliver Epper, Paul van
+  Gelder, Peter Prevos, Peter Smith, Riccardo Giannitrapani, 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,
+  atanasj, azegas, babusri, bdillahu, coherentstate, doolio, duli,
+  drcxd, elge70, elliottw, fingerknight, hpgisler, hyperfocus1337,
+  jtpavlock, juh, leafarbelm, mentalisttraceur, pRot0ta1p, rbenit68,
+  relict007, sarcom-sar, sienic, skissue, sundar bp,
+  yetanotherfossman, zadca123
+
+Special thanks to Peter Povinec who helped refine the file-naming
+scheme, which is the cornerstone of this project.
+
+Special thanks to Jean-Philippe Gagné Guay for the numerous
+contributions to the code base.
+
+* GNU Free Documentation License
+:PROPERTIES:
+:APPENDIX: t
+:CUSTOM_ID: h:2d84e73e-c143-43b5-b388-a6765da974ea
+:END:
+
+#+texinfo: @include doclicense.texi
+
+#+begin_export html
+<pre>
+
+                GNU Free Documentation License
+                 Version 1.3, 3 November 2008
+
+
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+     <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns.  See
+https://www.gnu.org/licenses/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.3
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+</pre>
+#+end_export
+
+#+html: <!--
+
+* Indices
+:PROPERTIES:
+:CUSTOM_ID: h:dd530040-de9d-4f2b-8dfd-d8b8f14c058e
+:END:
+
+** Function index
+:PROPERTIES:
+:INDEX: fn
+:CUSTOM_ID: h:317b8c20-6dc1-4390-a20a-d01d75a48ccb
+:END:
+
+** Variable index
+:PROPERTIES:
+:INDEX: vr
+:CUSTOM_ID: h:2f69d4fe-0804-4f7f-aa57-4e03e7f20d98
+:END:
+
+** Concept index
+:PROPERTIES:
+:INDEX: cp
+:CUSTOM_ID: h:10365e44-2fc0-4b66-a613-682fea09ee68
+:END:
+
+#+html: -->
blob - /dev/null
blob + d19a789ff27c7479ccb21f61f543940c0edde9c4 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/denote-autoloads.el
@@ -0,0 +1,755 @@
+;;; denote-autoloads.el --- automatically extracted autoloads (do not edit)   -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+
+;;; Generated autoloads from denote.el
+
+ (put 'denote-directory 'safe-local-variable (lambda (val) (or (stringp val) (eq val 'local) (eq val 'default-directory))))
+ (put 'denote-known-keywords 'safe-local-variable #'listp)
+ (put 'denote-infer-keywords 'safe-local-variable (lambda (val) (or val (null val))))
+(autoload 'denote-sort-files "denote" "\
+Returned sorted list of Denote FILES.
+
+With COMPONENT as a symbol among `denote-sort-components',
+sort files based on the corresponding file name component.
+
+With COMPONENT as the symbol of a function, use it to perform the
+sorting.  In this case, the function is called with two arguments, as
+described by `sort'.
+
+With COMPONENT as a nil value keep the original date-based
+sorting which relies on the identifier of each file name.
+
+With optional REVERSE as a non-nil value, reverse the sort order.
+
+(fn FILES COMPONENT &optional REVERSE)")
+(autoload 'denote-sort-dired "denote" "\
+Produce Dired buffer with sorted files from variable `denote-directory'.
+When called interactively, prompt for FILES-MATCHING-REGEXP and,
+depending on the value of the user option `denote-sort-dired-extra-prompts',
+also prompt for SORT-BY-COMPONENT, REVERSE, and EXCLUDE-REGEXP.
+
+1. FILES-MATCHING-REGEXP limits the list of Denote files to
+   those matching the provided regular expression.
+
+2. SORT-BY-COMPONENT sorts the files by their file name component (one
+   among `denote-sort-components').  If it is nil, sorting is performed
+   according to the user option `denote-sort-dired-default-sort-component',
+   falling back to the identifier.
+
+3. REVERSE is a boolean to reverse the order when it is a non-nil value.
+   If `denote-sort-dired-extra-prompts' is configured to skip this
+   prompt, then the sorting is done according to the user option
+   `denote-sort-dired-default-reverse-sort', falling back to
+   nil (i.e. no reverse sort).
+
+4. EXCLUDE-REGEXP excludes the files that match the given regular
+   expression.  This is done after FILES-MATCHING-REGEXP and
+   OMIT-CURRENT have been applied.
+
+When called from Lisp, the arguments are a string, a symbol among
+`denote-sort-components', a non-nil value, and a string, respectively.
+
+(fn FILES-MATCHING-REGEXP SORT-BY-COMPONENT REVERSE EXCLUDE-REGEXP)" t)
+(autoload 'denote "denote" "\
+Create a new note with the appropriate metadata and file name.
+
+Run the `denote-after-new-note-hook' after creating the new note and
+return its path.  Before returning the path, determine what needs to be
+done to the buffer, in accordance with the user option `denote-kill-buffers'.
+
+When called interactively, the metadata and file name are prompted
+according to the value of `denote-prompts'.
+
+When called from Lisp, all arguments are optional.
+
+- TITLE is a string or a function returning a string.
+
+- KEYWORDS is a list of strings.  The list can be empty or the
+  value can be set to nil.
+
+- FILE-TYPE is a symbol among those described in the user option
+  `denote-file-type'.
+
+- DIRECTORY is a string representing the path to either the
+  value of the variable `denote-directory' or a subdirectory
+  thereof.  The subdirectory must exist: Denote will not create
+  it.  If DIRECTORY does not resolve to a valid path, the
+  variable `denote-directory' is used instead.
+
+- DATE is a string representing a date like 2022-06-30 or a date
+  and time like 2022-06-16 14:30.  A nil value or an empty string
+  is interpreted as the `current-time'.
+
+- TEMPLATE is a symbol which represents the key of a cons cell in
+  the user option `denote-templates'.  The value of that key is
+  inserted to the newly created buffer after the front matter.
+
+- SIGNATURE is a string or a function returning a string.
+
+(fn &optional TITLE KEYWORDS FILE-TYPE DIRECTORY DATE TEMPLATE SIGNATURE)" t)
+(autoload 'denote-type "denote" "\
+Create note while prompting for a file type.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `file-type' prompt appended to its existing prompts." t)
+(function-put 'denote-type 'interactive-only 't)
+(autoload 'denote-date "denote" "\
+Create note while prompting for a date.
+
+The date can be in YEAR-MONTH-DAY notation like 2022-06-30 or
+that plus the time: 2022-06-16 14:30.  When the user option
+`denote-date-prompt-use-org-read-date' is non-nil, the date
+prompt uses the more powerful Org+calendar system.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `date' prompt appended to its existing prompts." t)
+(function-put 'denote-date 'interactive-only 't)
+(autoload 'denote-subdirectory "denote" "\
+Create note while prompting for a subdirectory.
+
+Available candidates include the value of the variable
+`denote-directory' and any subdirectory thereof.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `subdirectory' prompt appended to its existing prompts." t)
+(function-put 'denote-subdirectory 'interactive-only 't)
+(autoload 'denote-template "denote" "\
+Create note while prompting for a template.
+
+Available candidates include the keys in the `denote-templates'
+alist.  The value of the selected key is inserted in the newly
+created note after the front matter.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `template' prompt appended to its existing prompts." t)
+(function-put 'denote-template 'interactive-only 't)
+(autoload 'denote-signature "denote" "\
+Create note while prompting for a file signature.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `signature' prompt appended to its existing prompts." t)
+(function-put 'denote-signature 'interactive-only 't)
+(autoload 'denote-region "denote" "\
+Call `denote' and insert therein the text of the active region.
+
+Note that, currently, `denote-save-buffers' and
+`denote-kill-buffers' are NOT respected.  The buffer is not
+saved or killed at the end of `denote-region'." t)
+(function-put 'denote-region 'interactive-only 't)
+(autoload 'denote-open-or-create "denote" "\
+Visit TARGET file in variable `denote-directory'.
+If file does not exist, invoke `denote' to create a file.  In that case,
+use the last input at the file prompt as the default value of the title
+prompt.
+
+(fn TARGET)" t)
+(autoload 'denote-open-or-create-with-command "denote" "\
+Like `denote-open-or-create' but use one of the `denote-commands-for-new-notes'." t)
+(function-put 'denote-open-or-create-with-command 'interactive-only 't)
+(autoload 'denote-rename-file "denote" "\
+Rename file and update existing front matter if appropriate.
+
+Always rename the file where it is located in the file system:
+never move it to another directory.
+
+If in Dired, consider FILE to be the one at point, else the
+current file, else prompt with minibuffer completion for one.
+When called from Lisp, FILE is a file system path represented as
+a string.
+
+If FILE has a Denote-compliant identifier, retain it while
+updating components of the file name referenced by the user
+option `denote-prompts'.  By default, these are the TITLE and
+KEYWORDS.  The SIGNATURE is another one.  When called from Lisp,
+TITLE and SIGNATURE are strings, while KEYWORDS is a list of
+strings.
+
+If there is no identifier, create an identifier based on the
+following conditions:
+
+1. If the `denote-prompts' includes an entry for date prompts,
+   then prompt for DATE and take its input to produce a new
+   identifier.  For use in Lisp, DATE must conform with
+   `denote-valid-date-p'.
+
+2. If DATE is nil (e.g. when `denote-prompts' does not include a
+   date entry), use the file attributes to determine the last
+   modified date of FILE and format it as an identifier.
+
+3. As a fallback, derive an identifier from the current date and
+   time.
+
+4. At any rate, if the resulting identifier is not unique among
+   the files in the variable `denote-directory', increment it
+   such that it becomes unique.
+
+In interactive use, and assuming `denote-prompts' includes a
+title entry, make the TITLE prompt have prefilled text in the
+minibuffer that consists of the current title of FILE.  The
+current title is either retrieved from the front matter (such as
+the #+title in Org) or from the file name.
+
+Do the same for the SIGNATURE prompt, subject to `denote-prompts',
+by prefilling the minibuffer with the current signature of FILE,
+if any.
+
+Same principle for the KEYWORDS prompt: convert the keywords in
+the file name into a comma-separated string and prefill the
+minibuffer with it (the KEYWORDS prompt accepts more than one
+keywords, each separated by a comma, else the `crm-separator').
+
+For all prompts, interpret an empty input as an instruction to
+remove that file name component.  For example, if a TITLE prompt
+is available and FILE is 20240211T093531--some-title__keyword1.org
+then rename FILE to 20240211T093531__keyword1.org.
+
+In interactive use, if there is no entry for a file name
+component in `denote-prompts', keep it as-is.
+
+When called from Lisp, the special symbol `keep-current' can be
+used for the TITLE, KEYWORDS, SIGNATURE and DATE parameters to
+keep them as-is.
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input.  The Emacs default setup accepts the
+  empty minibuffer contents as they are, though popular packages
+  like `vertico' use the first available completion candidate
+  instead.  For `vertico', the user must either move one up to
+  select the prompt and then type RET there with empty contents,
+  or use the command `vertico-exit-input' with empty contents.
+  That Vertico command is bound to M-RET as of this writing on
+  2024-02-13 08:08 +0200. ]
+
+As a final step, ask for confirmation, showing the difference
+between old and new file names.  Do not ask for confirmation if
+the user option `denote-rename-confirmations' does not contain
+the symbol `modify-file-name'.
+
+If FILE has front matter for TITLE and KEYWORDS, ask to rewrite
+their values in order to reflect the new input, unless
+`denote-rename-confirmations' lacks `rewrite-front-matter'.  When
+the `denote-save-buffers' is nil (the default), do not save the
+underlying buffer, thus giving the user the option to
+double-check the result, such as by invoking the command
+`diff-buffer-with-file'.  The rewrite of the TITLE and KEYWORDS
+in the front matter should not affect the rest of the front
+matter.
+
+If the file does not have front matter but is among the supported file
+types (per the user option `denote-file-type'), add front matter to the
+top of it and leave the buffer unsaved for further inspection.  Save the
+buffer if `denote-save-buffers' is non-nil.
+
+When `denote-kill-buffers' is t or `on-rename', kill the buffer
+if it was not already being visited before the rename operation.
+
+For the front matter of each file type, refer to the variables:
+
+- `denote-org-front-matter'
+- `denote-text-front-matter'
+- `denote-toml-front-matter'
+- `denote-yaml-front-matter'
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'.
+
+Run the `denote-after-rename-file-hook' after renaming FILE.
+
+This command is intended to (i) rename Denote files, (ii) convert
+existing supported file types to Denote notes, and (ii) rename
+non-note files (e.g. PDF) that can benefit from Denote's
+file-naming scheme.
+
+For a version of this command that works with multiple files
+one-by-one, use `denote-dired-rename-files'.
+
+(fn FILE TITLE KEYWORDS SIGNATURE DATE)" t)
+(autoload 'denote-dired-rename-files "denote" "\
+Rename Dired marked files same way as `denote-rename-file'.
+Rename each file in sequence, making all the relevant prompts.
+Unlike `denote-rename-file', do not prompt for confirmation of
+the changes made to the file: perform them outright (same as
+setting `denote-rename-confirmations' to a nil value)." '(dired-mode))
+(function-put 'denote-dired-rename-files 'interactive-only 't)
+(autoload 'denote-dired-rename-marked-files-with-keywords "denote" "\
+Rename marked files in Dired to a Denote file name by writing keywords.
+
+Specifically, do the following:
+
+- retain the file's existing name and make it the TITLE field,
+  per Denote's file-naming scheme;
+
+- sluggify the TITLE, according to our conventions (check the
+  user option `denote-file-name-slug-functions');
+
+- prepend an identifier to the TITLE;
+
+- preserve the file's extension, if any;
+
+- prompt once for KEYWORDS and apply the user's input to the
+  corresponding field in the file name, rewriting any keywords
+  that may exist while removing keywords that do exist if
+  KEYWORDS is empty;
+
+- add or rewrite existing front matter to the underlying file, if it is
+  recognized as a Denote note (per the user option `denote-file-type'),
+  such that it includes the new keywords.
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'.
+
+Run the `denote-after-rename-file-hook' after renaming is done.
+
+Also see the specialized commands to only add or remove keywords:
+
+- `denote-dired-rename-marked-files-add-keywords'.
+- `denote-dired-rename-marked-files-remove-keywords'." '(dired-mode))
+(function-put 'denote-dired-rename-marked-files-with-keywords 'interactive-only 't)
+(autoload 'denote-dired-rename-marked-files-add-keywords "denote" "\
+Like `denote-dired-rename-marked-files-with-keywords' to only add keywords." '(dired-mode))
+(function-put 'denote-dired-rename-marked-files-add-keywords 'interactive-only 't)
+(autoload 'denote-dired-rename-marked-files-remove-keywords "denote" "\
+Like `denote-dired-rename-marked-files-with-keywords' to only remove keywords." '(dired-mode))
+(function-put 'denote-dired-rename-marked-files-remove-keywords 'interactive-only 't)
+(autoload 'denote-rename-file-using-front-matter "denote" "\
+Rename FILE using its front matter as input.
+When called interactively, FILE is the variable `buffer-file-name' or
+the Dired file at point, which is subsequently inspected for the
+requisite front matter.  It is thus implied that the FILE has a file
+type that is supported by Denote, per the user option `denote-file-type'.
+
+The values of `denote-rename-confirmations',
+`denote-save-buffers' and `denote-kill-buffers' are respected.
+
+Only the front matter lines that appear in the front matter template (as
+defined in `denote-file-types') will be handled.
+
+To change the identifier (date) of the note with this command, the
+identifier line (if present) of the front matter must be modified.
+Modifying the date line has no effect.
+
+While this command generally does not modify the front matter, there are
+exceptions.  The value of the `date' line will follow that of the
+`identifier' line.  If they are both in the front matter template and
+the `date' line is missing, it will be added again.  Similarly, if they
+are both in the front matter template and the `date' line is present and
+the `identifier' line has been removed, the `date' line will be removed
+as well.  Also, if the keywords are out of order and
+`denote-sort-keywords' is non-nil, they will be sorted.  There will be a
+prompt for this if `denote-rename-confirmations' contains
+`rewrite-front-matter'.
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'.
+
+(fn FILE)" t)
+(autoload 'denote-dired-rename-marked-files-using-front-matter "denote" "\
+Call `denote-rename-file-using-front-matter' over the Dired marked files.
+Refer to the documentation of that command for the technicalities.
+
+Marked files must count as notes for the purposes of Denote, which means
+that they at least have an identifier in their file name and use a
+supported file type, per the user option `denote-file-type'.  Files that
+do not meet this criterion are ignored because Denote cannot know if
+they have front matter and what that may be." '(dired-mode))
+(autoload 'denote-change-file-type-and-front-matter "denote" "\
+Change file type of FILE and add an appropriate front matter.
+
+If in Dired, consider FILE to be the one at point, else the
+current file, else prompt with minibuffer completion for one.
+
+Add a front matter in the format of the NEW-FILE-TYPE at the
+beginning of the file.
+
+Retrieve the title of FILE from a line starting with a title
+field in its front matter, depending on the previous file
+type (e.g.  #+title for Org).  The same process applies for
+keywords.
+
+As a final step, ask for confirmation, showing the difference
+between old and new file names.
+
+Important note: No attempt is made to modify any other elements
+of the file.  This needs to be done manually.
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'.
+
+(fn FILE NEW-FILE-TYPE)" t)
+(autoload 'denote-dired-mode "denote" "\
+Fontify all Denote-style file names.
+
+Add this or `denote-dired-mode-in-directories' to
+`dired-mode-hook'.
+
+This is a minor mode.  If called interactively, toggle the `Denote-Dired
+mode' mode.  If the prefix argument is positive, enable the mode, and if
+it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
+mode if ARG is nil, omitted, or is a positive number.  Disable the mode
+if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate the variable `denote-dired-mode'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+(fn &optional ARG)" t)
+(autoload 'denote-dired-mode-in-directories "denote" "\
+Enable `denote-dired-mode' in `denote-dired-directories'.
+Add this function to `dired-mode-hook'.
+
+If `denote-dired-directories-include-subdirectories' is non-nil,
+also enable it in all subdirectories.")
+(autoload 'denote-link "denote" "\
+Create link to FILE note in variable `denote-directory' with DESCRIPTION.
+
+When called interactively, prompt for FILE using completion.  In this
+case, derive FILE-TYPE from the current buffer.  FILE-TYPE is used to
+determine the format of the link.
+
+Return the DESCRIPTION of the link in the format specified by
+`denote-link-description-format'.  The default is to return the text of
+the active region or the title of the note (plus the signature if
+present).
+
+With optional ID-ONLY as a non-nil argument, such as with a universal
+prefix (\\[universal-argument]), insert links with just the identifier
+and no further description.  In this case, the link format is always
+[[denote:IDENTIFIER]].
+
+If the DESCRIPTION is empty, format the link the same as with ID-ONLY.
+
+When called from Lisp, FILE is a string representing a full file system
+path.  FILE-TYPE is a symbol as described in the user option
+`denote-file-type'.  DESCRIPTION is a string.  Whether the caller treats
+the active region specially, is up to it.
+
+(fn FILE FILE-TYPE DESCRIPTION &optional ID-ONLY)" t)
+(autoload 'denote-find-link "denote" "\
+Use minibuffer completion to visit linked file.
+Also see `denote-find-backlink'." t)
+(function-put 'denote-find-link 'interactive-only 't)
+(autoload 'denote-link-after-creating "denote" "\
+Create new note in the background and link to it directly.
+
+Use `denote' interactively to produce the new note.  Its doc
+string explains which prompts will be used and under what
+conditions.
+
+With optional ID-ONLY as a prefix argument create a link that
+consists of just the identifier.  Else try to also include the
+file's title.  This has the same meaning as in `denote-link'.
+
+For a variant of this, see `denote-link-after-creating-with-command'.
+
+IMPORTANT NOTE: Normally, `denote' does not save the buffer it
+produces for the new note.  This is a safety precaution to not
+write to disk unless the user wants it (e.g. the user may choose
+to kill the buffer, thus cancelling the creation of the note).
+However, for this command the creation of the note happens in the
+background and the user may miss the step of saving their buffer.
+We thus have to save the buffer in order to (i) establish valid
+links, and (ii) retrieve whatever front matter from the target
+file.  Though see `denote-save-buffer-after-creation'.
+
+(fn &optional ID-ONLY)" t)
+(autoload 'denote-link-after-creating-with-command "denote" "\
+Like `denote-link-after-creating' but prompt for note-making COMMAND.
+Use this to, for example, call `denote-signature' so that the
+newly created note has a signature as part of its file name.
+
+Optional ID-ONLY has the same meaning as in the command
+`denote-link-after-creating'.
+
+(fn COMMAND &optional ID-ONLY)" t)
+(autoload 'denote-link-or-create "denote" "\
+Use `denote-link' on TARGET file, creating it if necessary.
+
+If TARGET file does not exist, call `denote-link-after-creating' which
+runs the `denote' command interactively to create the file.  The
+established link will then be targeting that new file.  In that case,
+use the last input at the file prompt as the default value of the title
+prompt.
+
+With optional ID-ONLY as a prefix argument create a link that
+consists of just the identifier.  Else try to also include the
+file's title.  This has the same meaning as in `denote-link'.
+
+(fn TARGET &optional ID-ONLY)" t)
+(autoload 'denote-grep "denote" "\
+Search QUERY in the content of Denote files.
+QUERY should be a regular expression accepted by `xref-search-program'.
+
+The files to search for are those returned by `denote-directory-files'
+with a non-nil TEXT-ONLY argument.
+
+Results are put in a buffer which allows folding and further
+filtering (see the manual for details).
+
+You can insert a link to a grep search in any note by using the command
+`denote-query-contents-link'.
+
+(fn QUERY)" t)
+(autoload 'denote-grep-marked-dired-files "denote" "\
+Do the equivalent of `denote-grep' for QUERY in marked Dired files.
+
+(fn QUERY)" t)
+(autoload 'denote-grep-files-referenced-in-region "denote" "\
+Perform `denote-grep' QUERY in files referenced between START and END.
+When called interactively, prompt for QUERY.  Also get START and END as
+the buffer positions that delimit the marked region.  When called from
+Lisp, QUERY is a string, while START and END are buffer positions, as
+integers.
+
+Find references to files by their identifier.  This includes links with
+just the identifier (as described in `denote-link' and related), links
+written by an Org dynamic block (see the `denote-org' package), or even
+file listings such as those of `dired' and the command-line `ls' program.
+
+(fn QUERY START END)" t)
+(autoload 'denote-backlinks "denote" "\
+Produce a buffer with backlinks to the current note.
+
+Show the names of files linking to the current file.  Include the
+context of each link if the user option `denote-backlinks-show-context'
+is non-nil.
+
+Place the buffer below the current window or wherever the user option
+`denote-backlinks-display-buffer-action' specifies." t)
+(autoload 'denote-find-backlink "denote" "\
+Use minibuffer completion to visit backlink to current file.
+Alo see `denote-find-link'." t)
+(function-put 'denote-find-backlink 'interactive-only 't)
+(autoload 'denote-query-contents-link "denote" "\
+Insert query link for file contents.
+Prompt for QUERY or use the text of the active region.  When the user
+follows this link, place any matches in a separate buffer (using the
+built-in Xref mechanism).  This is the equivalent of a Unix grep command
+across the variable `denote-directory'.
+
+(fn QUERY)" t)
+(autoload 'denote-query-filenames-link "denote" "\
+Insert query link for file names.
+Prompt for QUERY or use the text of the active region.  When the user
+follows this link, place any matches in a separate buffer (using the
+built-in Dired mechanism).  This is the equivalent of a Unix find
+command across the variable `denote-directory'.
+
+(fn QUERY)" t)
+(autoload 'denote-fontify-links-mode-maybe "denote" "\
+Enable `denote-fontify-links-mode' in a denote file unless in `org-mode'.")
+(autoload 'denote-fontify-links-mode "denote" "\
+A minor mode to fontify and fold Denote links.
+
+Enabled this mode only when the current buffer is a Denote note and the
+major mode is not `org-mode' (or derived therefrom).  Consider using
+`denote-fontify-links-mode-maybe' for this purpose.
+
+This is a minor mode.  If called interactively, toggle the
+`Denote-Fontify-Links mode' mode.  If the prefix argument is positive,
+enable the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
+mode if ARG is nil, omitted, or is a positive number.  Disable the mode
+if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate the variable `denote-fontify-links-mode'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+(fn &optional ARG)" t)
+(autoload 'denote-add-links "denote" "\
+Insert links to all files whose file names match REGEXP.
+Use this command to reference multiple files at once.  Particularly
+useful for the creation of metanotes (read the manual for more on the
+matter).
+
+Optional ID-ONLY has the same meaning as in `denote-link': it
+inserts links with just the identifier.
+
+(fn REGEXP &optional ID-ONLY)" t)
+(autoload 'denote-link-to-file-with-contents "denote" "\
+Link to a file whose contents match QUERY.
+This is similar to `denote-link', except that the file prompt is limited
+to files matching QUERY.  Optional ID-ONLY has the same meaning as in
+`denote-link'.
+
+(fn QUERY &optional ID-ONLY)" t)
+(autoload 'denote-link-to-all-files-with-contents "denote" "\
+Link to all files whose contents match QUERY.
+This is similar to `denote-add-links', except it searches inside file
+contents, not file names.  Optional ID-ONLY has the same meaning as in
+`denote-link' and `denote-add-links'.
+
+(fn QUERY &optional ID-ONLY)" t)
+(autoload 'denote-link-dired-marked-notes "denote" "\
+Insert Dired marked FILES as links in BUFFER.
+
+FILES conform with the Denote file-naming scheme, such that they can be
+linked to using the `denote:' link type.
+
+The BUFFER is one which visits a Denote note file.  If there are
+multiple BUFFER candidates in buffers, prompt with completion for
+one among them.  If there is none, throw an error.
+
+With optional ID-ONLY as a prefix argument, insert links with
+just the identifier (same principle as with `denote-link').
+
+This command is meant to be used from a Dired buffer.
+
+(fn FILES BUFFER &optional ID-ONLY)" '(dired-mode))
+(defvar denote-menu-bar-mode t "\
+Non-nil if Denote-Menu-Bar mode is enabled.
+See the `denote-menu-bar-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `denote-menu-bar-mode'.")
+(custom-autoload 'denote-menu-bar-mode "denote" nil)
+(autoload 'denote-menu-bar-mode "denote" "\
+Show Denote menu bar.
+
+This is a global minor mode.  If called interactively, toggle the
+`Denote-Menu-Bar mode' mode.  If the prefix argument is positive, enable
+the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
+mode if ARG is nil, omitted, or is a positive number.  Disable the mode
+if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `(default-value \\='denote-menu-bar-mode)'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+(fn &optional ARG)" t)
+(autoload 'denote-link-ol-follow "denote" "\
+Find file of type `denote:' matching LINK.
+LINK is the identifier of the note, optionally followed by a file search
+option akin to that of standard Org `file:' link types.  Read Info
+node `(org) Query Options'.
+
+If LINK is not an identifier, then it is not pointing to a file but to a
+query of file contents or file names (see the commands
+`denote-query-contents-link' and `denote-query-filenames-link').
+
+Uses the function `denote-directory' to establish the path to the file.
+
+(fn LINK)")
+(autoload 'denote-link-ol-complete "denote" "\
+Like `denote-link' but for Org integration.
+This lets the user complete a link through the `org-insert-link'
+interface by first selecting the `denote:' hyperlink type.")
+(autoload 'denote-link-ol-store "denote" "\
+Handler for `org-store-link' adding support for denote: links.
+Optional INTERACTIVE? is used by `org-store-link'.
+
+Also see the user option `denote-org-store-link-to-heading'.
+
+(fn &optional INTERACTIVE?)")
+(autoload 'denote-link-ol-export "denote" "\
+Export a `denote:' link from Org files.
+The LINK, DESCRIPTION, and FORMAT are handled by the export
+backend.
+
+(fn LINK DESCRIPTION FORMAT)")
+(eval-after-load 'org `(funcall ',(lambda nil (with-no-warnings (org-link-set-parameters "denote" :follow #'denote-link-ol-follow :face #'denote-get-link-face :help-echo #'denote-link-ol-help-echo :complete #'denote-link-ol-complete :store #'denote-link-ol-store :export #'denote-link-ol-export)))))
+(autoload 'denote-org-capture "denote" "\
+Create new note through `org-capture-templates'.
+Use this as a function that returns the path to the new file.
+The file is populated with Denote's front matter.  It can then be
+expanded with the usual specifiers or strings that
+`org-capture-templates' supports.
+
+This function obeys `denote-prompts', but it ignores `file-type',
+if present: it always sets the Org file extension for the created
+note to ensure that the capture process works as intended,
+especially for the desired output of the
+`denote-org-capture-specifiers' (which can include arbitrary
+text).
+
+Consult the manual for template samples.")
+(autoload 'denote-org-capture-with-prompts "denote" "\
+Like `denote-org-capture' but with optional prompt parameters.
+
+When called without arguments, do not prompt for anything.  Just
+return the front matter with title and keyword fields empty and
+the date and identifier fields specified.  Also make the file
+name consist of only the identifier plus the Org file name
+extension.
+
+Otherwise produce a minibuffer prompt for every non-nil value
+that corresponds to the TITLE, KEYWORDS, SUBDIRECTORY, DATE, and
+TEMPLATE arguments.  The prompts are those used by the standard
+`denote' command and all of its utility commands.
+
+When returning the contents that fill in the Org capture
+template, the sequence is as follows: front matter, TEMPLATE, and
+then the value of the user option `denote-org-capture-specifiers'.
+
+Important note: in the case of SUBDIRECTORY actual subdirectories
+must exist---Denote does not create them.  Same principle for
+TEMPLATE as templates must exist and are specified in the user
+option `denote-templates'.
+
+(fn &optional TITLE KEYWORDS SUBDIRECTORY DATE TEMPLATE)")
+(defvar denote-rename-buffer-mode nil "\
+Non-nil if Denote-Rename-Buffer mode is enabled.
+See the `denote-rename-buffer-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `denote-rename-buffer-mode'.")
+(custom-autoload 'denote-rename-buffer-mode "denote" nil)
+(autoload 'denote-rename-buffer-mode "denote" "\
+Automatically rename Denote buffers to be easier to read.
+
+A buffer is renamed upon visiting the underlying file.  This
+means that existing buffers are not renamed until they are
+visited again in a new buffer (files are visited with the command
+`find-file' or related).
+
+This is a global minor mode.  If called interactively, toggle the
+`Denote-Rename-Buffer mode' mode.  If the prefix argument is positive,
+enable the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
+mode if ARG is nil, omitted, or is a positive number.  Disable the mode
+if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `(default-value \\='denote-rename-buffer-mode)'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+(fn &optional ARG)" t)
+(register-definition-prefixes "denote" '("denote-"))
+
+;;; End of scraped data
+
+(provide 'denote-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; denote-autoloads.el ends here
blob - /dev/null
blob + d9e18a70a8b0eedb75f28e1fe6317142707c3127 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/denote-pkg.el
@@ -0,0 +1,2 @@
+;; Generated package description from mode: lisp-data; .el  -*- denoteno-byte-compile: t -*-
+(define-package "denote" "4.0.0" "Simple notes with an efficient file-naming scheme" '((emacs "28.1")) :commit "c98c74ec74fb6f0c894c5bf730d092d716e55b84" :authors '(("Protesilaos Stavrou" . "info@protesilaos.com")) :maintainer '("Protesilaos Stavrou" . "info@protesilaos.com") :url "https://github.com/protesilaos/denote")
blob - /dev/null
blob + e0677608ee1d1c1cd666f866a131ce348564995e (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/denote.el
@@ -0,0 +1,6478 @@
+;;; denote.el --- Simple notes with an efficient file-naming scheme -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022-2025  Free Software Foundation, Inc.
+
+;; Author: Protesilaos Stavrou <info@protesilaos.com>
+;; Maintainer: Protesilaos Stavrou <info@protesilaos.com>
+;; URL: https://github.com/protesilaos/denote
+;; Version: 4.0.0
+;; Package-Requires: ((emacs "28.1"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Denote aims to be a simple-to-use, focused-in-scope, and effective
+;; note-taking and file-naming tool for Emacs.
+;;
+;; Denote is based on the idea that files should follow a predictable
+;; and descriptive file-naming scheme.  The file name must offer a
+;; clear indication of what the contents are about, without reference
+;; to any other metadata.  Denote basically streamlines the creation
+;; of such files or file names while providing facilities to link
+;; between them (where those files are editable).
+;;
+;; Denote's file-naming scheme is not limited to "notes".  It can be used
+;; for all types of file, including those that are not editable in Emacs,
+;; such as videos.  Naming files in a consistent way makes their
+;; filtering and retrieval considerably easier.  Denote provides relevant
+;; facilities to rename files, regardless of file type.
+;;
+;; The manual describes all the technicalities about the file-naming
+;; scheme, points of entry to creating new notes, commands to check
+;; links between notes, and more: ;; <https://protesilaos.com/emacs/denote>.
+;; If you have the info manual available, evaluate:
+;;
+;;    (info "(denote) Top")
+;;
+;; What follows is a general overview of its core core design
+;; principles (again: please read the manual for the technicalities):
+;;
+;; * Predictability :: File names must follow a consistent and
+;;   descriptive naming convention (see the manual's "The file-naming
+;;   scheme").  The file name alone should offer a clear indication of
+;;   what the contents are, without reference to any other metadatum.
+;;   This convention is not specific to note-taking, as it is pertinent
+;;   to any form of file that is part of the user's long-term storage
+;;   (see the manual's "Renaming files").
+;;
+;; * Composability :: Be a good Emacs citizen, by integrating with other
+;;   packages or built-in functionality instead of re-inventing
+;;   functions such as for filtering or greping.  The author of Denote
+;;   (Protesilaos, aka "Prot") writes ordinary notes in plain text
+;;   (`.txt'), switching on demand to an Org file only when its expanded
+;;   set of functionality is required for the task at hand (see the
+;;   manual's "Points of entry").
+;;
+;; * Portability :: Notes are plain text and should remain portable.
+;;   The way Denote writes file names, the front matter it includes in
+;;   the note's header, and the links it establishes must all be
+;;   adequately usable with standard Unix tools.  No need for a databse
+;;   or some specialised software.  As Denote develops and this manual
+;;   is fully fleshed out, there will be concrete examples on how to do
+;;   the Denote-equivalent on the command-line.
+;;
+;; * Flexibility :: Do not assume the user's preference for a
+;;   note-taking methodology.  Denote is conceptually similar to the
+;;   Zettelkasten Method, which you can learn more about in this
+;;   detailed introduction: <https://zettelkasten.de/introduction/>.
+;;   Notes are atomic (one file per note) and have a unique identifier.
+;;   However, Denote does not enforce a particular methodology for
+;;   knowledge management, such as a restricted vocabulary or mutually
+;;   exclusive sets of keywords.  Denote also does not check if the user
+;;   writes thematically atomic notes.  It is up to the user to apply
+;;   the requisite rigor and/or creativity in pursuit of their preferred
+;;   workflow (see the manual's "Writing metanotes").
+;;
+;; * Hackability :: Denote's code base consists of small and reusable
+;;   functions.  They all have documentation strings.  The idea is to
+;;   make it easier for users of varying levels of expertise to
+;;   understand what is going on and make surgical interventions where
+;;   necessary (e.g. to tweak some formatting).  In this manual, we
+;;   provide concrete examples on such user-level configurations (see
+;;   the manual's "Keep a journal or diary").
+;;
+;; Now the important part...  "Denote" is the familiar word, though it
+;; also is a play on the "note" concept.  Plus, we can come up with
+;; acronyms, recursive or otherwise, of increasingly dubious utility
+;; like:
+;;
+;; + Don't Ever Note Only The Epiphenomenal
+;; + Denote Everything Neatly; Omit The Excesses
+;;
+;; But we'll let you get back to work.  Don't Eschew or Neglect your
+;; Obligations, Tasks, and Engagements.
+
+;;; Code:
+
+(require 'seq)
+(require 'xref)
+(require 'dired)
+(eval-when-compile (require 'subr-x))
+
+(defgroup denote ()
+  "Simple notes with an efficient file-naming scheme."
+  :group 'files
+  :link '(info-link "(denote) Top")
+  :link '(url-link :tag "Homepage" "https://protesilaos.com/emacs/denote"))
+
+;;;; User options
+
+;; About the autoload: (info "(elisp) File Local Variables")
+
+;;;###autoload (put 'denote-directory 'safe-local-variable (lambda (val) (or (stringp val) (eq val 'local) (eq val 'default-directory))))
+(defcustom denote-directory (expand-file-name "~/Documents/notes/")
+  "Directory for storing personal notes.
+
+If you intend to reference this variable in Lisp, consider using
+the function `denote-directory' instead."
+  :group 'denote
+  :safe (lambda (val) (or (stringp val) (eq val 'local) (eq val 'default-directory)))
+  :package-version '(denote . "2.0.0")
+  :link '(info-link "(denote) Maintain separate directories for notes")
+  :type 'directory)
+
+(define-obsolete-variable-alias 'denote-save-buffer-after-creation 'denote-save-buffers "3.0.0")
+
+(defcustom denote-save-buffers nil
+  "Control whether commands that handle new notes save their buffer outright.
+
+The default behaviour of commands such as `denote' (or related)
+is to not save the buffer they create.  This gives the user the
+chance to review the text before writing it to a file.  The user
+may choose to delete the unsaved buffer, thus not creating a new
+note.
+
+This option also applies to notes affected by the renaming
+commands (`denote-rename-file' and related).
+
+If this user option is set to a non-nil value, such buffers are
+saved automatically.  The assumption is that the user who opts in
+to this feature is familiar with the `denote-rename-file'
+operation (or related) and knows it is reliable.  Data loss may
+occur if the file is modified externally.
+
+Also see `denote-kill-buffers'."
+  :group 'denote
+  :package-version '(denote . "3.0.0")
+  :type 'boolean)
+
+(defcustom denote-kill-buffers nil
+  "Control whether creation or renaming commands kill their buffer.
+
+The default behaviour of creation or renaming commands such as
+`denote' or `denote-rename-file' is to not kill the buffer they
+create or modify at the end of their operation.
+
+If this user option is nil (the default), buffers affected by a
+creation or renaming command are not automatically killed.
+
+If set to `on-creation', new notes are automatically killed.
+
+If set to `on-rename', renamed notes are automatically killed.
+
+If set to t, new and renamed notes are killed.
+
+If a buffer is killed, it is also saved, as if `denote-save-buffers'
+were t. See its documentation.
+
+In all cases, if the buffer already existed before the Denote operation
+it is NOT automatically killed."
+  :group 'denote
+  :package-version '(denote . "3.1.0")
+  :type '(choice
+          (const :tag "Do not kill buffers" nil)
+          (const :tag "Kill after creation" on-creation)
+          (const :tag "Kill after rename" on-rename)
+          (const :tag "Kill after creation and rename" t)))
+
+;;;###autoload (put 'denote-known-keywords 'safe-local-variable #'listp)
+(defcustom denote-known-keywords
+  '("emacs" "philosophy" "politics" "economics")
+  "List of strings with predefined keywords for `denote'.
+Also see user options: `denote-infer-keywords',
+`denote-sort-keywords', `denote-file-name-slug-functions'."
+  :group 'denote
+  :safe #'listp
+  :package-version '(denote . "0.1.0")
+  :type '(repeat string))
+
+;;;###autoload (put 'denote-infer-keywords 'safe-local-variable (lambda (val) (or val (null val))))
+(defcustom denote-infer-keywords t
+  "Whether to infer keywords from existing notes' file names.
+
+When non-nil, search the file names of existing notes in the
+variable `denote-directory' for their keyword field and extract
+the entries as \"inferred keywords\".  These are combined with
+`denote-known-keywords' and are presented as completion
+candidates while using `denote' and related commands
+interactively.
+
+If nil, refrain from inferring keywords.  The aforementioned
+completion prompt only shows the `denote-known-keywords'.  Use
+this if you want to enforce a restricted vocabulary.
+
+The user option `denote-excluded-keywords-regexp' can be used to
+exclude keywords that match a regular expression.
+
+Inferred keywords are specific to the value of the variable
+`denote-directory'.  If a silo with a local value is used, as
+explained in that variable's doc string, the inferred keywords
+are specific to the given silo.
+
+For advanced Lisp usage, the function `denote-keywords' returns
+the appropriate list of strings."
+  :group 'denote
+  :safe (lambda (val) (or val (null val)))
+  :package-version '(denote . "0.1.0")
+  :type 'boolean)
+
+(defcustom denote-prompts '(title keywords)
+  "Specify the prompts followed by relevant Denote commands.
+
+Commands that prompt for user input to construct a Denote file name
+include, but are not limited to: `denote', `denote-signature',
+`denote-type', `denote-date', `denote-subdirectory',
+`denote-rename-file', `denote-dired-rename-files'.
+
+The value of this user option is a list of symbols, which includes any
+of the following:
+
+- `title': Prompt for the title of the new note.
+
+- `keywords': Prompts with completion for the keywords of the new note.
+  Available candidates are those specified in the user option
+  `denote-known-keywords'.  If the user option `denote-infer-keywords'
+  is non-nil, keywords in existing note file names are included in the
+  list of candidates.  The `keywords' prompt uses `completing-read-multiple',
+  meaning that it can accept multiple keywords separated by a comma (or
+  whatever the value of `crm-separator' is).
+
+- `file-type': Prompts with completion for the file type of the new
+  note.  Available candidates are those specified in the user option
+  `denote-file-type'.  Without this prompt, `denote' uses the value of
+  the variable `denote-file-type'.
+
+- `subdirectory': Prompts with completion for a subdirectory in which to
+  create the note.  Available candidates are the value of the user
+  option `denote-directory' and all of its subdirectories.  Any
+  subdirectory must already exist: Denote will not create it.
+
+- `date': Prompts for the date of the new note.  It will expect an input
+  like 2022-06-16 or a date plus time: 2022-06-16 14:30.  Without the
+  `date' prompt, the `denote' command uses the `current-time'.  (To
+  leverage the more sophisticated Org method, see the
+  `denote-date-prompt-use-org-read-date'.)
+
+- `template': Prompts for a KEY among `denote-templates'.  The value of
+  that KEY is used to populate the new note with content, which is added
+  after the front matter.
+
+- `signature': Prompts for an arbitrary string that can be used for any
+  kind of workflow, such as a special tag to label the part1 and part2
+  of a large file that is split in half, or to add special contexts like
+  home and work, or even priorities like a, b, c. One other use-case is
+  to implement a sequencing scheme that makes notes have hierarchical
+  relationships.  This is handled by our optional extension
+  denote-sequence.el, which is part of the denote package (read the
+  manual).
+
+The prompts occur in the given order.
+
+If the value of this user option is nil, no prompts are used.  The
+resulting file name will consist of an identifier (i.e. the date and
+time) and a supported file type extension (per the variable
+`denote-file-type').
+
+Recall that Denote's standard file-naming scheme is defined as
+follows (read the manual for the technicalities):
+
+    DATE--TITLE__KEYWORDS.EXT
+
+Depending on the inclusion of the `title', `keywords', and
+`signature' prompts, file names will be any of those
+permutations:
+
+    DATE.EXT
+    DATE--TITLE.EXT
+    DATE__KEYWORDS.EXT
+    DATE==SIGNATURE.EXT
+    DATE==SIGNATURE--TITLE.EXT
+    DATE==SIGNATURE--TITLE__KEYWORDS.EXT
+    DATE==SIGNATURE__KEYWORDS.EXT
+
+When in doubt, always include the `title' and `keywords'
+prompts (the default style).
+
+Finally, this user option only affects the interactive use of the
+`denote' or other relevant commands (advanced users can call it from
+Lisp).  In Lisp usage, the behaviour is always what the caller
+specifies, based on the supplied arguments.
+
+Also see `denote-history-completion-in-prompts'.
+
+To change the order of the file name components, refer to
+`denote-file-name-components-order'."
+  :group 'denote
+  :package-version '(denote . "2.3.0")
+  :link '(info-link "(denote) The denote-prompts option")
+  :type '(radio (const :tag "Use no prompts" nil)
+                (set :tag "Available prompts" :greedy t
+                     (const :tag "Title" title)
+                     (const :tag "Keywords" keywords)
+                     (const :tag "Date" date)
+                     (const :tag "File type extension" file-type)
+                     (const :tag "Subdirectory" subdirectory)
+                     (const :tag "Template" template)
+                     (const :tag "Signature" signature))))
+
+(defcustom denote-file-name-components-order '(identifier signature title keywords)
+  "Specify the order of the file name components.
+
+The value is a list of the following symbols:
+
+- `identifier': This is the combination of the date and time.  When it
+  is the first on the list, it looks like \"20240519T073456\" and does
+  not have a component separator of its own due its unambiguous format.
+  When it is placed anywhere else in the file name, it is prefixed with
+  \"@@\", so it looks like \"@@20240519T073456\".
+
+- `signature': This is an arbitrary string that can be used to qualify
+  the file in some way, according to the user's methodology (e.g. to add
+  a sequence to notes).  The string is always prefixed with the \"==\"
+  to remain unambiguous.
+
+- `title': This is an arbitrary string which describes the file.  It is
+  always prefixed with \"--\" to be unambiguous.
+
+- `keywords': This is a series of one or more words that succinctly
+  group the file.  Multiple keywords are separated by an underscore
+  prefixed to each of them.  The file name component is always prefixed
+  with \"__\".
+
+All four symbols must appear exactly once.  Duplicates are ignored.  Any
+missing symbol is added automatically.
+
+Some examples:
+
+    (setq denote-file-name-components-order
+       \\='(identifier signature title keywords))
+    => 20240519T07345==hello--this-is-the-title__denote_testing.org
+
+    (setq denote-file-name-components-order
+       \\='(signature identifier title keywords))
+    => ==hello@@20240519T07345--this-is-the-title__denote_testing.org
+
+    (setq denote-file-name-components-order
+       \\='(title signature identifier keywords))
+    => --this-is-the-title==hello@@20240519T07345__denote_testing.org
+
+    (setq denote-file-name-components-order
+       \\='(keywords title signature identifier))
+    => __denote_testing--this-is-the-title==hello@@20240519T07345.org
+
+Also see the user option `denote-prompts', which affects which
+components are actually used in the order specified herein.
+
+Before deciding on this, please consider the longer-term implications
+of file names with varying patterns. Consistency makes things
+predictable and thus easier to find. So pick one order and never touch
+it again. When in doubt, leave the default file-naming scheme as-is.
+
+This user option should only be used to build a file name.  Custom code
+should not have behaviors that depend on its value.  The reason is that
+its value can change over time and Denote should be able to handle past
+and current notes."
+  :group 'denote
+  :package-version '(denote . "3.0.0")
+  ;; FIXME 2024-05-19: This technically works to display the user
+  ;; option in the Custom buffer and to show its current value, though
+  ;; it does not allow the user to modify it graphically: they have to
+  ;; switch to the Lisp expression.  Find a way to present an
+  ;; interface that lets the user reorder those elements.
+  ;;
+  ;; Still, making this a defcustom helps with discoverability, as
+  ;; well as with the use of `setopt' and related.
+  :type '(list
+          (const :tag "Identifier component (date and time)" identifier)
+          (const :tag "File signature (text to qualify a file)" signature)
+          (const :tag "The title of the file" title)
+          (const :tag "Keywords of the file" keywords)))
+
+(defcustom denote-front-matter-components-present-even-if-empty-value '(title keywords date identifier)
+  "The components that are always present in front matter even when empty.
+
+Components are `title', `keywords', `signature', `date', `identifier'.
+
+Note that even though a component may be listed in this variable, it
+will not be present in the front matter if the corresponding line is not
+in the front matter template."
+  :group 'denote
+  :package-version '(denote . "4.0.0")
+  :type '(list
+          (const :tag "Title" title)
+          (const :tag "Keywords" keywords)
+          (const :tag "Signature" signature)
+          (const :tag "Date" date)
+          (const :tag "Identifier" identifier)))
+
+(defcustom denote-sort-keywords t
+  "Whether to sort keywords in new files.
+
+When non-nil, the keywords of `denote' are sorted with
+`string-collate-lessp' regardless of the order they were inserted at the
+minibuffer prompt.
+
+If nil, show the keywords in their given order."
+  :group 'denote
+  :package-version '(denote . "0.1.0")
+  :type 'boolean)
+
+(defcustom denote-file-type nil
+  "The file type extension for new notes.
+
+By default (a nil value), the file type is that of Org mode.
+Though the `org' symbol can be specified for the same effect.
+
+When the value is the symbol `markdown-yaml', the file type is
+that of Markdown mode and the front matter uses YAML notation.
+Similarly, `markdown-toml' is Markdown but has TOML syntax in the
+front matter.
+
+When the value is `text', the file type is that of Text mode.
+
+Any other non-nil value is the same as the default.
+
+NOTE: Expert users can change the supported file-types by editing
+the value of `denote-file-types'.  That variable, which is not a
+user option, controls the behaviour of all file-type-aware
+functions (creating notes, renaming them, inserting front matter,
+formatting a link, etc.). Consult its documentation for the
+technicalities."
+  :type '(choice
+          (const :tag "Unspecified (defaults to Org)" nil)
+          (const :tag "Org mode (default)" org)
+          (const :tag "Markdown (YAML front matter)" markdown-yaml)
+          (const :tag "Markdown (TOML front matter)" markdown-toml)
+          (const :tag "Plain text" text))
+  :package-version '(denote . "0.6.0")
+  :group 'denote)
+
+(defcustom denote-date-format nil
+  "Date format in the front matter (file header) of new notes.
+
+When nil (the default value), use a file-type-specific
+format (also check the user option `denote-file-type'):
+
+- For Org, an inactive timestamp is used, such as [2022-06-30 Wed
+  15:31].
+
+- For Markdown, the RFC3339 standard is applied:
+  2022-06-30T15:48:00+03:00.
+
+- For plain text, the format is that of ISO 8601: 2022-06-30.
+
+If the value is a string, ignore the above and use it instead.
+The string must include format specifiers for the date.  These
+are described in the doc string of `format-time-string'."
+  :type '(choice
+          (const :tag "Use appropiate format for each file type" nil)
+          (string :tag "Custom format for `format-time-string'"))
+  :package-version '(denote . "0.2.0")
+  :group 'denote)
+
+(defcustom denote-date-prompt-use-org-read-date nil
+  "Whether to use `org-read-date' in date prompts.
+
+If non-nil, use `org-read-date'.  If nil, input the date as a
+string, as described in `denote'.
+
+This option is relevant when `denote-prompts' includes a `date'
+and/or when the user invokes the command `denote-date'."
+  :group 'denote
+  :package-version '(denote . "0.6.0")
+  :type 'boolean)
+
+(defcustom denote-org-store-link-to-heading nil
+  "Determine whether `org-store-link' links to the current Org heading.
+
+[ Remember that what `org-store-link' does is merely collect a link.  To
+  actually insert it, use the command `org-insert-link'.  Note that
+  `org-capture' uses `org-store-link' internally when it needs to store
+  a link.  ]
+
+When the value is nil, the Denote handler for `org-store-link' produces
+links only to the current file (by using the file's identifier).  For
+example:
+
+    [[denote:20240118T060608][Some test]]
+
+If the value is `context', the link consists of the file's identifier
+and the text of the current heading, like this:
+
+    [[denote:20240118T060608::*Heading text][Some test::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.
+
+If the value is `id' or, for backward-compatibility, any other non-nil
+value, then Denote will use the standard Org mechanism of the CUSTOM_ID
+property to create a unique link to the heading.  If the heading does
+not have a CUSTOM_ID, it creates it and includes it in its PROPERTIES
+drawer.  If a CUSTOM_ID exists, it takes it as-is.  The result is like
+this:
+
+    [[denote:20240118T060608::#h:eed0fb8e-4cc7-478f][Some test::Heading text]]
+
+The value of the CUSTOM_ID is determined by the Org user option
+`org-id-method'.  The sample shown above uses the default UUID
+infrastructure (though I deleted a few characters to not get
+complaints from the byte compiler about long lines in the doc
+string...).
+
+Note that this option does not affect how Org behaves with regard to
+`org-id-link-to-org-use-id'.  If that user option is set to create ID
+properties, then those will be created by Org even if the Denote link
+handler will take care to not use/store the ID value.  Concretely, users
+who never want ID properties under their headings should keep
+`org-id-link-to-org-use-id' in its nil value.
+
+Context links are easier to break than those with a CUSTOM_ID in cases
+where either the heading text changes or there is another heading that
+matches that text.  The potential advantage of context links is that
+they do not require a PROPERTIES drawer.
+
+When visiting a link to a heading, Org opens the Denote file and then
+navigates to that heading.
+
+[ This feature only works in Org mode files, as other file types
+  do not have a linking mechanism that handles unique identifiers
+  for headings or other patterns to jump to.  If `org-store-link'
+  is invoked in one such file, it captures only the Denote
+  identifier of the file, even if this user option is set to a
+  non-nil value.  ]"
+  :group 'denote
+  :package-version '(denote . "4.0.0")
+  :type '(choice (const :tag "No link to heading (default)" nil)
+                 (const :tag "Link to the context" context)
+                 (const :tag "Link wtih CUSTOM_ID, creating it if needed" id)))
+
+(defcustom denote-templates nil
+  "Alist of content templates for new notes.
+A template is arbitrary text that Denote will add to a newly
+created note right below the front matter.
+
+Templates are expressed as a (KEY . VALUE) association.
+
+- The KEY is the name which identifies the template.  It is an
+  arbitrary symbol, such as `report', `memo', `statement'.
+
+- The VALUE is either a string or the symbol of a function.
+
+  - If it is a string, it is ordinary text that Denote will insert
+    as-is.  It can contain newline characters to add spacing.  The
+    manual of Denote contains examples on how to use the `concat'
+    function, beside writing a generic string.
+
+  - If it is a function, it is called without arguments and is expected
+    to return a string.  Denote will call the function and insert the
+    result in the buffer.
+
+The user can choose a template either by invoking the command
+`denote-template' or by changing the user option `denote-prompts'
+to always prompt for a template when calling the `denote'
+command."
+  :type '(alist :key-type symbol :value-type (choice string function))
+  :package-version '(denote . "3.1.0")
+  :link '(info-link "(denote) The denote-templates option")
+  :group 'denote)
+
+(make-obsolete-variable 'denote-rename-no-confirm 'denote-rename-confirmations "3.0.0")
+
+(defcustom denote-rename-confirmations '(rewrite-front-matter modify-file-name)
+  "Make renaming commands prompt for confirmations.
+
+This affects the behaviour of renaming commands.  The value is either
+nil, in which case no confirmation is ever requested, or a list of
+symbols among the following:
+
+- `modify-file-name' means that renaming commands will ask for
+  confirmation before modifying the file name.
+
+- `rewrite-front-matter' means that renaming commands will ask for
+  confirmation before rewritting the front matter.
+
+- `add-front-matter' means that renaming commands will ask for
+  confirmation before adding new front matter to the file.
+
+The default behaviour of the `denote-rename-file' command (and others
+like it) is to ask for an affirmative answer as a final step before
+changing the file name and, where relevant, inserting or updating the
+corresponding front matter.
+
+Specialized commands that build on top of `denote-rename-file' (or
+related) may internally bind this user option to a non-nil value in
+order to perform their operation (e.g. `denote-dired-rename-files' goes
+through each marked Dired file, prompting for the information to use,
+but carries out the renaming without asking for confirmation)."
+  :group 'denote
+  :type '(radio (const :tag "Disable all confirmations" nil)
+                (set :tag "Available confirmations" :greedy t
+                     (const :tag "Add front matter" add-front-matter)
+                     (const :tag "Rewrite front matter" rewrite-front-matter)
+                     (const :tag "Modify file name" modify-file-name))))
+
+(defcustom denote-excluded-directories-regexp nil
+  "Regular expression of directories to exclude from all operations.
+Omit matching directories from file prompts and also exclude them
+from all functions that check the contents of the variable
+`denote-directory'.  The regexp needs to match only the name of
+the directory, not its full path.
+
+File prompts are used by several commands, such as `denote-link'
+and `denote-subdirectory'.
+
+Functions that check for files include `denote-directory-files'
+and `denote-directory-subdirectories'.
+
+The match is performed with `string-match-p'."
+  :group 'denote
+  :package-version '(denote . "1.2.0")
+  :type 'string)
+
+(defcustom denote-excluded-keywords-regexp nil
+  "Regular expression of keywords to not infer.
+Keywords are inferred from file names and provided at relevant
+prompts as completion candidates when the user option
+`denote-infer-keywords' is non-nil.
+
+The match is performed with `string-match-p'."
+  :group 'denote
+  :package-version '(denote . "1.2.0")
+  :type 'string)
+
+(defcustom denote-excluded-files-regexp nil
+  "Regular expression of files that are excluded from Denote file prompts.
+Files are provided for completion when using commands like `denote-link'
+and `denote-open-or-create'.
+
+The match is performed with `string-match-p' on the full file path."
+  :group 'denote
+  :package-version '(denote . "3.0.0")
+  :type 'string)
+
+(defcustom denote-after-new-note-hook nil
+  "Normal hook that runs after the `denote' command.
+This also covers all convenience functions that call `denote'
+internally, such as `denote-signature' and `denote-type' (check
+the default value of the user option `denote-commands-for-new-notes')."
+  :group 'denote
+  :package-version '(denote . "2.1.0")
+  :link '(info-link "(denote) Standard note creation")
+  :type 'hook)
+
+(defcustom denote-after-rename-file-hook nil
+  "Normal hook called after a succesful Denote rename operation.
+This affects the behaviour of the commands `denote-rename-file',
+`denote-dired-rename-files', `denote-rename-file-using-front-matter',
+`denote-dired-rename-marked-files-with-keywords',
+`denote-dired-rename-marked-files-using-front-matter',
+`denote-keywords-add', `denote-keywords-remove', and any other
+command that builds on top of them."
+  :group 'denote
+  :package-version '(denote . "2.3.0")
+  :link '(info-link "(denote) Renaming files")
+  :type 'hook)
+
+(defcustom denote-region-after-new-note-functions nil
+  "Abnormal hook called after `denote-region'.
+Functions in this hook are called with two arguments,
+representing the beginning and end buffer positions of the region
+that was inserted in the new note.  These are called only if
+`denote-region' is invoked while a region is active.
+
+A common use-case is to call `org-insert-structure-template'
+after a region is inserted.  This case does not actually require
+the aforementioned arguments, in which case the function can
+simply declare them as ignored by prefixing the argument names
+with an underscore.  For example, the following will prompt for a
+structure template as soon as `denote-region' is done:
+
+    (defun my-denote-region-org-structure-template (_beg _end)
+      (when (derived-mode-p \\='org-mode)
+        (activate-mark)
+        (call-interactively \\='org-insert-structure-template)))
+
+    (add-hook \\='denote-region-after-new-note-functions
+              #\\='my-denote-region-org-structure-template)"
+  :group 'denote
+  :package-version '(denote . "2.1.0")
+  :link '(info-link "(denote) Create a note with the region's contents")
+  :type 'hook)
+
+(defvar denote-prompts-with-history-as-completion
+  '(denote-title-prompt denote-signature-prompt denote-files-matching-regexp-prompt denote-query-link-prompt)
+  "Prompts that conditionally perform completion against their history.
+
+These are minibuffer prompts that ordinarily accept a free form string
+input, as opposed to matching against a predefined set.
+
+These prompts can optionally perform completion against their own
+minibuffer history when the user option `denote-history-completion-in-prompts'
+is set to a non-nil value.")
+
+(defcustom denote-history-completion-in-prompts t
+  "Toggle history completion in all `denote-prompts-with-history-as-completion'.
+
+When this user option is set to a non-nil value, use minibuffer history
+entries as completion candidates in `denote-prompts-with-history-as-completion'.
+Those will show previous inputs from their respective history as
+possible values to select, either to (i) re-insert them verbatim or (ii)
+with the intent to edit further (depending on the minibuffer user
+interface, one can select a candidate with TAB without exiting the
+minibuffer, as opposed to what RET normally does by selecting and
+exiting).
+
+When this user option is set to a nil value, all of the
+`denote-prompts-with-history-as-completion' do not use minibuffer
+completion: they just prompt for a string of characters.  Their
+history is still available through all the standard ways of retrieving
+minibuffer history, such as with the command `previous-history-element'.
+
+History completion still allows arbitrary values to be provided as
+input: they do not have to match the available minibuffer completion
+candidates.
+
+Note that some prompts, like `denote-keywords-prompt', always use
+minibuffer completion, due to the specifics of their data.
+
+[ Consider enabling the built-in `savehist-mode' to persist minibuffer
+  histories between sessions.]
+
+Also see `denote-prompts'."
+  :type 'boolean
+  :package-version '(denote . "2.3.0")
+  :group 'denote)
+
+(defcustom denote-commands-for-new-notes
+  '(denote
+    denote-date
+    denote-subdirectory
+    denote-template
+    denote-type
+    denote-signature)
+  "List of commands for `denote-command-prompt' that create a new note.
+These are used by commands such as `denote-open-or-create-with-command'
+and `denote-link-after-creating-with-command'."
+  :group 'denote
+  :package-version '(denote . "2.1.0")
+  :link '(info-link "(denote) Choose which commands to prompt for")
+  :type '(repeat symbol))
+
+(defcustom denote-file-name-slug-functions
+  '((title . denote-sluggify-title)
+    (signature . denote-sluggify-signature)
+    (keyword . denote-sluggify-keyword))
+  "Specify the method Denote uses to format the components of the file name.
+
+The value is an alist where each element is a cons cell of the
+form (COMPONENT . METHOD).
+
+- The COMPONENT is an unquoted symbol among `title', `signature',
+  `keyword' (notice the absence of `s', see below), which
+  refers to the corresponding component of the file name.
+
+- The METHOD is the function to be used to format the given
+  component.  This function should take a string as its parameter
+  and return the string formatted for the file name.  In the case
+  of the `keyword' component, the function receives a SINGLE
+  string representing a single keyword and return it formatted
+  for the file name.  Joining the keywords together is handled by
+  Denote.
+
+Note that the `keyword' function is also applied to the keywords
+of the front matter.
+
+By default, if a function is not specified for a component, we
+use `denote-sluggify-title', `denote-sluggify-keyword' and
+`denote-sluggify-signature'.
+
+Remember that deviating from the default file-naming scheme of Denote
+will make things harder to search in the future, as files can/will have
+permutations that create uncertainty.  The sluggification scheme and
+concomitant restrictions we impose by default are there for a very good
+reason: they are the distillation of years of experience.  Here we give
+you what you wish, but bear in mind it may not be what you need.  You
+have been warned."
+  :group 'denote
+  :package-version '(denote . "2.3.0")
+  :link '(info-link "(denote) User-defined sluggification of file name components")
+  :type '(alist :key (choice (const title)
+                             (const signature)
+                             (const keyword))
+                :value function))
+
+(define-obsolete-variable-alias
+  'denote-link-button-action
+  'denote-open-link-function
+  "4.0.0")
+
+(defcustom denote-open-link-function #'find-file-other-window
+  "Function to find the file of a Denote link.
+
+The default value is `find-file-other-window', with `find-file' because
+another common option.  Users can provide a custom function which
+behaves like the other two.
+
+This is used in all non-Org buffers that have a link created by Denote.
+Org has its own mechanism, which you can learn more about by reading the
+documentation of the `org-open-at-point' command."
+  :group 'denote
+  :type '(choice (function :tag "Other window" find-file-other-window)
+                 (function :tag "Current window" find-file)
+                 (function :tag "Custom function"))
+  :package-version '(denote . "4.0.0"))
+
+(define-obsolete-variable-alias
+  'denote-link-description-function
+  'denote-link-description-format
+  "4.0.0")
+
+(defcustom denote-link-description-format #'denote-link-description-with-signature-and-title
+  "The format of a link description text.
+This determines how `denote-link' and related functions create a link
+description by default.
+
+The value can be either a function or a string.  If it is a function, it
+is called with one argument, the file, and should return a string
+representing the link description.
+
+The default is a function that returns the active region or the title of
+the note (with the signature if present).
+
+If the value is a string, it treats specially the following specifiers:
+
+- The %t is the Denote TITLE in the front matter or the file name.
+- The %T is the Denote TITLE in the file name.
+- The %i is the Denote IDENTIFIER of the file.
+- The %I is the identifier converted to DAYNAME, DAYNUM MONTHNUM YEAR.
+- The %d is the same as %i (DATE mnemonic).
+- The %D is a \"do what I mean\" which behaves the same as %t and if
+  that returns nothing, it falls back to %I, then %i.
+- The %s is the Denote SIGNATURE of the file.
+- The %k is the Denote KEYWORDS of the file.
+- The %% is a literal percent sign.
+
+In addition, the following flags are available for each of the specifiers:
+
+- 0 :: Pad to the width, if given, with zeros instead of spaces.
+- - :: Pad to the width, if given, on the right instead of the left.
+- < :: Truncate to the width and precision, if given, on the left.
+- > :: Truncate to the width and precision, if given, on the right.
+- ^ :: Convert to upper case.
+- _ :: Convert to lower case.
+
+When combined all together, the above are written thus:
+
+    %<flags><width><precision>SPECIFIER-CHARACTER
+
+Any other text in the string it taken as-is.  Users may want, for
+example, to include some text that makes Denote links stand out, such as
+a [D] prefix.
+
+If the region is active, its text is used as the link's description."
+  :type '(choice
+          (string :tag "String with treats format specifiers specially")
+          (function :tag "Custom function like `denote-link-description-with-signature-and-title'"))
+  :package-version '(denote . "4.0.0")
+  :group 'denote)
+
+;;;; Main variables
+
+;; For character classes, evaluate: (info "(elisp) Char Classes")
+
+(defconst denote-id-format "%Y%m%dT%H%M%S"
+  "Format of ID prefix of a note's filename.
+The note's ID is derived from the date and time of its creation.")
+
+(defconst denote-id-regexp "\\([0-9]\\{8\\}\\)\\(T[0-9]\\{6\\}\\)"
+  "Regular expression to match `denote-id-format'.")
+
+(defconst denote-signature-regexp "==\\([^.]*?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
+  "Regular expression to match the SIGNATURE field in a file name.")
+
+(defconst denote-title-regexp "--\\([^.]*?\\)\\(==.*\\|__.*\\|@@.*\\|\\..*\\)*$"
+  "Regular expression to match the TITLE field in a file name.")
+
+(defconst denote-keywords-regexp "__\\([^.]*?\\)\\(==.*\\|--.*\\|__.*\\|@@.*\\|\\..*\\)*$"
+  "Regular expression to match the KEYWORDS field in a file name.")
+
+(make-obsolete-variable
+ 'denote-excluded-punctuation-extra-regexp
+ 'denote-file-name-slug-functions
+ "4.0.0")
+
+;;;; File helper functions
+
+(defun denote--completion-table (category candidates)
+  "Pass appropriate metadata CATEGORY to completion CANDIDATES."
+  (lambda (string pred action)
+    (if (eq action 'metadata)
+        `(metadata (category . ,category))
+      (complete-with-action action candidates string pred))))
+
+(defun denote--completion-table-no-sort (category candidates)
+  "Pass appropriate metadata CATEGORY to completion CANDIDATES.
+Like `denote--completion-table' but also disable sorting."
+  (lambda (string pred action)
+    (if (eq action 'metadata)
+        `(metadata (category . ,category)
+                   (display-sort-function . ,#'identity))
+      (complete-with-action action candidates string pred))))
+
+(defun denote--default-directory-is-silo-p ()
+  "Return path to silo if `default-directory' is a silo."
+  (when-let* ((dir-locals (dir-locals-find-file default-directory))
+              ((alist-get 'denote-directory dir-local-variables-alist)))
+    (cond
+     ((listp dir-locals)
+      (car dir-locals))
+     ((stringp dir-locals)
+      dir-locals))))
+
+(defun denote--make-denote-directory ()
+  "Make the variable `denote-directory' and its parents, if needed."
+  (when (not (file-directory-p denote-directory))
+    (make-directory denote-directory :parents)))
+
+(defun denote-directory ()
+  "Return path of variable `denote-directory' as a proper directory.
+Custom Lisp code can `let' bind the variable `denote-directory'
+to override what this function returns."
+  (if-let* (((or (eq denote-directory 'default-directory) (eq denote-directory 'local)))
+            (silo-dir (denote--default-directory-is-silo-p)))
+      (progn
+        (display-warning
+         'denote
+         "Silo value must be a string; `local' or `default-directory'are obsolete"
+         :error)
+        silo-dir)
+    (let ((denote-directory (file-name-as-directory (expand-file-name denote-directory))))
+      (denote--make-denote-directory)
+      denote-directory)))
+
+;; TODO: Review and fix the features listed in the docstring below before
+;; making this a user option.
+(defvar denote-generate-identifier-automatically t
+  "Make creation and renaming commands automatically create and identifier.
+
+This applies when a note is created or renamed.  The default is to
+always create an identifier automatically.
+
+Valid values are: t, nil, `on-creation', and `on-rename'.
+
+IMPORTANT: Some features may not work with notes that do not have an
+identifier.  For example, backlinks do not contain files without an
+identifier.")
+
+;;;;; Sluggification functions
+
+(defun denote-slug-keep-only-ascii (str)
+  "Remove all non-ASCII characters from STR and replace them with spaces.
+This is useful as a helper function to construct
+`denote-file-name-slug-functions'."
+  (let* ((ascii-range (seq-map
+                       (lambda (character)
+                         (if (and (>= character 33) (<= character 126))
+                             character
+                           32)) ; empty space
+                       str))
+         (characters (seq-filter #'characterp ascii-range)))
+    (mapconcat #'string characters)))
+
+(define-obsolete-function-alias
+  'denote--slug-hyphenate
+  'denote-slug-hyphenate
+  "4.0.0")
+
+(defun denote-slug-hyphenate (str)
+  "Replace spaces and underscores with hyphens in STR.
+Also replace multiple hyphens with a single one and remove any
+leading and trailing hyphen."
+  (replace-regexp-in-string
+   "^-\\|-$" ""
+   (replace-regexp-in-string
+    "-\\{2,\\}" "-"
+    (replace-regexp-in-string "_\\|\s+" "-" str))))
+
+(defun denote-slug-put-equals (str)
+  "Replace spaces and underscores with equals signs in STR.
+Also replace multiple equals signs with a single one and remove
+any leading and trailing signs."
+  (replace-regexp-in-string
+   "^=\\|=$" ""
+   (replace-regexp-in-string
+    "=\\{2,\\}" "="
+    (replace-regexp-in-string "_\\|\s+" "=" str))))
+
+(defun denote--remove-dot-characters (str)
+  "Remove dot characters from STR."
+  (replace-regexp-in-string "\\." "" str))
+
+(defun denote--trim-right-token-characters (str component)
+  "Remove =, -, _ and @ from the end of STR.
+The removal is done only if necessary according to COMPONENT."
+  (if (eq component 'title)
+      (string-trim-right str "[=@_]+")
+    (string-trim-right str "[=@_-]+")))
+
+(defun denote--replace-consecutive-token-characters (str component)
+  "Replace consecutive characters with a single one in STR.
+Hyphens, underscores, equal signs and at signs are replaced with
+a single one in str, if necessary according to COMPONENT."
+  (let ((str (replace-regexp-in-string
+              "_\\{2,\\}" "_"
+              (replace-regexp-in-string
+               "=\\{2,\\}" "="
+               (replace-regexp-in-string
+                "@\\{2,\\}" "@" str)))))
+    ;; -- are allowed in titles when the default sluggification is disabled
+    (if (eq component 'title)
+        str
+      (replace-regexp-in-string
+       "-\\{2,\\}" "-" str))))
+
+(defun denote-sluggify (component str)
+  "Make STR an appropriate slug for file name COMPONENT.
+
+Apply the function specified in `denote-file-name-slug-function' to
+COMPONENT which is one of `title', `signature', `keyword'.  If the
+resulting string still contains consecutive -, _, =, or @, they are
+replaced by a single occurence of the character, if necessary according
+to COMPONENT.  If COMPONENT is `keyword', remove underscores from STR as
+they are used as the keywords separator in file names."
+  (let* ((slug-function (alist-get component denote-file-name-slug-functions))
+         (str-slug (cond ((eq component 'title)
+                          (funcall (or slug-function #'denote-sluggify-title) str))
+                         ((eq component 'keyword)
+                          (replace-regexp-in-string
+                           "_" ""
+                           (funcall (or slug-function #'denote-sluggify-keyword) str)))
+                         ((eq component 'signature)
+                          (funcall (or slug-function #'denote-sluggify-signature) str)))))
+    (denote--trim-right-token-characters
+     (denote--replace-consecutive-token-characters
+      (denote--remove-dot-characters str-slug) component) component)))
+
+(defun denote-sluggify-title (str)
+  "Make STR an appropriate slug for title."
+  (downcase
+   (denote-slug-hyphenate
+    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/=]*" "" str))))
+
+(defun denote-sluggify-signature (str)
+  "Make STR an appropriate slug for signature."
+  (downcase
+   (denote-slug-put-equals
+    (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/-]*" "" str))))
+
+(defun denote-sluggify-keyword (str)
+  "Sluggify STR while joining separate words."
+  (downcase
+   (replace-regexp-in-string "[][{}!@#$%^&*()+'\"?,.\|;:~`‘’“”/_ =-]*" "" str)))
+
+(defun denote-sluggify-keywords (keywords)
+  "Sluggify KEYWORDS, which is a list of strings."
+  (mapcar (lambda (keyword)
+            (denote-sluggify 'keyword keyword))
+          keywords))
+
+;;;;; Common helper functions
+
+(defun denote--file-empty-p (file)
+  "Return non-nil if FILE is empty."
+  (zerop (or (file-attribute-size (file-attributes file)) 0)))
+
+(defun denote-identifier-p (identifier)
+  "Return non-nil if IDENTIFIER string is a Denote identifier."
+  (string-match-p (format "\\`%s\\'" denote-id-regexp) identifier))
+
+(defun denote-file-has-identifier-p (file)
+  "Return non-nil if FILE has a Denote identifier."
+  (denote-retrieve-filename-identifier file))
+
+(defun denote-file-has-supported-extension-p (file)
+  "Return non-nil if FILE has supported extension.
+Also account for the possibility of an added .gpg suffix.  Supported
+extensions are those implied by the variable `denote-file-type'."
+  (seq-some (lambda (e)
+              (string-suffix-p e file))
+            (denote-file-type-extensions-with-encryption)))
+
+(defun denote-file-is-in-denote-directory-p (file)
+  "Return non-nil if FILE is in the variable `denote-directory'."
+  (string-prefix-p (denote-directory) (expand-file-name file)))
+
+(defun denote-filename-is-note-p (filename)
+  "Return non-nil if FILENAME is a valid name for a Denote note.
+For our purposes, its path must be part of the variable
+`denote-directory', it must have a Denote identifier in its name, and
+use one of the extensions implied by the variable `denote-file-type'."
+  (and (denote-file-is-in-denote-directory-p filename)
+       (denote-file-has-identifier-p filename)
+       (denote-file-has-supported-extension-p filename)))
+
+(defun denote-file-is-note-p (file)
+  "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'."
+  (and (file-regular-p file) (denote-filename-is-note-p file)))
+
+(defun denote-file-has-denoted-filename-p (file)
+  "Return non-nil if FILE respects the file-naming scheme of Denote.
+
+This tests the rules of Denote's file-naming scheme.  Sluggification is
+ignored.  It is done by removing all file name components and validating
+what remains."
+  (let* ((initial-filename (file-name-nondirectory file))
+         (filename initial-filename)
+         (title (denote-retrieve-filename-title file))
+         (keywords-string (denote-retrieve-filename-keywords file))
+         (signature (denote-retrieve-filename-signature file))
+         (identifier (denote-retrieve-filename-identifier file)))
+    (when title
+      (setq filename (replace-regexp-in-string (concat "\\(--" (regexp-quote title) "\\).*\\'") "" filename nil nil 1)))
+    (when keywords-string
+      (setq filename (replace-regexp-in-string (concat "\\(__" (regexp-quote keywords-string) "\\).*\\'") "" filename nil nil 1)))
+    (when signature
+      (setq filename (replace-regexp-in-string (concat "\\(==" (regexp-quote signature) "\\).*\\'") "" filename nil nil 1)))
+    (when identifier
+      (if (string-match-p "@@" filename)
+          (setq filename (replace-regexp-in-string (concat "\\(@@" (regexp-quote identifier) "\\).*\\'") "" filename nil nil 1))
+        (setq filename (replace-regexp-in-string (concat "\\(" (regexp-quote identifier) "\\).*\\'") "" filename nil nil 1))))
+    ;; What remains should be the empty string or the file extension.
+    (and (not (string-prefix-p "." initial-filename))
+         (or (string-empty-p filename)
+             (string-prefix-p "." filename)))))
+
+(defun denote-file-has-signature-p (file)
+  "Return non-nil if FILE has a Denote identifier."
+  (denote-retrieve-filename-signature file))
+
+(defun denote-file-is-writable-and-supported-p (file)
+  "Return non-nil if FILE is writable and has supported extension."
+  ;; We do not want to test that the file is regular (exists) because we want
+  ;; this function to return t on files that are still unsaved.
+  (and (file-writable-p file)
+       (denote-file-has-supported-extension-p file)))
+
+(defun denote-get-file-name-relative-to-denote-directory (file)
+  "Return name of FILE relative to the variable `denote-directory'.
+FILE must be an absolute path."
+  (when-let* ((dir (denote-directory))
+              ((file-name-absolute-p file))
+              (file-name (expand-file-name file))
+              ((string-prefix-p dir file-name)))
+    (substring-no-properties file-name (length dir))))
+
+(defun denote-extract-id-from-string (string)
+  "Return existing Denote identifier in STRING, else nil."
+  (when (string-match denote-id-regexp string)
+    (match-string-no-properties 0 string)))
+
+(defun denote--exclude-directory-regexp-p (file)
+  "Return non-nil if FILE matches `denote-excluded-directories-regexp'."
+  (and (stringp denote-excluded-directories-regexp)
+       (string-match-p denote-excluded-directories-regexp file)))
+
+(defun denote--directory-files-recursively-predicate (file)
+  "Predicate used by `directory-files-recursively' on FILE.
+
+Return t if FILE is valid, else return nil."
+  (let ((rel (denote-get-file-name-relative-to-denote-directory file)))
+    (cond
+     ((string-match-p "\\`\\." rel) nil)
+     ((string-match-p "/\\." rel) nil)
+     ((denote--exclude-directory-regexp-p rel) nil)
+     ((file-readable-p file)))))
+
+(defun denote--directory-all-files-recursively ()
+  "Return list of all files in variable `denote-directory'.
+Avoids traversing dotfiles (unconditionally) and whatever matches
+`denote-excluded-directories-regexp'."
+  (directory-files-recursively
+   (denote-directory)
+   directory-files-no-dot-files-regexp
+   :include-directories
+   #'denote--directory-files-recursively-predicate
+   :follow-symlinks))
+
+(defun denote--file-excluded-p (file)
+  "Return non-file if FILE matches `denote-excluded-files-regexp'."
+  (and denote-excluded-files-regexp
+       (string-match-p denote-excluded-files-regexp file)))
+
+(defun denote--directory-get-files ()
+  "Return list with full path of valid files in variable `denote-directory'.
+Consider files that satisfy `denote-file-has-identifier-p' and
+are not backups."
+  (mapcar
+   #'expand-file-name
+   (seq-filter
+    (lambda (file)
+      (and (file-regular-p file)
+           (denote-file-has-identifier-p file)
+           (not (denote--file-excluded-p file))
+           (not (backup-file-name-p file))))
+    (denote--directory-all-files-recursively))))
+
+(defun denote-directory-files (&optional files-matching-regexp omit-current text-only exclude-regexp)
+  "Return list of absolute file paths in variable `denote-directory'.
+Files that match `denote-excluded-files-regexp' are excluded from the
+list.
+
+Files only need to have an identifier.  The return value may thus
+include file types that are not implied by the variable
+`denote-file-type'.
+
+With optional FILES-MATCHING-REGEXP, restrict files to those
+matching the given regular expression.
+
+With optional OMIT-CURRENT as a non-nil value, do not include the
+current Denote file in the returned list.
+
+With optional TEXT-ONLY as a non-nil value, limit the results to
+text files that satisfy `denote-file-has-supported-extension-p'.
+
+With optional EXCLUDE-REGEXP exclude the files that match the given
+regular expression.  This is done after FILES-MATCHING-REGEXP and
+OMIT-CURRENT have been applied."
+  (let ((files (denote--directory-get-files)))
+    (when (and omit-current buffer-file-name (denote-file-has-identifier-p buffer-file-name))
+      (setq files (delete buffer-file-name files)))
+    (when files-matching-regexp
+      (setq files (seq-filter
+                   (lambda (f)
+                     (string-match-p files-matching-regexp (denote-get-file-name-relative-to-denote-directory f)))
+                   files)))
+    (when text-only
+      (setq files (seq-filter #'denote-file-has-supported-extension-p files)))
+    (when exclude-regexp
+      (setq files (seq-remove
+                   (lambda (file)
+                     (string-match-p exclude-regexp file))
+                   files)))
+    files))
+
+(defun denote-directory-subdirectories ()
+  "Return list of subdirectories in variable `denote-directory'.
+Omit dotfiles (such as .git) unconditionally.  Also exclude
+whatever matches `denote-excluded-directories-regexp'."
+  (seq-remove
+   (lambda (filename)
+     (let ((rel (denote-get-file-name-relative-to-denote-directory filename)))
+       (or (not (file-directory-p filename))
+           (string-match-p "\\`\\." rel)
+           (string-match-p "/\\." rel)
+           (denote--exclude-directory-regexp-p rel))))
+   (denote--directory-all-files-recursively)))
+
+;; TODO 2023-01-24: Perhaps there is a good reason to make this a user
+;; option, but I am keeping it as a generic variable for now.
+(defvar denote-encryption-file-extensions '(".gpg" ".age")
+  "List of strings specifying file extensions for encryption.")
+
+(defun denote-file-type-extensions-with-encryption ()
+  "Derive `denote-file-type-extensions' plus `denote-encryption-file-extensions'."
+  (let ((file-extensions (denote-file-type-extensions))
+        all)
+    (dolist (ext file-extensions)
+      (dolist (enc denote-encryption-file-extensions)
+        (push (concat ext enc) all)))
+    (append file-extensions all)))
+
+(defun denote-get-file-extension (file)
+  "Return extension of FILE with dot included.
+Account for `denote-encryption-file-extensions'.  In other words,
+return something like .org.gpg if it is part of the file, else
+return .org."
+  (let ((outer-extension (file-name-extension file :period)))
+    (if-let* (((member outer-extension denote-encryption-file-extensions))
+              (file (file-name-sans-extension file))
+              (inner-extension (file-name-extension file :period)))
+        (concat inner-extension outer-extension)
+      outer-extension)))
+
+(defun denote-get-file-extension-sans-encryption (file)
+  "Return extension of FILE with dot included and without the encryption part.
+Build on top of `denote-get-file-extension' though always return
+something like .org even if the actual file extension is
+.org.gpg."
+  (let ((extension (denote-get-file-extension file)))
+    (if (string-match (regexp-opt denote-encryption-file-extensions) extension)
+        (substring extension 0 (match-beginning 0))
+      extension)))
+
+(defun denote-get-path-by-id (id)
+  "Return absolute path of ID string in `denote-directory-files'."
+  (let ((files
+         (seq-filter
+          (lambda (file)
+            (string= id (denote-retrieve-filename-identifier file)))
+          (denote-directory-files))))
+    (if (length< files 2)
+        (car files)
+      (seq-find
+       (lambda (file)
+         (let ((file-extension (denote-get-file-extension-sans-encryption file)))
+           (and (denote-file-has-supported-extension-p file)
+                (or (string= (denote--file-extension denote-file-type)
+                             file-extension)
+                    (string= ".org" file-extension)
+                    (member file-extension (denote-file-type-extensions))))))
+       files))))
+
+(defun denote-get-relative-path-by-id (id &optional directory)
+  "Return relative path of ID string in `denote-directory-files'.
+The path is relative to DIRECTORY (default: ‘default-directory’)."
+  (when-let* ((path (denote-get-path-by-id id)))
+    (file-relative-name path directory)))
+
+(defvar denote-file-history nil
+  "Minibuffer history of `denote-file-prompt'.")
+
+(defalias 'denote--file-history 'denote-file-history
+  "Compatibility alias for `denote-file-history'.")
+
+(defvar denote-file-prompt-latest-input nil
+  "Latest input passed to `denote-file-prompt'.
+This is used for retrieving a value that is used to set a new default at
+the title prompt of `denote-open-or-create' and related commands.")
+
+(defvar denote-file-prompt-use-files-matching-regexp nil
+  "The `denote-file-prompt' FILES-MATCHING-REGEXP value.
+Only ever `let' bind this, otherwise the restriction will always be
+there.")
+
+(defun denote-file-prompt (&optional files-matching-regexp prompt-text no-require-match)
+  "Prompt for file in variable `denote-directory'.
+Files that match `denote-excluded-files-regexp' are excluded from the
+list.
+
+With optional FILES-MATCHING-REGEXP, filter the candidates per
+the given regular expression.
+
+With optional PROMPT-TEXT, use it instead of the default call to
+select a file.
+
+With optional NO-REQUIRE-MATCH, accept the given input as-is.
+
+Return the absolute path to the matching file."
+  (let* ((default-directory (denote-directory))
+         (relative-files (mapcar
+                          #'denote-get-file-name-relative-to-denote-directory
+                          (denote-directory-files
+                           (or denote-file-prompt-use-files-matching-regexp files-matching-regexp)
+                           :omit-current)))
+         (prompt (format "%s in %s: "
+                         (or prompt-text "Select FILE")
+                         (propertize (denote-directory) 'face 'denote-faces-prompt-current-name)))
+         (input (completing-read
+                 prompt
+                 (denote--completion-table 'file relative-files)
+                 nil (unless no-require-match :require-match)
+                 nil 'denote-file-history))
+         (absolute-file (concat (denote-directory) input)))
+    ;; NOTE: This block is executed when no-require-match is t. It is useful
+    ;; for commands such as `denote-open-or-create` or similar.
+    (unless (file-exists-p absolute-file)
+      (setq denote-file-prompt-latest-input input)
+      (setq denote-file-history (delete input denote-file-history)))
+    ;; NOTE: We must always return an absolute path, even if it does not
+    ;; exist, because callers expect one.  They handle a non-existent file
+    ;; appropriately.
+    absolute-file))
+
+;;;; The sort mechanism
+
+(defgroup denote-sort nil
+  "Sort Denote files based on a file name component."
+  :group 'denote
+  :link '(info-link "(denote) Top")
+  :link '(url-link :tag "Homepage" "https://protesilaos.com/emacs/denote"))
+
+(defconst denote-sort-comparison-fallback-function #'string-collate-lessp
+  "String comparison function used by `denote-sort-files' subroutines.")
+
+(defconst denote-sort-components '(title keywords signature identifier)
+  "List of sorting keys applicable for `denote-sort-files' and related.")
+
+(defcustom denote-sort-identifier-comparison-function denote-sort-comparison-fallback-function
+  "Function to sort the DATE/IDENTIFIER component in file names.
+The function accepts two arguments and must return a non-nil value if
+the first argument is smaller than the second one."
+  :type 'function
+  :package-version '(denote . "4.0.0")
+  :group 'denote-sort)
+
+(defcustom denote-sort-title-comparison-function denote-sort-comparison-fallback-function
+  "Function to sort the TITLE component in file names.
+The function accepts two arguments and must return a non-nil value if
+the first argument is smaller than the second one."
+  :type 'function
+  :package-version '(denote . "3.1.0")
+  :group 'denote-sort)
+
+(defcustom denote-sort-keywords-comparison-function denote-sort-comparison-fallback-function
+  "Function to sort the KEYWORDS component in file names.
+The function accepts two arguments and must return a non-nil value if
+the first argument is smaller than the second one."
+  :type 'function
+  :package-version '(denote . "3.1.0")
+  :group 'denote-sort)
+
+(defcustom denote-sort-signature-comparison-function denote-sort-comparison-fallback-function
+  "Function to sort the SIGNATURE component in file names.
+The function accepts two arguments and must return a non-nil value if
+the first argument is smaller than the second one."
+  :type 'function
+  :package-version '(denote . "3.1.0")
+  :group 'denote-sort)
+
+(defcustom denote-sort-dired-extra-prompts '(sort-by-component reverse-sort)
+  "Determine what `denote-sort-dired' prompts for beside a search query.
+This concerns the additional prompts issued by `denote-sort-dired' about
+whether to sort by a given file name component and to then reverse the
+sort.
+
+The value is a list of symbols, which can include the symbols
+`sort-by-component', `reverse-sort', and `exclude-regexp'.  The order is
+significant, with the leftmost symbol coming first.
+
+These symbols correspond to the following:
+
+- A choice to select the file name component to sort by.
+- A yes or no prompt on whether to reverse the sorting.
+- A string (or regular expression) of files to be excluded from the results.
+
+If the value is nil, skip all prompts.  In this scenario, the sorting is
+done according to `denote-sort-dired-default-sort-component' and
+`denote-sort-dired-default-reverse-sort'."
+  :type '(radio (const :tag "Do not prompt for anything" nil)
+                (set :tag "Available prompts" :greedy t
+                     (const :tag "Sort by file name component" sort-by-component)
+                     (const :tag "Reverse the sort" reverse-sort)
+                     (const :tag "Exclude files matching regexp" exclude-regexp)))
+  :package-version '(denote . "4.0.0")
+  :group 'denote-sort)
+
+(defcustom denote-sort-dired-default-sort-component 'identifier
+  "Set the default file name component to sort by.
+This is used only if `denote-sort-dired-extra-prompts' omits the
+minibuffer prompt for which file name component to sort by."
+  :type '(radio
+          (const :tag "Sort by identifier (default)" identifier)
+          (const :tag "Sort by title" title)
+          (const :tag "Sort by keywords" keywords)
+          (const :tag "Sort by signature" signature))
+  :package-version '(denote . "3.1.0")
+  :group 'denote-sort)
+
+(defcustom denote-sort-dired-default-reverse-sort nil
+  "If non-nil, reverse the sorting order by default.
+This is used only if `denote-sort-dired-extra-prompts' omits the
+minibuffer prompt that asks for a reverse sort or not."
+  :type 'boolean
+  :package-version '(denote . "3.1.0")
+  :group 'denote-sort)
+
+;; NOTE 2023-12-04: We can have compound sorting algorithms such as
+;; title+signature, but I want to keep this simple for the time being.
+;; Let us first hear from users to understand if there is a real need
+;; for such a feature.
+(defmacro denote-sort--define-lessp (component)
+  "Define function to sort by COMPONENT."
+  (let ((retrieve-fn (intern (format "denote-retrieve-filename-%s" component)))
+        (comparison-fn (intern (format "denote-sort-%s-comparison-function" component))))
+    `(defun ,(intern (format "denote-sort-%s-lessp" component)) (file1 file2)
+       ,(format
+         "Return smallest among FILE1, FILE2 based on their %s.
+The `%s' performs the comparison."
+         component comparison-fn)
+       (let* ((one (,retrieve-fn file1))
+              (two (,retrieve-fn file2))
+              (one-empty-p (or (null one) (string-empty-p one)))
+              (two-empty-p (or (null two) (string-empty-p two))))
+         (cond
+          (one-empty-p nil)
+          ((and (not one-empty-p) two-empty-p) one)
+          (t (funcall (or ,comparison-fn denote-sort-comparison-fallback-function) one two)))))))
+
+;; TODO 2023-12-04: Subject to the above NOTE, we can also sort by
+;; directory and by file length.
+(denote-sort--define-lessp identifier)
+(denote-sort--define-lessp title)
+(denote-sort--define-lessp keywords)
+(denote-sort--define-lessp signature)
+
+;;;###autoload
+(defun denote-sort-files (files component &optional reverse)
+  "Returned sorted list of Denote FILES.
+
+With COMPONENT as a symbol among `denote-sort-components',
+sort files based on the corresponding file name component.
+
+With COMPONENT as the symbol of a function, use it to perform the
+sorting.  In this case, the function is called with two arguments, as
+described by `sort'.
+
+With COMPONENT as a nil value keep the original date-based
+sorting which relies on the identifier of each file name.
+
+With optional REVERSE as a non-nil value, reverse the sort order."
+  (let* ((files-to-sort (copy-sequence files))
+         (sort-fn (pcase component
+                    ((pred functionp) component)
+                    ('identifier #'denote-sort-identifier-lessp)
+                    ('title #'denote-sort-title-lessp)
+                    ('keywords #'denote-sort-keywords-lessp)
+                    ('signature #'denote-sort-signature-lessp)))
+         (sorted-files (if sort-fn (sort files sort-fn) files-to-sort)))
+    (if reverse
+        (reverse sorted-files)
+      sorted-files)))
+
+(defun denote-sort-get-directory-files (files-matching-regexp sort-by-component &optional reverse omit-current exclude-regexp)
+  "Return sorted list of files in variable `denote-directory'.
+
+With FILES-MATCHING-REGEXP as a string limit files to those
+matching the given regular expression.
+
+With SORT-BY-COMPONENT as a symbol among `denote-sort-components',
+pass it to `denote-sort-files' to sort by the corresponding file
+name component.
+
+With optional REVERSE as a non-nil value, reverse the sort order.
+
+With optional OMIT-CURRENT, do not include the current file in
+the list.
+
+With optional EXCLUDE-REGEXP exclude the files that match the given
+regular expression.  This is done after FILES-MATCHING-REGEXP and
+OMIT-CURRENT have been applied."
+  (denote-sort-files
+   (denote-directory-files files-matching-regexp omit-current nil exclude-regexp)
+   sort-by-component
+   reverse))
+
+(defun denote-sort-get-links (files-matching-regexp sort-by-component current-file-type id-only &optional reverse exclude-regexp)
+  "Return sorted typographic list of links for FILES-MATCHING-REGEXP.
+
+With FILES-MATCHING-REGEXP as a string, match files stored in the
+variable `denote-directory'.
+
+With SORT-BY-COMPONENT as a symbol among `denote-sort-components',
+sort FILES-MATCHING-REGEXP by the given Denote file name
+component.  If SORT-BY-COMPONENT is nil or an unknown non-nil
+value, default to the identifier-based sorting.
+
+With CURRENT-FILE-TYPE as a symbol among those specified in
+the variable `denote-file-type' (or the `car' of each element in
+`denote-file-types'), format the link accordingly.  With a nil or
+unknown non-nil value, default to the Org notation.
+
+With ID-ONLY as a non-nil value, produce links that consist only
+of the identifier, thus deviating from CURRENT-FILE-TYPE.
+
+With optional REVERSE as a non-nil value, reverse the sort order.
+
+With optional EXCLUDE-REGEXP exclude the files that match the given
+regular expression.  This is done after FILES-MATCHING-REGEXP and
+OMIT-CURRENT have been applied."
+  (denote-link--prepare-links
+   (denote-sort-get-directory-files files-matching-regexp sort-by-component reverse exclude-regexp)
+   current-file-type
+   id-only))
+
+(defvar denote-sort-component-history nil
+  "Minibuffer history of `denote-sort-component-prompt'.")
+
+(defalias 'denote-sort--component-hist 'denote-sort-component-history
+  "Compatibility alias for `denote-sort-component-history'.")
+
+(defun denote-sort-component-prompt ()
+  "Prompt for sorting key among `denote-sort-components'."
+  (let ((default (car denote-sort-component-history)))
+    (intern
+     (completing-read
+      (format-prompt "Sort by file name component" default)
+      denote-sort-components nil :require-match
+      nil 'denote-sort-component-history default))))
+
+(defvar denote-sort-exclude-files-history nil
+  "Minibuffer history for `denote-sort-exclude-files-prompt'.")
+
+(defun denote-sort-exclude-files-prompt ()
+  "Prompt for regular expression of files to exclude."
+  ;; TODO 2024-12-03: Maybe use `read-regexp'?  We do not use it
+  ;; elsewhere, so maybe this is fine.
+  (let ((default (car denote-sort-exclude-files-history)))
+    (read-string
+     (format-prompt "Exclude files matching REGEXP" default)
+     default 'denote-sort-exclude-files-history)))
+
+(defvar-local denote-sort--dired-buffer nil
+  "Buffer object of current `denote-sort-dired'.")
+
+(defun denote-sort-dired--prompts ()
+  "Return list of prompts per `denote-sort-dired-extra-prompts'."
+  (let (sort-by-component reverse-sort exclude-rx)
+    (dolist (prompt denote-sort-dired-extra-prompts)
+      (pcase prompt
+        ('sort-by-component (setq sort-by-component (denote-sort-component-prompt)))
+        ('reverse-sort (setq reverse-sort (y-or-n-p "Reverse sort? ")))
+        ('exclude-regexp (setq exclude-rx (denote-sort-exclude-files-prompt)))))
+    (list sort-by-component reverse-sort exclude-rx)))
+
+;;;###autoload
+(defun denote-sort-dired (files-matching-regexp sort-by-component reverse exclude-regexp)
+  "Produce Dired buffer with sorted files from variable `denote-directory'.
+When called interactively, prompt for FILES-MATCHING-REGEXP and,
+depending on the value of the user option `denote-sort-dired-extra-prompts',
+also prompt for SORT-BY-COMPONENT, REVERSE, and EXCLUDE-REGEXP.
+
+1. FILES-MATCHING-REGEXP limits the list of Denote files to
+   those matching the provided regular expression.
+
+2. SORT-BY-COMPONENT sorts the files by their file name component (one
+   among `denote-sort-components').  If it is nil, sorting is performed
+   according to the user option `denote-sort-dired-default-sort-component',
+   falling back to the identifier.
+
+3. REVERSE is a boolean to reverse the order when it is a non-nil value.
+   If `denote-sort-dired-extra-prompts' is configured to skip this
+   prompt, then the sorting is done according to the user option
+   `denote-sort-dired-default-reverse-sort', falling back to
+   nil (i.e. no reverse sort).
+
+4. EXCLUDE-REGEXP excludes the files that match the given regular
+   expression.  This is done after FILES-MATCHING-REGEXP and
+   OMIT-CURRENT have been applied.
+
+When called from Lisp, the arguments are a string, a symbol among
+`denote-sort-components', a non-nil value, and a string, respectively."
+  (interactive
+   (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts)))
+  (let ((component (or sort-by-component
+                       denote-sort-dired-default-sort-component
+                       'identifier))
+        (reverse-sort (or reverse
+                          denote-sort-dired-default-reverse-sort
+                          nil))
+        (exclude-rx (or exclude-regexp nil)))
+    (if-let* ((default-directory (denote-directory))
+              (files (denote-sort-get-directory-files files-matching-regexp component reverse-sort nil exclude-rx))
+              ;; NOTE 2023-12-04: Passing the FILES-MATCHING-REGEXP as
+              ;; buffer-name produces an error if the regexp contains a
+              ;; wildcard for a directory. I can reproduce this in emacs
+              ;; -Q and am not sure if it is a bug. Anyway, I will report
+              ;; it upstream, but even if it is fixed we cannot use it
+              ;; for now (whatever fix will be available for Emacs 30+).
+              (denote-sort-dired-buffer-name (format "Denote sort `%s' by `%s'" files-matching-regexp component))
+              (buffer-name (format "Denote sort by `%s' at %s" component (format-time-string "%T"))))
+        (let ((dired-buffer (dired (cons buffer-name (mapcar #'file-relative-name files)))))
+          (setq denote-sort--dired-buffer dired-buffer)
+          (with-current-buffer dired-buffer
+            (setq-local revert-buffer-function
+                        (lambda (&rest _)
+                          ;; FIXME 2025-01-04: Killing the buffer has
+                          ;; the unintended side effect of affecting the
+                          ;; window configuration when we call
+                          ;; `denote-update-dired-buffers'.
+                          (kill-buffer dired-buffer)
+                          (denote-sort-dired files-matching-regexp component reverse-sort exclude-rx))))
+          buffer-name)
+      (message "No matching files for: %s" files-matching-regexp))))
+
+(defalias 'denote-dired 'denote-sort-dired
+  "Alias for `denote-sort-dired' command.")
+
+;;;; Keywords
+
+(defun denote-extract-keywords-from-path (path)
+  "Extract keywords from PATH and return them as a list of strings.
+PATH must be a Denote-style file name where keywords are prefixed
+with an underscore.
+
+If PATH has no such keywords, return nil.
+
+Also see `denote-retrieve-filename-keywords'."
+  (when-let* ((kws (denote-retrieve-filename-keywords path)))
+    (split-string kws "_" :omit-nulls)))
+
+(defalias 'denote-retrieve-filename-keywords-as-list 'denote-extract-keywords-from-path
+  "Alias for the function `denote-extract-keywords-from-path'")
+
+(define-obsolete-function-alias
+  'denote--inferred-keywords
+  'denote-infer-keywords-from-files
+  "4.0.0")
+
+(defun denote-infer-keywords-from-files (&optional files-matching-regexp)
+  "Return list of keywords in `denote-directory-files'.
+With optional FILES-MATCHING-REGEXP, only extract keywords from the
+matching files.  Otherwise, do it for all files.
+
+Keep any duplicates.  Users who do not want duplicates should refer to
+the functions `denote-keywords'."
+  (when-let* ((files (denote-directory-files files-matching-regexp))
+              (keywords (mapcan #'denote-extract-keywords-from-path files)))
+    (if-let* ((regexp denote-excluded-keywords-regexp))
+        (seq-remove
+         (lambda (k)
+           (string-match-p regexp k))
+         keywords)
+      keywords)))
+
+(defun denote-keywords (&optional files-matching-regexp)
+  "Return appropriate list of keyword candidates.
+If `denote-infer-keywords' is non-nil, infer keywords from existing
+notes and combine them into a list with `denote-known-keywords'.  Else
+use only the latter.
+
+In the case of keyword inferrence, use optional FILES-MATCHING-REGEXP,
+to extract keywords only from the matching files.  Otherwise, do it for
+all files.
+
+Filter inferred keywords with the user option `denote-excluded-keywords-regexp'."
+  (delete-dups
+   (if denote-infer-keywords
+       (append (denote-infer-keywords-from-files files-matching-regexp) denote-known-keywords)
+     denote-known-keywords)))
+
+(defvar denote-keyword-history nil
+  "Minibuffer history of inputted keywords.")
+
+(defalias 'denote--keyword-history 'denote-keyword-history
+  "Compatibility alias for `denote-keyword-history'.")
+
+(make-obsolete
+ 'denote-convert-file-name-keywords-to-crm
+ nil
+ "3.0.0: Keywords are always returned as a list")
+
+(defun denote--keywords-crm (keywords &optional prompt initial)
+  "Use `completing-read-multiple' for KEYWORDS.
+With optional PROMPT, use it instead of a generic text for file
+keywords.  With optional INITIAL, add it to the minibuffer as
+initial input."
+  (delete-dups
+   (completing-read-multiple
+    (format-prompt (or prompt "New file KEYWORDS") nil)
+    keywords nil nil initial 'denote-keyword-history)))
+
+(defun denote-keywords-prompt (&optional prompt-text initial-keywords infer-from-files-matching-regexp)
+  "Prompt for one or more keywords.
+Read entries as separate when they are demarcated by the
+`crm-separator', which typically is a comma.
+
+With optional PROMPT-TEXT, use it to prompt the user for keywords.  Else
+use a generic prompt.  With optional INITIAL-KEYWORDS use them as the
+initial minibuffer text.
+
+With optional INFER-FROM-FILES-MATCHING-REGEXP, only infer keywords from
+files that match the given regular expression, per the function
+`denote-keywords'.
+
+Return an empty list if the minibuffer input is empty."
+  (denote--keywords-crm (denote-keywords infer-from-files-matching-regexp) prompt-text initial-keywords))
+
+(defun denote-keywords-sort (keywords)
+  "Sort KEYWORDS if `denote-sort-keywords' is non-nil.
+KEYWORDS is a list of strings, per `denote-keywords-prompt'."
+  (if denote-sort-keywords
+      (sort (copy-sequence keywords) #'string-collate-lessp)
+    keywords))
+
+(defun denote-keywords-combine (keywords)
+  "Combine KEYWORDS list of strings into a single string.
+Keywords are separated by the underscore character, per the
+Denote file-naming scheme."
+  (string-join keywords "_"))
+
+(defun denote--keywords-add-to-history (keywords)
+  "Append KEYWORDS to `denote-keyword-history'."
+  (mapc
+   (lambda (kw)
+     (add-to-history 'denote-keyword-history kw))
+   (delete-dups keywords)))
+
+;;;; File types
+
+(defvar denote-org-front-matter
+  "#+title:      %s
+#+date:       %s
+#+filetags:   %s
+#+identifier: %s
+#+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)
+Change the front matter format'.")
+
+(defvar denote-yaml-front-matter
+  "---
+title:      %s
+date:       %s
+tags:       %s
+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)
+Change the front matter format'.")
+
+(defvar denote-toml-front-matter
+  "+++
+title      = %s
+date       = %s
+tags       = %s
+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)
+Change the front matter format'.")
+
+(defvar denote-text-front-matter
+  "title:      %s
+date:       %s
+tags:       %s
+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)
+Change the front matter format'.")
+
+(defun denote-format-string-for-md-front-matter (s)
+  "Surround string S with quotes.
+
+This can be used in `denote-file-types' to format front mattter."
+  (format "%S" s))
+
+(defun denote-trim-whitespace (s)
+  "Trim whitespace around string S.
+This can be used in `denote-file-types' to format front mattter."
+  (string-trim s))
+
+(defun denote--trim-quotes (s)
+  "Trim quotes around string S."
+  (let ((trims "[\"']+"))
+    (string-trim s trims trims)))
+
+(defun denote-trim-whitespace-then-quotes (s)
+  "Trim whitespace then quotes around string S.
+This can be used in `denote-file-types' to format front mattter."
+  (denote--trim-quotes (denote-trim-whitespace s)))
+
+(defun denote-format-string-for-org-front-matter (s)
+  "Return string S as-is for Org or plain text front matter."
+  s)
+
+(defun denote-format-keywords-for-md-front-matter (keywords)
+  "Format front matter KEYWORDS for markdown file type.
+KEYWORDS is a list of strings.  Consult the `denote-file-types'
+for how this is used."
+  (format "[%s]" (mapconcat (lambda (k) (format "%S" k)) keywords ", ")))
+
+(defun denote-format-keywords-for-text-front-matter (keywords)
+  "Format front matter KEYWORDS for text file type.
+KEYWORDS is a list of strings.  Consult the `denote-file-types'
+for how this is used."
+  (string-join keywords "  "))
+
+(defun denote-format-keywords-for-org-front-matter (keywords)
+  "Format front matter KEYWORDS for org file type.
+KEYWORDS is a list of strings.  Consult the `denote-file-types'
+for how this is used."
+  (if keywords
+      (format ":%s:" (string-join keywords ":"))
+    ""))
+
+(defun denote-extract-keywords-from-front-matter (keywords-string)
+  "Extract keywords list from front matter KEYWORDS-STRING.
+Split KEYWORDS-STRING into a list of strings.
+
+Consult the `denote-file-types' for how this is used."
+  (split-string keywords-string "[:,\s]+" t "[][ \"']+"))
+
+(defun denote-extract-date-from-front-matter (date-string)
+  "Extract date object from front matter DATE-STRING.
+
+Consult the `denote-file-types' for how this is used."
+  (let ((date-string (denote-trim-whitespace date-string)))
+    (if (string-empty-p date-string)
+        nil
+      (date-to-time date-string))))
+
+(defvar denote-file-types
+  '((org
+     :extension ".org"
+     :front-matter denote-org-front-matter
+     :title-key-regexp "^#\\+title\\s-*:"
+     :title-value-function denote-format-string-for-org-front-matter
+     :title-value-reverse-function denote-trim-whitespace
+     :keywords-key-regexp "^#\\+filetags\\s-*:"
+     :keywords-value-function denote-format-keywords-for-org-front-matter
+     :keywords-value-reverse-function denote-extract-keywords-from-front-matter
+     :signature-key-regexp "^#\\+signature\\s-*:"
+     :signature-value-function denote-format-string-for-org-front-matter
+     :signature-value-reverse-function denote-trim-whitespace
+     :identifier-key-regexp "^#\\+identifier\\s-*:"
+     :identifier-value-function denote-format-string-for-org-front-matter
+     :identifier-value-reverse-function denote-trim-whitespace
+     :date-key-regexp "^#\\+date\\s-*:"
+     :date-value-function denote-date-org-timestamp
+     :date-value-reverse-function denote-extract-date-from-front-matter
+     :link denote-org-link-format
+     :link-in-context-regexp denote-org-link-in-context-regexp)
+    (markdown-yaml
+     :extension ".md"
+     :front-matter denote-yaml-front-matter
+     :title-key-regexp "^title\\s-*:"
+     :title-value-function denote-format-string-for-md-front-matter
+     :title-value-reverse-function denote-trim-whitespace-then-quotes
+     :keywords-key-regexp "^tags\\s-*:"
+     :keywords-value-function denote-format-keywords-for-md-front-matter
+     :keywords-value-reverse-function denote-extract-keywords-from-front-matter
+     :signature-key-regexp "^signature\\s-*:"
+     :signature-value-function denote-format-string-for-md-front-matter
+     :signature-value-reverse-function denote-trim-whitespace-then-quotes
+     :identifier-key-regexp "^identifier\\s-*:"
+     :identifier-value-function denote-format-string-for-md-front-matter
+     :identifier-value-reverse-function denote-trim-whitespace-then-quotes
+     :date-key-regexp "^date\\s-*:"
+     :date-value-function denote-date-rfc3339
+     :date-value-reverse-function denote-extract-date-from-front-matter
+     :link denote-md-link-format
+     :link-in-context-regexp denote-md-link-in-context-regexp)
+    (markdown-toml
+     :extension ".md"
+     :front-matter denote-toml-front-matter
+     :title-key-regexp "^title\\s-*="
+     :title-value-function denote-format-string-for-md-front-matter
+     :title-value-reverse-function denote-trim-whitespace-then-quotes
+     :keywords-key-regexp "^tags\\s-*="
+     :keywords-value-function denote-format-keywords-for-md-front-matter
+     :keywords-value-reverse-function denote-extract-keywords-from-front-matter
+     :signature-key-regexp "^signature\\s-*="
+     :signature-value-function denote-format-string-for-md-front-matter
+     :signature-value-reverse-function denote-trim-whitespace-then-quotes
+     :identifier-key-regexp "^identifier\\s-*="
+     :identifier-value-function denote-format-string-for-md-front-matter
+     :identifier-value-reverse-function denote-trim-whitespace-then-quotes
+     :date-key-regexp "^date\\s-*="
+     :date-value-function denote-date-rfc3339
+     :date-value-reverse-function denote-extract-date-from-front-matter
+     :link denote-md-link-format
+     :link-in-context-regexp denote-md-link-in-context-regexp)
+    (text
+     :extension ".txt"
+     :front-matter denote-text-front-matter
+     :title-key-regexp "^title\\s-*:"
+     :title-value-function denote-format-string-for-org-front-matter
+     :title-value-reverse-function denote-trim-whitespace
+     :keywords-key-regexp "^tags\\s-*:"
+     :keywords-value-function denote-format-keywords-for-text-front-matter
+     :keywords-value-reverse-function denote-extract-keywords-from-front-matter
+     :signature-key-regexp "^signature\\s-*:"
+     :signature-value-function denote-format-string-for-org-front-matter
+     :signature-value-reverse-function denote-trim-whitespace
+     :identifier-key-regexp "^identifier\\s-*:"
+     :identifier-value-function denote-format-string-for-org-front-matter
+     :identifier-value-reverse-function denote-trim-whitespace
+     :date-key-regexp "^date\\s-*:"
+     :date-value-function denote-date-iso-8601
+     :date-value-reverse-function denote-extract-date-from-front-matter
+     :link denote-org-link-format
+     :link-in-context-regexp denote-org-link-in-context-regexp))
+  "Alist of variable `denote-file-type' and their format properties.
+
+Each element is of the form (SYMBOL PROPERTY-LIST).  SYMBOL is one of
+those specified in the user option `denote-file-type' or an arbitrary
+symbol that defines a new file type.
+
+PROPERTY-LIST is a plist that consists of the following elements:
+
+- `:extension' is a string with the file extension including the
+  period.
+
+- `:date-function' is a function that can format a date.  See the
+  functions `denote-date-iso-8601', `denote-date-rfc3339', and
+  `denote-date-org-timestamp'.
+
+- `:front-matter' is either a string passed to `format' or a
+  variable holding such a string.  The `format' function accepts
+  four arguments, which come from `denote' in this order: TITLE,
+  DATE, KEYWORDS, IDENTIFIER.  Read the doc string of `format' on
+  how to reorder arguments.
+
+- `:title-key-regexp' is a regular expression that is used to
+  retrieve the title line in a file.  The first line matching
+  this regexp is considered the title line.
+
+- `:title-value-function' is the function used to format the raw
+  title string for inclusion in the front matter (e.g. to
+  surround it with quotes).  Use the `identity' function if no
+  further processing is required.
+
+- `:title-value-reverse-function' is the function used to
+  retrieve the raw title string from the front matter.  It
+  performs the reverse of `:title-value-function'.
+
+- `:keywords-key-regexp' is a regular expression used to retrieve
+  the keywords' line in the file.  The first line matching this
+  regexp is considered the keywords' line.
+
+- `:keywords-value-function' is the function used to format the
+  keywords' list of strings as a single string, with appropriate
+  delimiters, for inclusion in the front matter.
+
+- `:keywords-value-reverse-function' is the function used to
+  retrieve the keywords' value from the front matter.  It
+  performs the reverse of the `:keywords-value-function'.
+
+- `:link' is a string, or variable holding a string, that
+  specifies the format of a link.  See the variables
+  `denote-org-link-format', `denote-md-link-format'.
+
+- `:link-in-context-regexp' is a regular expression that is used
+  to match the aforementioned link format.  See the variables
+  `denote-org-link-in-context-regexp',`denote-md-link-in-context-regexp'.
+
+If the user option `denote-file-type' is nil, use the first element of
+this list for new note creation.  The default is `org'.")
+
+(defun denote--file-extension (file-type)
+  "Return file type extension based on FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :extension))
+
+(defun denote--front-matter (file-type)
+  "Return front matter based on FILE-TYPE."
+  (let ((prop (plist-get
+               (alist-get file-type denote-file-types)
+               :front-matter)))
+    (if (symbolp prop)
+        (symbol-value prop)
+      prop)))
+
+(defun denote--title-key-regexp (file-type)
+  "Return the title key regexp associated to FILE-TYPE."
+  (or (plist-get
+       (alist-get file-type denote-file-types)
+       :title-key-regexp)
+      "^DenoteUserWantsEmptyFieldSoHandleIt")) ; Will not be found
+
+(defun denote--title-value-function (file-type)
+  "Convert title string to a front matter title, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :title-value-function))
+
+(defun denote--title-value-reverse-function (file-type)
+  "Convert front matter title to the title string, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :title-value-reverse-function))
+
+(defun denote--keywords-key-regexp (file-type)
+  "Return the keywords key regexp associated to FILE-TYPE."
+  (or (plist-get
+       (alist-get file-type denote-file-types)
+       :keywords-key-regexp)
+      "^DenoteUserWantsEmptyFieldSoHandleIt")) ; Will not be found
+
+(defun denote--keywords-value-function (file-type)
+  "Convert keywords' list to front matter keywords, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :keywords-value-function))
+
+(defun denote--keywords-value-reverse-function (file-type)
+  "Convert front matter keywords to keywords' list, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :keywords-value-reverse-function))
+
+(defun denote--signature-key-regexp (file-type)
+  "Return the signature key regexp associated to FILE-TYPE."
+  (or (plist-get
+       (alist-get file-type denote-file-types)
+       :signature-key-regexp)
+      "^DenoteUserWantsEmptyFieldSoHandleIt")) ; Will not be found
+
+(defun denote--signature-value-function (file-type)
+  "Convert signature string to front matter signature, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :signature-value-function))
+
+(defun denote--signature-value-reverse-function (file-type)
+  "Convert front matter signature to signature string, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :signature-value-reverse-function))
+
+(defun denote--identifier-key-regexp (file-type)
+  "Return the identifier key regexp associated to FILE-TYPE."
+  (or (plist-get
+       (alist-get file-type denote-file-types)
+       :identifier-key-regexp)
+      "^DenoteUserWantsEmptyFieldSoHandleIt")) ; Will not be found
+
+(defun denote--identifier-value-function (file-type)
+  "Convert identifier string to front matter identifier, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :identifier-value-function))
+
+(defun denote--identifier-value-reverse-function (file-type)
+  "Convert front matter identifier to identifier string, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :identifier-value-reverse-function))
+
+(defun denote--date-key-regexp (file-type)
+  "Return the date key regexp associated to FILE-TYPE."
+  (or (plist-get
+       (alist-get file-type denote-file-types)
+       :date-key-regexp)
+      "^DenoteUserWantsEmptyFieldSoHandleIt")) ; Will not be found
+
+(defun denote--date-value-function (file-type)
+  "Convert date object to front matter date, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :date-value-function))
+
+(defun denote--date-value-reverse-function (file-type)
+  "Convert front matter date to date object, per FILE-TYPE."
+  (plist-get
+   (alist-get file-type denote-file-types)
+   :date-value-reverse-function))
+
+(defun denote--link-format (file-type)
+  "Return link format extension based on FILE-TYPE."
+  (let ((prop (plist-get
+               (alist-get file-type denote-file-types)
+               :link)))
+    (if (symbolp prop)
+        (symbol-value prop)
+      prop)))
+
+(defun denote--link-in-context-regexp (file-type)
+  "Return link regexp in context based on FILE-TYPE."
+  (let ((prop (plist-get
+               (alist-get file-type denote-file-types)
+               :link-in-context-regexp)))
+    (if (symbolp prop)
+        (symbol-value prop)
+      prop)))
+
+(defun denote-file-type-extensions ()
+  "Return all file type extensions in `denote-file-types'."
+  (delete-dups
+   (mapcar (lambda (type)
+             (plist-get (cdr type) :extension))
+           denote-file-types)))
+
+(defun denote--file-type-keys ()
+  "Return all `denote-file-types' keys."
+  (delete-dups (mapcar #'car denote-file-types)))
+
+(defun denote--get-component-key-regexp-function (component)
+  "Return COMPONENT's key regexp function.
+
+COMPONENT can be one of `title', `keywords', `identifier', `date', `signature'."
+  (pcase component
+    ('title #'denote--title-key-regexp)
+    ('keywords #'denote--keywords-key-regexp)
+    ('signature #'denote--signature-key-regexp)
+    ('date #'denote--date-key-regexp)
+    ('identifier #'denote--identifier-key-regexp)))
+
+(defun denote--format-front-matter (title date keywords id signature filetype)
+  "Front matter for new notes.
+
+TITLE, SIGNATURE, and ID are strings.  DATE is a date object.  KEYWORDS
+is a list of strings.  FILETYPE is one of the values of variable
+`denote-file-type'."
+  (let* ((fm (denote--front-matter filetype))
+         (title-value-function (denote--title-value-function filetype))
+         (keywords-value-function (denote--keywords-value-function filetype))
+         (id-value-function (denote--identifier-value-function filetype))
+         (signature-value-function (denote--signature-value-function filetype))
+         (title-string (if title-value-function (funcall title-value-function title) ""))
+         (date-string (denote--format-front-matter-date date filetype))
+         (keywords-string (if keywords-value-function (funcall keywords-value-function (denote-sluggify-keywords keywords)) ""))
+         (id-string (if id-value-function (funcall id-value-function id) ""))
+         (signature-string (if signature-value-function (funcall signature-value-function (denote-sluggify-signature signature)) ""))
+         (new-front-matter (if fm (format fm title-string date-string keywords-string id-string signature-string) "")))
+    ;; Remove lines with empty values if the corresponding component
+    ;; is not in `denote-front-matter-components-present-even-if-empty-value'.
+    (with-temp-buffer
+      (insert new-front-matter)
+      (dolist (component '(title date keywords signature identifier))
+        (let ((value (pcase component ('title title) ('keywords keywords) ('signature signature) ('date date) ('identifier id)))
+              (component-key-regexp-function (denote--get-component-key-regexp-function component)))
+          (goto-char (point-min))
+          (when (and (not (denote--component-has-value-p component value))
+                     (not (memq component denote-front-matter-components-present-even-if-empty-value))
+                     (re-search-forward (funcall component-key-regexp-function filetype) nil t 1))
+              (goto-char (line-beginning-position))
+              (delete-region (line-beginning-position) (line-beginning-position 2)))))
+      (buffer-string))))
+
+;;;; Front matter or content retrieval functions
+
+(defun denote-retrieve-filename-identifier (file)
+  "Extract identifier from FILE name, if present, else return nil.
+
+To create a new one from a date, refer to the function
+`denote-get-identifier'."
+  (let ((filename (file-name-nondirectory file)))
+    (cond ((string-match (concat "\\`" denote-id-regexp) filename)
+           (match-string-no-properties 0 filename))
+          ((string-match (concat "@@\\(?1:" denote-id-regexp "\\)") filename)
+           (match-string-no-properties 1 filename)))))
+
+;; TODO 2023-12-08: Maybe we can only use
+;; `denote-retrieve-filename-identifier' and remove this function.
+(defun denote-retrieve-filename-identifier-with-error (file)
+  "Extract identifier from FILE name, if present, else signal an error."
+  (or (denote-retrieve-filename-identifier file)
+      (error "Cannot find `%s' as a file with a Denote identifier" file)))
+
+(defun denote-get-identifier (date)
+  "Convert DATE into a Denote identifier using `denote-id-format'.
+If DATE is nil, return an empty string as the identifier."
+  (if date
+      (format-time-string denote-id-format date)
+    ""))
+
+(defvar denote--used-ids nil
+  "Hash table of used identifiers.
+This variable should be set only for the duration of a command.
+It should stay nil otherwise.")
+
+(define-obsolete-function-alias
+  'denote-create-unique-file-identifier
+  'denote-get-identifier
+  "4.0.0")
+
+(defun denote-retrieve-filename-keywords (file)
+  "Extract keywords from FILE name, if present, else return nil.
+Return matched keywords as a single string.
+
+Also see `denote-extract-keywords-from-path' (alias
+`denote-retrieve-filename-keywords-as-list')."
+  (let ((filename (file-name-nondirectory file)))
+    (when (string-match denote-keywords-regexp filename)
+      (match-string 1 filename))))
+
+(defun denote-retrieve-filename-signature (file)
+  "Extract signature from FILE name, if present, else return nil."
+  (let ((filename (file-name-nondirectory file)))
+    (when (string-match denote-signature-regexp filename)
+      (match-string 1 filename))))
+
+(defun denote-retrieve-filename-title (file)
+  "Extract Denote title component from FILE name, else return nil."
+  (let ((filename (file-name-nondirectory file)))
+    (when (string-match denote-title-regexp filename)
+      (match-string 1 filename))))
+
+(defun denote--file-with-temp-buffer-subr (file)
+  "Return path to FILE or its buffer together with the appropriate function.
+Subroutine of `denote--file-with-temp-buffer'."
+  (let* ((buffer (get-file-buffer file))
+         (file-exists (file-exists-p file))
+         (buffer-modified (buffer-modified-p buffer)))
+    (cond
+     ((or (and file-exists
+               buffer
+               (not buffer-modified)
+               (not (eq buffer-modified 'autosaved)))
+          (and file-exists (not buffer)))
+      (cons #'insert-file-contents file))
+     (buffer
+      (cons #'insert-buffer buffer))
+     ;; (t
+     ;;  (error "Cannot find anything about file `%s'" file))
+     )))
+
+(defmacro denote--file-with-temp-buffer (file &rest body)
+  "If FILE exists, insert its contents in a temp buffer and call BODY."
+  (declare (indent 1))
+  `(when-let* ((file-and-function (denote--file-with-temp-buffer-subr ,file)))
+     (with-temp-buffer
+       (funcall (car file-and-function) (cdr file-and-function))
+       (goto-char (point-min))
+       ,@body)))
+
+(defmacro denote--define-retrieve-front-matter (component scope)
+  "Define a function to retrieve front matter for COMPONENT given SCOPE.
+The COMPONENT is one of the file name components that has a
+corresponding front matter entry.  SCOPE is a symbol of either `value'
+or `line', referring to what the function should retrieve."
+  (declare (indent 1))
+  `(defun ,(intern (format "denote-retrieve-front-matter-%s-%s" component scope)) (file file-type)
+     (when file-type
+       (denote--file-with-temp-buffer file
+         (when (re-search-forward (,(intern (format "denote--%s-key-regexp" component)) file-type) nil t 1)
+           ,(cond
+             ((eq scope 'value)
+              `(funcall (,(intern (format "denote--%s-value-reverse-function" component)) file-type)
+                        (buffer-substring-no-properties (point) (line-end-position))))
+             ((eq scope 'line)
+              '(buffer-substring-no-properties (line-beginning-position) (line-end-position)))
+             (t (error "`%s' is not a known scope" scope))))))))
+
+(denote--define-retrieve-front-matter title value)
+(denote--define-retrieve-front-matter title line)
+(denote--define-retrieve-front-matter keywords value)
+(denote--define-retrieve-front-matter keywords line)
+(denote--define-retrieve-front-matter signature value)
+(denote--define-retrieve-front-matter signature line)
+(denote--define-retrieve-front-matter identifier value)
+(denote--define-retrieve-front-matter identifier line)
+(denote--define-retrieve-front-matter date value)
+(denote--define-retrieve-front-matter date line)
+
+;; These are private front matter retrieval functions, working with a content parameter
+
+(defmacro denote--define-retrieve-front-matter-from-content (component scope)
+  "Define a function to retrieve front matter for COMPONENT given SCOPE.
+The COMPONENT is one of the file name components that has a
+corresponding front matter entry.  SCOPE is a symbol of either `value'
+or `line', referring to what the function should retrieve."
+  (declare (indent 1))
+  `(defun ,(intern (format "denote--retrieve-front-matter-%s-%s-from-content" component scope)) (content file-type)
+     (when file-type
+       (with-temp-buffer
+         (insert content)
+         (goto-char (point-min))
+         (when (re-search-forward (,(intern (format "denote--%s-key-regexp" component)) file-type) nil t 1)
+           ,(cond
+             ((eq scope 'value)
+              `(funcall (,(intern (format "denote--%s-value-reverse-function" component)) file-type)
+                        (buffer-substring-no-properties (point) (line-end-position))))
+             ((eq scope 'line)
+              '(buffer-substring-no-properties (line-beginning-position) (line-end-position)))
+             (t (error "`%s' is not a known scope" scope))))))))
+
+(denote--define-retrieve-front-matter-from-content title value)
+(denote--define-retrieve-front-matter-from-content title line)
+(denote--define-retrieve-front-matter-from-content keywords value)
+(denote--define-retrieve-front-matter-from-content keywords line)
+(denote--define-retrieve-front-matter-from-content signature value)
+(denote--define-retrieve-front-matter-from-content signature line)
+(denote--define-retrieve-front-matter-from-content identifier value)
+(denote--define-retrieve-front-matter-from-content identifier line)
+(denote--define-retrieve-front-matter-from-content date value)
+(denote--define-retrieve-front-matter-from-content date line)
+
+(defalias 'denote-retrieve-title-value 'denote-retrieve-front-matter-title-value
+  "Alias for `denote-retrieve-front-matter-title-value'.")
+
+(defalias 'denote-retrieve-title-line 'denote-retrieve-front-matter-title-line
+  "Alias for `denote-retrieve-front-matter-title-line'.")
+
+(defalias 'denote-retrieve-keywords-value 'denote-retrieve-front-matter-keywords-value
+  "Alias for `denote-retrieve-front-matter-keywords-value'.")
+
+(defalias 'denote-retrieve-keywords-line 'denote-retrieve-front-matter-keywords-line
+  "Alias for `denote-retrieve-front-matter-keywords-line'.")
+
+(defun denote-retrieve-title-or-filename (file type)
+  "Return appropriate title for FILE given its TYPE.
+This is a wrapper for `denote-retrieve-front-matter-title-value' and
+`denote-retrieve-filename-title'."
+  (let ((has-denoted-filename (denote-file-has-denoted-filename-p file))
+        (has-supported-extension (denote-file-has-supported-extension-p file)))
+    (cond ((and has-denoted-filename has-supported-extension)
+           (or (denote-retrieve-front-matter-title-value file type)
+               (denote-retrieve-filename-title file)
+               ""))
+          (has-denoted-filename
+           (or (denote-retrieve-filename-title file) ""))
+          (t
+           (file-name-base file)))))
+
+(make-obsolete 'denote--retrieve-location-in-xrefs 'denote-retrieve-groups-xref-query "4.0.0")
+
+(define-obsolete-function-alias
+  'denote--retrieve-group-in-xrefs
+  'denote-retrieve-groups-xref-query
+  "4.0.0")
+
+(defun denote-retrieve-groups-xref-query (query &optional files-matching-regexp)
+  "Access location of xrefs for QUERY and group them per file.
+Limit the search to text files.  With optional FILES-MATCHING-REGEXP,
+pass it to `denote-directory-files'."
+  (when-let* ((files (denote-directory-files files-matching-regexp nil :text-only))
+              (locations (mapcar #'xref-match-item-location (xref-matches-in-files query files))))
+    (mapcar #'xref-location-group locations)))
+
+(define-obsolete-function-alias
+  'denote--retrieve-files-in-xrefs
+  'denote-retrieve-files-xref-query
+  "4.0.0")
+
+(defun denote-retrieve-files-xref-query (query &optional files-matching-regexp)
+  "Return sorted, deduplicated file names with matches for QUERY in their contents.
+Limit the search to text files.  With optional FILES-MATCHING-REGEXP,
+pass it to `denote-directory-files'."
+  (sort
+   (delete-dups
+    (denote-retrieve-groups-xref-query query files-matching-regexp))
+   #'string-collate-lessp))
+
+(defvar denote-query--last-files nil
+  "List of files matched by the last call to `denote-make-links-buffer'.")
+
+(defvar denote-query--last-query nil
+  "String of the last call to `denote-make-links-buffer'.")
+
+(defvar denote-query--omit-current t
+  "When non-nil `denote-make-links-buffer' omits the current file.")
+
+(defun denote-retrieve-xref-alist (query &optional files)
+  "Return xref alist of absolute file paths with location of matches for QUERY.
+Optional FILES can be a list of files to search for.  It can also be a
+regular expression, which means to use the text files in the variable
+`denote-directory' that match that regexp.
+
+If FILES is not given, use all text files as returned by
+`denote-directory-files'."
+  (let ((xref-file-name-display 'abs))
+    (xref--analyze
+     (xref-matches-in-files
+      query
+      (if (and files (listp files))
+          files
+        (denote-directory-files files denote-query--omit-current :text-only))))))
+
+;;;; New note
+
+;;;;; Common helpers for new notes
+
+(defun denote-format-file-name (dir-path id keywords title extension signature)
+  "Format file name.
+DIR-PATH, ID, KEYWORDS, TITLE, EXTENSION and SIGNATURE are
+expected to be supplied by `denote' or equivalent command.
+
+DIR-PATH is a string pointing to a directory.  It ends with a
+forward slash (the function `denote-directory' makes sure this is
+the case when returning the value of the variable `denote-directory').
+DIR-PATH cannot be nil or an empty string.
+
+ID is a string holding the identifier of the note.  It can be an
+empty string, in which case its respective file name component is
+not added to the base file name.
+
+DIR-PATH and ID form the base file name.
+
+KEYWORDS is a list of strings that is reduced to a single string
+by `denote-keywords-combine'.  KEYWORDS can be an empty list or
+a nil value, in which case the relevant file name component is
+not added to the base file name.
+
+TITLE and SIGNATURE are strings.  They can be an empty string, in
+which case their respective file name component is not added to
+the base file name.
+
+EXTENSION is a string that contains a dot followed by the file
+type extension.  It can be an empty string or a nil value, in
+which case it is not added to the base file name."
+  (cond
+   ((null dir-path)
+    (error "DIR-PATH must not be nil"))
+   ((string-empty-p dir-path)
+    (error "DIR-PATH must not be an empty string"))
+   ((not (string-suffix-p "/" dir-path))
+    (error "DIR-PATH does not end with a / as directories ought to")))
+  (let ((file-name "")
+        (components (seq-union denote-file-name-components-order
+                               '(identifier signature title keywords))))
+    (dolist (component components)
+      (cond ((and (eq component 'identifier) id (not (string-empty-p id)))
+             (setq file-name (concat file-name "@@" id)))
+            ((and (eq component 'title) title (not (string-empty-p title)))
+             (setq file-name (concat file-name "--" (denote-sluggify 'title title))))
+            ((and (eq component 'keywords) keywords)
+             (setq file-name (concat file-name "__" (denote-keywords-combine (denote-sluggify-keywords keywords)))))
+            ((and (eq component 'signature) signature (not (string-empty-p signature)))
+             (setq file-name (concat file-name "==" (denote-sluggify 'signature signature))))))
+    (when (string-empty-p file-name)
+      (error "There should be at least one file name component"))
+    (setq file-name (concat file-name extension))
+    ;; Do not prepend identifier with @@ if it is the first component and has the format 00000000T000000.
+    (when (and (string-prefix-p "@@" file-name)
+               (string-match-p (concat "\\`" denote-id-regexp "\\'") id)) ; This is always true for now.
+      (setq file-name (substring file-name 2)))
+    (concat dir-path file-name)))
+
+;; Adapted from `org-hugo--org-date-time-to-rfc3339' in the `ox-hugo'
+;; package: <https://github.com/kaushalmodi/ox-hugo>.
+(defun denote-date-rfc3339 (date)
+  "Format DATE using the RFC3339 specification."
+  (if date
+      (replace-regexp-in-string
+       "\\([0-9]\\{2\\}\\)\\([0-9]\\{2\\}\\)\\'" "\\1:\\2"
+       (format-time-string "%FT%T%z" date))
+    ""))
+
+(defun denote-date-org-timestamp (date)
+  "Format DATE using the Org inactive timestamp notation."
+  (if date
+      (format-time-string "[%F %a %R]" date)
+    ""))
+
+(defun denote-date-iso-8601 (date)
+  "Format DATE according to ISO 8601 standard."
+  (if date
+      (format-time-string "%F" date)
+    ""))
+
+(defun denote--format-front-matter-date (date file-type)
+  "Expand DATE in an appropriate format for FILE-TYPE."
+  (let ((format denote-date-format))
+    (cond
+     (format
+      (if date (format-time-string format date) ""))
+     ((when-let* ((fn (denote--date-value-function file-type)))
+        (funcall fn date)))
+     (t
+      (denote-date-org-timestamp date)))))
+
+(defun denote--prepare-note (title keywords date id directory file-type template signature)
+  "Prepare a new note file and return its path.
+
+Arguments TITLE, KEYWORDS, DATE, ID, DIRECTORY, FILE-TYPE,
+TEMPLATE, and SIGNATURE should be valid for note creation."
+  (let* ((path (denote-format-file-name
+                directory id keywords title (denote--file-extension file-type) signature))
+         (buffer (find-file path))
+         (header (denote--format-front-matter title date keywords id signature file-type)))
+    (when (file-regular-p path)
+      (user-error "A file named `%s' already exists" path))
+    (with-current-buffer buffer
+      (insert header)
+      (insert (cond
+               ((stringp template) template)
+               ((functionp template) (funcall template))
+               (t (user-error "Invalid template")))))
+    path))
+
+(defun denote--dir-in-denote-directory-p (directory)
+  "Return non-nil if DIRECTORY is in variable `denote-directory'."
+  (string-prefix-p (denote-directory) (expand-file-name directory)))
+
+(defun denote--valid-file-type (filetype)
+  "Return a valid filetype symbol given the argument FILETYPE.
+If none is found, the first element of `denote-file-types' is
+returned."
+  (let ((type (cond
+               ((stringp filetype) (intern filetype))
+               ((symbolp filetype) filetype)
+               (t (error "The `%s' is neither a string nor a symbol" filetype)))))
+    (cond ((memq type (denote--file-type-keys))
+           type)
+          ((null denote-file-types)
+           (user-error "At least one file type must be defined in `denote-file-types' to create a note"))
+          (t
+           (caar denote-file-types)))))
+
+(defun denote--date-add-current-time (date)
+  "Add current time to DATE, if necessary.
+The idea is to turn 2020-01-15 into 2020-01-15 16:19 so that the
+hour and minute component is not left to 00:00.
+
+This reduces the burden on the user who would otherwise need to
+input that value in order to avoid the error of duplicate
+identifiers.
+
+It also addresses a difference between Emacs 28 and Emacs 29
+where the former does not read dates without a time component."
+  (if (<= (length date) 10)
+      (format "%s %s" date (format-time-string "%H:%M:%S" (current-time)))
+    date))
+
+(define-obsolete-function-alias
+  'denote-parse-date
+  'denote-valid-date-p
+  "4.0.0")
+
+(defun denote-valid-date-p (date)
+  "Return DATE as a valid date.
+A valid DATE is a value that can be parsed by either
+`decode-time' or `date-to-time'.  Those functions signal an error
+if DATE is a value they do not recognise.
+
+If DATE is nil or an empty string, return nil."
+  (cond ((null date)
+         nil)
+        ((and (stringp date) (string-empty-p date))
+         nil)
+        ((and (or (numberp date) (listp date))
+              (decode-time date))
+         date)
+        (t ; non-empty strings (e.g. "2024-01-01", "2024-01-01 12:00", etc.)
+         (date-to-time (denote--date-add-current-time date)))))
+
+(defun denote--id-to-date (identifier)
+  "Convert IDENTIFIER string to YYYY-MM-DD."
+  (if (denote-identifier-p identifier)
+      (replace-regexp-in-string
+       "\\([0-9]\\{4\\}\\)\\([0-9]\\{2\\}\\)\\([0-9]\\{2\\}\\).*"
+       "\\1-\\2-\\3"
+       identifier)
+    (error "`%s' does not look like a Denote identifier per `denote-id-regexp'" identifier)))
+
+(defun denote--buffer-file-names ()
+  "Return file names of Denote buffers."
+  (delq nil
+        (mapcar
+         (lambda (buffer)
+           (when-let* (((buffer-live-p buffer))
+                       (file (buffer-file-name buffer))
+                       ((denote-filename-is-note-p file)))
+             file))
+         (buffer-list))))
+
+(defun denote--get-all-used-ids ()
+  "Return a hash-table of all used identifiers.
+It checks files in variable `denote-directory' and active buffer files."
+  (let* ((ids (make-hash-table :test 'equal))
+         (file-names (mapcar
+                      (lambda (file) (file-name-nondirectory file))
+                      (denote-directory-files)))
+         (names (append file-names (denote--buffer-file-names))))
+    (dolist (name names)
+      (when-let* ((id (denote-retrieve-filename-identifier name)))
+        (puthash id t ids)))
+    ids))
+
+(defun denote--find-first-unused-id (id)
+  "Return the first unused id starting at ID.
+If ID is already used, increment it 1 second at a time until an
+available id is found."
+  (let ((used-ids (or denote--used-ids (denote--get-all-used-ids)))
+        (current-id id)
+        (iteration 0))
+    (while (gethash current-id used-ids)
+      ;; Prevent infinite loop if `denote-id-format' is misconfigured
+      (setq iteration (1+ iteration))
+      (when (>= iteration 10000)
+        (user-error "A unique identifier could not be found"))
+      (setq current-id (denote-get-identifier (time-add (date-to-time current-id) 1))))
+    current-id))
+
+(defvar denote-command-prompt-history nil
+  "Minibuffer history for `denote-command-prompt'.")
+
+(defalias 'denote--command-prompt-history 'denote-command-prompt-history
+  "Compatibility alias for `denote-command-prompt-history'.")
+
+(defun denote-command-prompt ()
+  "Prompt for command among `denote-commands-for-new-notes'."
+  (let ((default (car denote-command-prompt-history)))
+    (intern
+     (completing-read
+      (format-prompt "Run note-creating Denote command" default)
+      denote-commands-for-new-notes nil :require-match
+      nil 'denote-command-prompt-history default))))
+
+;;;;; The `denote' command and its prompts
+
+(defun denote--prompt-with-completion-p (fn)
+  "Return non-nil if FN prompt should perform completion.
+FN is one among `denote-prompts-with-history-as-completion' and performs
+completion when the user option `denote-history-completion-in-prompts'
+is non-nil."
+  (and denote-history-completion-in-prompts
+       (memq fn denote-prompts-with-history-as-completion)))
+
+(defvar denote-ignore-region-in-denote-command nil
+  "If non-nil, the region is ignored by the `denote' command.
+
+The `denote' command uses the region as the default title when
+prompted for a title.  When this variable is non-nil, the
+`denote' command ignores the region.  This variable is useful in
+commands that have their own way of handling the region.")
+
+(defvar denote-title-prompt-current-default nil
+  "Currently bound default title for `denote-title-prompt'.
+Set the value of this variable within the lexical scope of a
+command that needs to supply a default title before calling
+`denote-title-prompt'.")
+
+(defun denote--command-with-features (command force-use-file-prompt-as-default-title force-ignore-region force-save in-background)
+  "Execute file-creating COMMAND with specified features.
+
+COMMAND is the symbol of a file-creating command to call, such as
+`denote' or `denote-signature'.
+
+With non-nil FORCE-USE-FILE-PROMPT-AS-DEFAULT-TITLE, use the last
+item of `denote-file-history' as the default title of the title
+prompt.  This is useful in a command such as `denote-link' where
+the entry of the file prompt can be reused as the default title.
+
+With non-nil FORCE-IGNORE-REGION, the region is ignore when
+creating the note, i.e. it will not be used as the initial title
+in a title prompt.  Else, the value of
+`denote-ignore-region-in-denote-command' is respected.
+
+With non-nil FORCE-SAVE, the file is saved at the end of the note
+creation.  Else, the value of `denote-save-buffers' is respected.
+
+With non-nil IN-BACKGROUND, the note creation happens in the
+background, i.e. the note's buffer will not be displayed after
+the note is created.
+
+Note that if all parameters except COMMAND are nil, this is
+equivalent to `(call-interactively command)'.
+
+The path of the newly created file is returned."
+  (let ((denote-save-buffers
+         (or force-save denote-save-buffers))
+        (denote-ignore-region-in-denote-command
+         (or force-ignore-region denote-ignore-region-in-denote-command))
+        (denote-title-prompt-current-default
+         (if force-use-file-prompt-as-default-title
+             denote-file-prompt-latest-input
+           denote-title-prompt-current-default))
+        (path))
+    (if in-background
+        (save-window-excursion
+          (setq path (call-interactively command)))
+      (setq path (call-interactively command)))
+    path))
+
+(defun denote--handle-save-and-kill-buffer (mode file initial-state)
+  "Save and kill buffer of FILE according to MODE and INITIAL-STATE.
+
+The values of `denote-save-buffers' and `denote-kill-buffers' are
+used to decide whether to save and/or kill the buffer visiting
+FILE.
+
+MODE is one of the symbols `creation' or `rename'.
+
+INITIAL-STATE is nil or one of the following symbols:
+`not-visited', `visited'.  If a buffer was already visited at the
+beginning of a rename operation, it is NOT killed automatically.
+
+If a buffer needs to be killed, it is also automatically saved,
+no matter the value of `denote-save-buffers'."
+  (let* ((do-kill-buffer (and (not (eq initial-state 'visited))
+                              (or (eq denote-kill-buffers t)
+                                  (and (eq mode 'creation)
+                                       (eq denote-kill-buffers 'on-creation))
+                                  (and (eq mode 'rename)
+                                       (eq denote-kill-buffers 'on-rename)))))
+         (do-save-buffer (or do-kill-buffer denote-save-buffers)))
+    (when-let* ((buffer (find-buffer-visiting file)))
+      (when do-save-buffer (with-current-buffer buffer (save-buffer)))
+      (when do-kill-buffer (kill-buffer buffer)))))
+
+(defvar denote-current-data nil
+  "Store the current unprocessed data passed to `denote'.
+This is an alist where each `car' is one among `title', `keywords',
+`signature', `directory', `date', `id', `file-type', `template'.  The
+value each of them contains is the unprocessed input (e.g. the title
+before it is sluggified).
+
+This may be used by the hooks `denote-after-new-note-hook' and
+`denote-after-rename-file-hook' to access the relevant data.")
+
+(defvar denote-use-title nil
+  "The title to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if nil.
+
+Only ever `let' bind this, otherwise the title will always be the same
+and the title prompt will be skipped.")
+
+(defvar denote-use-keywords 'default
+  "The keywords to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if `default'.
+
+Only ever `let' bind this, otherwise the keywords will always be the same
+and the keywords prompt will be skipped.")
+
+(defvar denote-use-signature nil
+  "The signature to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if nil.
+
+Only ever `let' bind this, otherwise the signaturew will always be the same
+and the signature prompt will be skipped.")
+
+(defvar denote-use-file-type nil
+  "The title to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if nil.
+
+Only ever `let' bind this, otherwise the file type will always be the
+same.")
+
+(defvar denote-use-directory nil
+  "The directory to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if nil.
+
+Only ever `let' bind this, otherwise the directory will always be the
+same.")
+
+(defvar denote-use-date nil
+  "The date to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if nil.
+
+Only ever `let' bind this, otherwise the date will always be the same
+and the date prompt will be skipped.")
+
+(defvar denote-use-template nil
+  "The template to be used in a note creation command.
+See the documentation of `denote' for acceptable values.  This variable
+is ignored if nil.
+
+Only ever `let' bind this, otherwise the template will always be the same
+and the template prompt will be skipped.")
+
+(defun denote--creation-get-note-data-from-prompts ()
+  "Retrieve the data necessary for note creation.
+
+The data elements are: title, keywords, file-type, directory,
+date, template and signature.
+
+It is retrieved from prompts according to `denote-prompts' and
+from `denote-use-*' variables.  For example, if
+`denote-use-title' is set to a title, then no prompts happen for
+the title and the value of `denote-use-title' will be used
+instead."
+  (let (title keywords file-type directory date template signature)
+    (dolist (prompt denote-prompts)
+      (pcase prompt
+        ('title (unless denote-use-title
+                  (setq title (denote-title-prompt
+                               (when (and (not denote-ignore-region-in-denote-command)
+                                          (use-region-p))
+                                 (buffer-substring-no-properties
+                                  (region-beginning)
+                                  (region-end)))))))
+        ('keywords (when (eq denote-use-keywords 'default)
+                     (setq keywords (denote-keywords-prompt))))
+        ('file-type (unless denote-use-file-type
+                      (setq file-type (denote-file-type-prompt))))
+        ('subdirectory (unless denote-use-directory
+                         (setq directory (denote-subdirectory-prompt))))
+        ('date (unless denote-use-date
+                 (setq date (denote-date-prompt))))
+        ('template (unless denote-use-template
+                     (setq template (denote-template-prompt))))
+        ('signature (unless denote-use-signature
+                      (setq signature (denote-signature-prompt))))))
+    (list title keywords file-type directory date template signature)))
+
+(defun denote--creation-prepare-note-data (title keywords file-type directory date template signature)
+  "Return parameters in a valid form for file creation.
+
+The data is: TITLE, KEYWORDS, FILE-TYPE, DIRECTORY, DATE,
+TEMPLATE and SIGNATURE.  The identifier is also returned.
+
+If a `denote-use-*' variable is set for a data, its value is used
+instead of that of the parameter."
+  (let* (;; Handle the `denote-use-*' variables
+         (title (or denote-use-title title))
+         (keywords (if (eq denote-use-keywords 'default) keywords denote-use-keywords))
+         (file-type (or denote-use-file-type file-type))
+         (directory (or denote-use-directory directory))
+         (date (or denote-use-date date))
+         (template (or denote-use-template template))
+         (signature (or denote-use-signature signature))
+         ;; Make the data valid
+         (title (or title ""))
+         (file-type (denote--valid-file-type (or file-type denote-file-type)))
+         (keywords (denote-keywords-sort keywords))
+         (date (denote-valid-date-p date))
+         (date (cond (date date)
+                     ((or (eq denote-generate-identifier-automatically t)
+                          (eq denote-generate-identifier-automatically 'on-creation))
+                      (current-time))))
+         (id (denote-get-identifier date))
+         (id (if (string-empty-p id) id (denote--find-first-unused-id id)))
+         (date (if (string-empty-p id) nil (date-to-time id)))
+         (directory (if (and directory (denote--dir-in-denote-directory-p directory))
+                        (file-name-as-directory directory)
+                      (denote-directory)))
+         (template (if (or (stringp template) (functionp template))
+                       template
+                     (or (alist-get template denote-templates) "")))
+         (signature (or signature "")))
+    (list title keywords file-type directory date id template signature)))
+
+;;;###autoload
+(defun denote (&optional title keywords file-type directory date template signature)
+  "Create a new note with the appropriate metadata and file name.
+
+Run the `denote-after-new-note-hook' after creating the new note and
+return its path.  Before returning the path, determine what needs to be
+done to the buffer, in accordance with the user option `denote-kill-buffers'.
+
+When called interactively, the metadata and file name are prompted
+according to the value of `denote-prompts'.
+
+When called from Lisp, all arguments are optional.
+
+- TITLE is a string or a function returning a string.
+
+- KEYWORDS is a list of strings.  The list can be empty or the
+  value can be set to nil.
+
+- FILE-TYPE is a symbol among those described in the user option
+  `denote-file-type'.
+
+- DIRECTORY is a string representing the path to either the
+  value of the variable `denote-directory' or a subdirectory
+  thereof.  The subdirectory must exist: Denote will not create
+  it.  If DIRECTORY does not resolve to a valid path, the
+  variable `denote-directory' is used instead.
+
+- DATE is a string representing a date like 2022-06-30 or a date
+  and time like 2022-06-16 14:30.  A nil value or an empty string
+  is interpreted as the `current-time'.
+
+- TEMPLATE is a symbol which represents the key of a cons cell in
+  the user option `denote-templates'.  The value of that key is
+  inserted to the newly created buffer after the front matter.
+
+- SIGNATURE is a string or a function returning a string."
+  (interactive (denote--creation-get-note-data-from-prompts))
+  (pcase-let* ((`(,title ,keywords ,file-type ,directory ,date ,id ,template ,signature)
+                (denote--creation-prepare-note-data title keywords file-type directory date template signature))
+               (note-path (denote--prepare-note title keywords date id directory file-type template signature)))
+    (denote--keywords-add-to-history keywords)
+    (setq denote-current-data
+          (list
+           (cons 'title title)
+           (cons 'keywords keywords)
+           (cons 'signature signature)
+           (cons 'directory directory)
+           (cons 'date date)
+           (cons 'id id)
+           (cons 'file-type file-type)
+           (cons 'template template)))
+    (run-hooks 'denote-after-new-note-hook)
+    (denote--handle-save-and-kill-buffer 'creation note-path nil)
+    note-path))
+
+(defvar denote-title-history nil
+  "Minibuffer history of `denote-title-prompt'.")
+
+(defalias 'denote--title-history 'denote-title-history
+  "Compatibility alias for `denote-title-history'.")
+
+(defmacro denote--with-conditional-completion (fn prompt history &optional initial-value default-value)
+  "Produce body of FN that may perform completion.
+Use PROMPT, HISTORY, INITIAL-VALUE, and DEFAULT-VALUE as arguments for
+the given minibuffer prompt."
+  `(if (denote--prompt-with-completion-p ,fn)
+       ;; NOTE 2023-10-27: By default SPC performs completion in the
+       ;; minibuffer.  We do not want that, as the user should be able to
+       ;; input an arbitrary string, while still performing completion
+       ;; against their input history.
+       (minibuffer-with-setup-hook
+           (lambda ()
+             (use-local-map
+              (let ((map (make-composed-keymap nil (current-local-map))))
+                (define-key map (kbd "SPC") nil)
+                map)))
+         (completing-read ,prompt ,history nil nil ,initial-value ',history ,default-value))
+     (read-string ,prompt ,initial-value ',history ,default-value)))
+
+(defun denote-title-prompt (&optional initial-title prompt-text)
+  "Prompt for title string.
+
+With optional INITIAL-TITLE use it as the initial minibuffer
+text.  With optional PROMPT-TEXT use it in the minibuffer instead
+of the default prompt.
+
+Previous inputs at this prompt are available for minibuffer completion
+if the user option `denote-history-completion-in-prompts' is set to a
+non-nil value."
+  (denote--with-conditional-completion
+   'denote-title-prompt
+   (format-prompt (or prompt-text "New file TITLE") denote-title-prompt-current-default)
+   denote-title-history
+   (or initial-title denote-title-prompt-current-default)
+   denote-title-prompt-current-default))
+
+(defvar denote-file-type-history nil
+  "Minibuffer history of `denote-file-type-prompt'.")
+
+(defalias 'denote--file-type-history 'denote-file-type-history
+  "Compatibility alias for `denote-file-type-history'.")
+
+(defun denote-file-type-prompt ()
+  "Prompt for variable `denote-file-type'.
+Note that a non-nil value other than `text', `markdown-yaml', and
+`markdown-toml' falls back to an Org file type.  We use `org'
+here for clarity."
+  (completing-read
+   "Select file TYPE: " (denote--file-type-keys) nil t
+   nil 'denote-file-type-history))
+
+(defvar denote-date-history nil
+  "Minibuffer history of `denote-date-prompt'.")
+
+(defalias 'denote--date-history 'denote-date-history
+  "Compatibility alias for `denote-date-history'.")
+
+(declare-function org-read-date "org" (&optional with-time to-time from-string prompt default-time default-input inactive))
+
+(defun denote--date-convert (date prefer-type)
+  "Determine how to convert DATE to PREFER-TYPE `:list' or `:string'."
+  (unless (memq prefer-type '(:list :string))
+    (error "The PREFER-TYPE must be either `:list' or `:string'"))
+  (cond ((eq prefer-type :list)
+         date)
+        ((eq prefer-type :string)
+         (if date (format-time-string "%F %T" date) ""))))
+
+(defun denote-date-prompt (&optional initial-date prompt-text)
+  "Prompt for date, expecting YYYY-MM-DD or that plus HH:MM.
+Use Org's more advanced date selection utility if the user option
+`denote-date-prompt-use-org-read-date' is non-nil.
+
+With optional INITIAL-DATE use it as the initial minibuffer
+text.  With optional PROMPT-TEXT use it in the minibuffer instead
+of the default prompt.
+
+INITIAL-DATE is a string that can be processed by `denote-valid-date-p',
+a value that can be parsed by `decode-time' or nil."
+  (let ((initial-date (denote-valid-date-p initial-date)))
+    (if (and denote-date-prompt-use-org-read-date
+             (require 'org nil :no-error))
+        (let* ((time (org-read-date nil t nil prompt-text (denote--date-convert initial-date :list)))
+               (org-time-seconds (format-time-string "%S" time))
+               (cur-time-seconds (format-time-string "%S" (current-time))))
+          ;; When the user does not input a time, org-read-date defaults to 00 for seconds.
+          ;; When the seconds are 00, we add the current seconds to avoid identifier collisions.
+          (when (string-equal "00" org-time-seconds)
+            (setq time (time-add time (string-to-number cur-time-seconds))))
+          (format-time-string "%Y-%m-%d %H:%M:%S" time))
+      (read-string
+       (or prompt-text "DATE and TIME for note (e.g. 2022-06-16 14:30): ")
+       (denote--date-convert initial-date :string)
+       'denote-date-history))))
+
+(defun denote-prompt-for-date-return-id (&optional initial-date prompt-text)
+  "Use `denote-date-prompt' and return it as `denote-id-format'.
+Optional INITIAL-DATE and PROMPT-TEXT have the same meaning as
+`denote-date-prompt'."
+  (denote-get-identifier
+   (denote-valid-date-p
+    (denote-date-prompt (denote-valid-date-p initial-date) prompt-text))))
+
+(defvar denote-subdirectory-history nil
+  "Minibuffer history of `denote-subdirectory-prompt'.")
+
+(defalias 'denote--subdir-history 'denote-subdirectory-history
+  "Compatibility alias for `denote-subdirectory-history'.")
+
+;; Making it a completion table is useful for packages that read the
+;; metadata, such as `marginalia' and `embark'.
+(defun denote--subdirs-completion-table (dirs)
+  "Match DIRS as a completion table."
+  (let* ((def (car denote-subdirectory-history))
+         (table (denote--completion-table 'file dirs))
+         (prompt (format-prompt "Select SUBDIRECTORY" def)))
+    (completing-read prompt table nil t nil 'denote-subdirectory-history def)))
+
+(defun denote-subdirectory-prompt ()
+  "Prompt for subdirectory of the variable `denote-directory'.
+The table uses the `file' completion category (so it works with
+packages such as `marginalia' and `embark')."
+  (let* ((root (directory-file-name (denote-directory)))
+         (subdirs (denote-directory-subdirectories))
+         (dirs (push root subdirs)))
+    (denote--subdirs-completion-table dirs)))
+
+(defvar denote-template-history nil
+  "Minibuffer history of `denote-template-prompt'.")
+
+(defalias 'denote--template-history 'denote-template-history
+  "Compatibility alias for `denote-template-history'.")
+
+(defun denote-template-prompt ()
+  "Prompt for template key in `denote-templates' and return its value."
+  (let ((templates denote-templates))
+    (alist-get
+     (intern
+      (completing-read
+       "Select TEMPLATE key: " (mapcar #'car templates)
+       nil t nil 'denote-template-history))
+     templates)))
+
+(defvar denote-signature-history nil
+  "Minibuffer history of `denote-signature-prompt'.")
+
+(defalias 'denote--signature-history 'denote-signature-history
+  "Compatibility alias for `denote-signature-history'.")
+
+(defun denote-signature-prompt (&optional initial-signature prompt-text)
+  "Prompt for signature string.
+With optional INITIAL-SIGNATURE use it as the initial minibuffer
+text.  With optional PROMPT-TEXT use it in the minibuffer instead
+of the default prompt.
+
+Previous inputs at this prompt are available for minibuffer completion
+if the user option `denote-history-completion-in-prompts' is set to a
+non-nil value."
+  (when (and initial-signature (string-empty-p initial-signature))
+    (setq initial-signature nil))
+  (denote--with-conditional-completion
+   'denote-signature-prompt
+   (format-prompt (or prompt-text "New file SIGNATURE") nil)
+   denote-signature-history
+   initial-signature))
+
+(defvar denote-files-matching-regexp-history nil
+  "Minibuffer history of `denote-files-matching-regexp-prompt'.")
+
+(defalias 'denote--files-matching-regexp-hist 'denote-files-matching-regexp-history
+  "Compatibility alias for `denote-files-matching-regexp-history'.")
+
+(defun denote-files-matching-regexp-prompt (&optional prompt-text)
+  "Prompt for REGEXP to filter Denote files by.
+With optional PROMPT-TEXT use it instead of a generic prompt."
+  (denote--with-conditional-completion
+   'denote-files-matching-regexp-prompt
+   (format-prompt (or prompt-text "Match files with the given REGEXP") nil)
+   denote-files-matching-regexp-history))
+
+;;;;; Convenience commands as `denote' variants
+
+(defalias 'denote-create-note 'denote
+  "Alias for `denote' command.")
+
+(define-obsolete-function-alias
+  'denote--add-prompts
+  'denote-add-prompts
+  "3.0.0")
+
+(defun denote-add-prompts (additional-prompts)
+  "Add list of ADDITIONAL-PROMPTS to `denote-prompts'.
+This is best done inside of a `let' to create a wrapper function around
+`denote', `denote-rename-file', and generally any command that consults
+the value of `denote-prompts'."
+  (seq-union additional-prompts denote-prompts))
+
+;;;###autoload
+(defun denote-type ()
+  "Create note while prompting for a file type.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `file-type' prompt appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(file-type))))
+    (call-interactively #'denote)))
+
+(defalias 'denote-create-note-using-type 'denote-type
+  "Alias for `denote-type' command.")
+
+;;;###autoload
+(defun denote-date ()
+  "Create note while prompting for a date.
+
+The date can be in YEAR-MONTH-DAY notation like 2022-06-30 or
+that plus the time: 2022-06-16 14:30.  When the user option
+`denote-date-prompt-use-org-read-date' is non-nil, the date
+prompt uses the more powerful Org+calendar system.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `date' prompt appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(date))))
+    (call-interactively #'denote)))
+
+(defalias 'denote-create-note-using-date 'denote-date
+  "Alias for `denote-date' command.")
+
+;;;###autoload
+(defun denote-subdirectory ()
+  "Create note while prompting for a subdirectory.
+
+Available candidates include the value of the variable
+`denote-directory' and any subdirectory thereof.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `subdirectory' prompt appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(subdirectory))))
+    (call-interactively #'denote)))
+
+(defalias 'denote-create-note-in-subdirectory 'denote-subdirectory
+  "Alias for `denote-subdirectory' command.")
+
+;;;###autoload
+(defun denote-template ()
+  "Create note while prompting for a template.
+
+Available candidates include the keys in the `denote-templates'
+alist.  The value of the selected key is inserted in the newly
+created note after the front matter.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `template' prompt appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(template))))
+    (call-interactively #'denote)))
+
+(defalias 'denote-create-note-with-template 'denote-template
+  "Alias for `denote-template' command.")
+
+;;;###autoload
+(defun denote-signature ()
+  "Create note while prompting for a file signature.
+
+This is the equivalent of calling `denote' when `denote-prompts'
+has the `signature' prompt appended to its existing prompts."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts (denote-add-prompts '(signature))))
+    (call-interactively #'denote)))
+
+(defalias 'denote-create-note-using-signature 'denote-signature
+  "Alias for `denote-signature' command.")
+
+;;;###autoload
+(defun denote-region ()
+  "Call `denote' and insert therein the text of the active region.
+
+Note that, currently, `denote-save-buffers' and
+`denote-kill-buffers' are NOT respected.  The buffer is not
+saved or killed at the end of `denote-region'."
+  (declare (interactive-only t))
+  (interactive)
+  (if-let* (((region-active-p))
+            ;; We capture the text early, otherwise it will be empty
+            ;; the moment `insert' is called.
+            (text (buffer-substring-no-properties (region-beginning) (region-end))))
+      (progn
+        (let ((denote-ignore-region-in-denote-command t)
+              ;; FIXME: Find a way to insert the region before the buffer is
+              ;; saved/killed by the creation command.
+              (denote-save-buffers nil)
+              (denote-kill-buffers nil))
+          (call-interactively 'denote))
+        (push-mark (point))
+        (insert text)
+        (run-hook-with-args 'denote-region-after-new-note-functions (mark) (point)))
+    (call-interactively 'denote)))
+
+;;;;; Other convenience commands
+
+;;;###autoload
+(defun denote-open-or-create (target)
+  "Visit TARGET file in variable `denote-directory'.
+If file does not exist, invoke `denote' to create a file.  In that case,
+use the last input at the file prompt as the default value of the title
+prompt."
+  (interactive (list (denote-file-prompt nil "Select file (RET on no match to create it)" :no-require-match)))
+  (if (and target (file-exists-p target))
+      (find-file target)
+    (denote--command-with-features #'denote :use-last-input-as-def-title nil nil nil)))
+
+;;;###autoload
+(defun denote-open-or-create-with-command ()
+  "Like `denote-open-or-create' but use one of the `denote-commands-for-new-notes'."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((target (denote-file-prompt nil "Select file (RET on no match to create it)" :no-require-match)))
+    (if (and target (file-exists-p target))
+        (find-file target)
+      (denote--command-with-features (denote-command-prompt) :use-file-prompt-as-def-title nil nil nil))))
+
+;;;; Note modification
+
+;;;;; Common helpers for note modifications
+
+(defun denote--file-types-with-extension (extension)
+  "Return only the entries of `denote-file-types' with EXTENSION.
+See the format of `denote-file-types'."
+  (seq-filter (lambda (type)
+                (string-equal (plist-get (cdr type) :extension) extension))
+              denote-file-types))
+
+(defun denote--file-type-org-extra-p ()
+  "Return non-nil if this is an `org-capture' or Org Note buffer."
+  (and (derived-mode-p 'org-mode)
+       (or (and (bound-and-true-p org-capture-mode)
+                (string-match-p "\\`CAPTURE-.*" (buffer-name)))
+           (string-match-p "\\`\\*Org Note\\*" (buffer-name))
+           (null buffer-file-name))))
+
+(defun denote-file-type (file)
+  "Use the file extension to detect the file type of FILE.
+
+If more than one file type correspond to this file extension, use the
+first file type for which the :title-key-regexp in `denote-file-types'
+matches in the file.
+
+Return nil if the file type is not recognized."
+  (when-let* ((extension (denote-get-file-extension-sans-encryption file))
+              (types (denote--file-types-with-extension extension)))
+    (if (= (length types) 1)
+        (caar types)
+      (or (car (seq-find
+                (lambda (type)
+                  (denote--regexp-in-file-p (plist-get (cdr type) :title-key-regexp) file))
+                types))
+          (caar types)))))
+
+(defun denote-filetype-heuristics (file)
+  "Return likely file type of FILE.
+If in the process of `org-capture', consider the file type to be that of
+Org.  Otherwise, use the function `denote-file-type' to return the type."
+  (if (denote--file-type-org-extra-p)
+      'org
+    (denote-file-type file)))
+
+(defun denote--revert-dired (buf)
+  "Revert BUF if appropriate.
+Do it if BUF is in Dired mode and is either part of the variable
+`denote-directory' or the `current-buffer'."
+  (let ((current (current-buffer)))
+    (with-current-buffer buf
+      (when (and (eq major-mode 'dired-mode)
+                 (or (and default-directory (denote--dir-in-denote-directory-p default-directory))
+                     (eq current buf)))
+        (revert-buffer)))))
+
+(defun denote-update-dired-buffers ()
+  "Update Dired buffers of variable `denote-directory'.
+Also revert the current Dired buffer even if it is not inside the
+variable `denote-directory'."
+  (mapc #'denote--revert-dired (buffer-list)))
+
+(defun denote-rename-file-and-buffer (old-name new-name)
+  "Rename file named OLD-NAME to NEW-NAME, updating buffer name.
+
+If the file exists on the file system, it is renamed.  This
+function may be called when creating a new note and the file does
+not exist yet.
+
+If a buffer is visiting the file, its name is updated."
+  (unless (string= (expand-file-name old-name) (expand-file-name new-name))
+    (when (and (file-regular-p old-name)
+               (file-writable-p new-name))
+      (cond
+       ((derived-mode-p 'dired-mode)
+        (dired-rename-file old-name new-name nil))
+       ;; NOTE 2024-02-25: The `vc-rename-file' requires the file to be
+       ;; saved, but our convention is to not save the buffer after
+       ;; changing front matter unless we absolutely have to (allows
+       ;; users to do `diff-buffer-with-file', for example).
+       ((and denote-save-buffers (not (buffer-modified-p)) (vc-backend old-name))
+        (vc-rename-file old-name new-name))
+       (t
+        (rename-file old-name new-name nil))))
+    (when-let* ((buffer (find-buffer-visiting old-name)))
+      (with-current-buffer buffer
+        (set-visited-file-name new-name nil t)))))
+
+(define-obsolete-function-alias
+  'denote--add-front-matter
+  'denote-prepend-front-matter
+  "4.0.0")
+
+(defun denote-prepend-front-matter (file title keywords signature date id file-type)
+  "Prepend front matter to FILE.
+The TITLE, KEYWORDS, DATE, ID, SIGNATURE, and FILE-TYPE are passed from
+the renaming command and are used to construct a new front matter block
+if appropriate."
+  (when-let* ((new-front-matter (denote--format-front-matter title date keywords id signature file-type)))
+    (with-current-buffer (find-file-noselect file)
+      (goto-char (point-min))
+      (insert new-front-matter))))
+
+(defun denote--regexp-in-file-p (regexp file)
+  "Return t if REGEXP matches in the FILE."
+  (denote--file-with-temp-buffer file
+    (re-search-forward regexp nil t 1)))
+
+(defun denote-rewrite-keywords (file keywords file-type &optional save-buffer)
+  "Rewrite KEYWORDS in FILE outright according to FILE-TYPE.
+
+Do the same as `denote-rewrite-front-matter' for keywords,
+but do not ask for confirmation.
+
+With optional SAVE-BUFFER, save the buffer corresponding to FILE.
+
+This function is for use in the commands `denote-keywords-add',
+`denote-keywords-remove', `denote-dired-rename-files', or
+related."
+  (let* ((new-front-matter (denote--format-front-matter "" (current-time) keywords "" "" file-type))
+         (new-keywords-line (denote--retrieve-front-matter-keywords-line-from-content new-front-matter file-type)))
+    (with-current-buffer (find-file-noselect file)
+      (save-excursion
+        (save-restriction
+          (widen)
+          (goto-char (point-min))
+          (when (re-search-forward (denote--keywords-key-regexp file-type) nil t 1)
+            (goto-char (line-beginning-position))
+            (insert new-keywords-line)
+            (delete-region (point) (line-end-position))
+            (when save-buffer (save-buffer))))))))
+
+(defun denote--component-has-value-p (component value)
+  "Return non-nil if COMPONENT has a non-nil/non-empty VALUE.
+
+COMPONENT can be one of `title', `keywords', `signature', `date',
+`identifier'.
+
+VALUE is the corresponding value to test.
+
+This function returns nil given an empty string title, signature or
+identifier.  It also returns nil given a nil date or nil keywords."
+  (pcase component
+    ('title (not (string-empty-p value)))
+    ('keywords (not (null value)))
+    ('signature (not (string-empty-p (denote-sluggify-signature value))))
+    ('date (not (null value)))
+    ('identifier (not (string-empty-p value)))))
+
+(defun denote--get-old-and-new-front-matter-lines (file new-front-matter file-type)
+  "Return an alist of the old and new front-matter lines for each component.
+
+The FILE contains the old front matter lines.
+
+NEW-FRONT-MATTER is a the front matter with the new values, with the
+format given by FILE-TYPE."
+  `((title . ((old . ,(denote-retrieve-front-matter-title-line file file-type))
+              (new . ,(denote--retrieve-front-matter-title-line-from-content new-front-matter file-type))))
+    (keywords . ((old . ,(denote-retrieve-front-matter-keywords-line file file-type))
+                 (new . ,(denote--retrieve-front-matter-keywords-line-from-content new-front-matter file-type))))
+    (signature . ((old . ,(denote-retrieve-front-matter-signature-line file file-type))
+                  (new . ,(denote--retrieve-front-matter-signature-line-from-content new-front-matter file-type))))
+    (date . ((old . ,(denote-retrieve-front-matter-date-line file file-type))
+             (new . ,(denote--retrieve-front-matter-date-line-from-content new-front-matter file-type))))
+    (identifier . ((old . ,(denote-retrieve-front-matter-identifier-line file file-type))
+                   (new . ,(denote--retrieve-front-matter-identifier-line-from-content new-front-matter file-type))))))
+
+(defun denote--get-front-matter-components-order (content file-type)
+  "Return the components in the order they appear in CONTENT given FILE-TYPE.
+
+Return a list containing the symbols `title', `signature', `keywords',
+`identifier' and `date' in the order that they appear in TEXT.  TEXT can
+be any string.  For example, it can be a front matter template or an
+entire file content."
+  (let ((components-with-line-numbers '()))
+    (with-temp-buffer
+      (insert content)
+      (goto-char (point-min))
+      (when (re-search-forward (denote--title-key-regexp file-type) nil t 1)
+        (push `(,(line-number-at-pos) . title) components-with-line-numbers))
+      (goto-char (point-min))
+      (when (re-search-forward (denote--keywords-key-regexp file-type) nil t 1)
+        (push `(,(line-number-at-pos) . keywords) components-with-line-numbers))
+      (goto-char (point-min))
+      (when (re-search-forward (denote--signature-key-regexp file-type) nil t 1)
+        (push `(,(line-number-at-pos) . signature) components-with-line-numbers))
+      (goto-char (point-min))
+      (when (re-search-forward (denote--date-key-regexp file-type) nil t 1)
+        (push `(,(line-number-at-pos) . date) components-with-line-numbers))
+      (goto-char (point-min))
+      (when (re-search-forward (denote--identifier-key-regexp file-type) nil t 1)
+        (push `(,(line-number-at-pos) . identifier) components-with-line-numbers)))
+    (mapcar #'cdr
+            (sort components-with-line-numbers (lambda (x y) (< (car x) (car y)))))))
+
+(defun denote--file-has-front-matter-p (file file-type)
+  "Return non-nil if FILE has at least one front-matter line, given FILE-TYPE.
+
+This is checked against its front matter definition.  If the front matter
+definition has no lines, this function returns non-nil."
+  (let* ((front-matter (denote--front-matter file-type))
+         (file-content (with-current-buffer (find-file-noselect file) (buffer-string)))
+         (components-in-template (denote--get-front-matter-components-order front-matter file-type))
+         (components-in-file (denote--get-front-matter-components-order file-content file-type)))
+    (or (null components-in-template)
+        (seq-intersection components-in-template components-in-file))))
+
+(defun denote--get-front-matter-rewrite-prompt (final-components to-add to-remove to-modify old-and-new-front-matter-lines)
+  "Return the prompt for the front matter rewrite operation.
+
+FINAL-COMPONENTS is the list of components to handle at the end of the
+rewrite operation.
+
+TO-ADD, TO-REMOVE, and TO-MODIFY are the list of components that needs
+to be added, removed or modified.
+
+OLD-AND-NEW-FRONT-MATTER-LINES is an alist containing the old and new
+front matter lines."
+  (let ((prompt "Replace front matter?"))
+    (dolist (component final-components)
+      (let ((old-line (alist-get 'old (alist-get component old-and-new-front-matter-lines)))
+            (new-line (alist-get 'new (alist-get component old-and-new-front-matter-lines)))
+            (next-prompt ""))
+        (cond ((memq component to-remove)
+               (setq next-prompt (format "\n-%s\n"
+                                         (propertize old-line 'face 'denote-faces-prompt-old-name))))
+              ((memq component to-add)
+               (setq next-prompt (format "\n-%s\n"
+                                         (propertize new-line 'face 'denote-faces-prompt-new-name))))
+              ((memq component to-modify)
+               (setq next-prompt (format "\n-%s\n-%s\n"
+                                         (propertize old-line 'face 'denote-faces-prompt-old-name)
+                                         (propertize new-line 'face 'denote-faces-prompt-new-name)))))
+        (setq prompt (concat prompt next-prompt))))
+    (concat prompt "?")))
+
+(defun denote--get-final-components-for-rewrite (components-in-file components-in-template components-to-add)
+  "Return the final components to handle by a front matter rewrite operation.
+
+COMPONENTS-TO-ADD is the list of components that have to be added to
+COMPONENTS-IN-FILE to build the list of components that will need to be
+handled during a front matter rewrite operation.
+
+COMPONENTS-IN-TEMPLATE is the list of components in a front matter
+template.  They are used to determine how the COMPONENTS-TO-ADD are
+added to COMPONENTS-IN-FILE.
+
+Example:
+          file = (title signature)
+      template = (title keywords date id signature)
+
+The date line is missing from the file.  From the template, we find out
+that it needs to be added *after* a keywords line.  Since we don't have
+one in the file, we keep looking for a line to add it *after* and find a
+title line.  Had we not found the title line in the file, we would have
+searched for a line to insert it *before*.  We would have inserted the
+date line before the signature line, for example.
+
+This is repeated until all missing components are added."
+  (let ((final-components (copy-sequence components-in-file)))
+    (dolist (component components-to-add)
+      (if-let* ((previous-components-in-template
+                 (seq-take-while (lambda (x) (not (eq x component))) components-in-template))
+                (first-previous-component-in-file
+                 (seq-find (lambda (x) (memq x final-components)) (reverse previous-components-in-template))))
+          ;; Insert after the existing element.
+          (let ((sublist final-components))
+            (while sublist
+              (if (not (eq (car sublist) first-previous-component-in-file))
+                  (setq sublist (cdr sublist))
+                (push component (cdr sublist))
+                (setq sublist nil))))
+        (let* ((next-components-in-template
+                (cdr (seq-drop-while (lambda (x) (not (eq x component))) components-in-template)))
+               (first-next-component-in-file
+                (seq-find (lambda (x) (memq x final-components)) next-components-in-template)))
+          ;; Insert before the existing element.  The intention is to
+          ;; modify final-components, but it does not work when push
+          ;; is called on sublist on the first iteration of the loop.
+          (if (eq (car final-components) first-next-component-in-file)
+              (push component final-components)
+            (let ((sublist final-components))
+              (while sublist
+                (if (not (eq (car sublist) first-next-component-in-file))
+                    (setq sublist (cdr sublist))
+                  (push component sublist)
+                  (setq sublist nil))))))))
+    final-components))
+
+(defun denote-rewrite-front-matter (file title keywords signature date identifier file-type)
+  "Rewrite front matter of note after `denote-rename-file'.
+The FILE, TITLE, KEYWORDS, SIGNATURE, DATE, IDENTIFIER, and FILE-TYPE
+are given by the renaming command and are used to construct new front
+matter values if appropriate.
+
+If `denote-rename-confirmations' contains `rewrite-front-matter',
+prompt to confirm the rewriting of the front matter."
+  (let* ((front-matter (denote--front-matter file-type))
+         (file-content (with-current-buffer (find-file-noselect file) (buffer-string)))
+         (components-in-template (denote--get-front-matter-components-order front-matter file-type))
+         (components-in-file (denote--get-front-matter-components-order file-content file-type))
+         (components-to-add '())
+         (components-to-remove '())
+         (components-to-modify '())
+         (new-front-matter (denote--format-front-matter title date keywords identifier signature file-type))
+         (old-and-new-front-matter-lines (denote--get-old-and-new-front-matter-lines file new-front-matter file-type)))
+    ;; Build the lists of components to add, remove, modify.
+    (dolist (component '(title keywords signature identifier date))
+      ;; Ignore the component if it is not in the template.  It is not added, removed or modified.
+      (when (memq component components-in-template)
+        (let ((value (pcase component ('title title) ('keywords keywords) ('signature signature) ('date date) ('identifier identifier))))
+          (cond ((and (not (memq component components-in-file))
+                      (denote--component-has-value-p component value))
+                 (push component components-to-add))
+                ((and (memq component components-in-file)
+                      ;; The component can still be marked for modification.
+                      (not (memq component denote-front-matter-components-present-even-if-empty-value))
+                      (not (denote--component-has-value-p component value)))
+                 (push component components-to-remove))
+                ((and (memq component components-in-file)
+                      (not (string= (alist-get 'old (alist-get component old-and-new-front-matter-lines))
+                                    (alist-get 'new (alist-get component old-and-new-front-matter-lines)))))
+                 (push component components-to-modify))))))
+    ;; There should be at least one component in the file and the template.
+    (when (and (seq-intersection components-in-file components-in-template)
+               (or components-to-add components-to-remove components-to-modify))
+      (when-let* ((final-components (denote--get-final-components-for-rewrite
+                                     components-in-file components-in-template components-to-add)))
+        (with-current-buffer (find-file-noselect file)
+          (when (or (not (memq 'rewrite-front-matter denote-rename-confirmations))
+                    (y-or-n-p (denote--get-front-matter-rewrite-prompt
+                               final-components
+                               components-to-add components-to-remove components-to-modify
+                               old-and-new-front-matter-lines)))
+            (save-excursion
+              (save-restriction
+                (widen)
+                (goto-char (point-min))
+                ;; Position point at the beginning of the first front matter line
+                (let ((first-component (car (seq-difference final-components components-to-add))))
+                  (re-search-forward
+                   (funcall (denote--get-component-key-regexp-function first-component) file-type) nil t 1)
+                  (goto-char (line-beginning-position)))
+                ;; Do the modifications
+                (dolist (component final-components)
+                  (let ((component-key-regexp-function (denote--get-component-key-regexp-function component))
+                        (new-line (alist-get 'new (alist-get component old-and-new-front-matter-lines))))
+                    (cond ((memq component components-to-remove)
+                           (re-search-forward (funcall component-key-regexp-function file-type) nil t 1)
+                           (delete-region (line-beginning-position) (line-beginning-position 2)))
+                          ((memq component components-to-add)
+                           (insert (concat new-line "\n")))
+                          ((memq component components-to-modify)
+                           (re-search-forward (funcall component-key-regexp-function file-type) nil t 1)
+                           (goto-char (line-beginning-position))
+                           (insert new-line)
+                           (delete-region (point) (line-end-position))
+                           (goto-char (line-beginning-position 2)))
+                          (t
+                           (goto-char (line-beginning-position 2))))))))))))))
+
+;;;;; The renaming commands and their prompts
+
+(defun denote--rename-dired-file-or-current-file-or-prompt ()
+  "Return Dired file at point or the current file, else prompt for one.
+Throw error if FILE is not regular, else return FILE."
+  (or (dired-get-filename nil t)
+      buffer-file-name
+      (let* ((file (buffer-file-name))
+             (format (if file
+                         (format "Rename FILE Denote-style [%s]: " file)
+                       "Rename FILE Denote-style: "))
+             (selected-file (read-file-name format nil file t nil)))
+        (if (or (file-directory-p selected-file)
+                (not (file-regular-p selected-file)))
+            (user-error "Only rename regular files")
+          selected-file))))
+
+(defun denote-rename-file-prompt (old-name new-name)
+  "Prompt to rename file named OLD-NAME to NEW-NAME.
+Return non-nil if the file should be renamed.
+
+If `denote-rename-confirmations' does not contain
+`modify-file-name', return t without prompting."
+  (or (not (memq 'modify-file-name denote-rename-confirmations))
+      (unless (string= (expand-file-name old-name) (expand-file-name new-name))
+        (y-or-n-p
+         (format "Rename %s to %s?"
+                 (propertize (file-name-nondirectory old-name) 'face 'denote-faces-prompt-old-name)
+                 (propertize (file-name-nondirectory new-name) 'face 'denote-faces-prompt-new-name))))))
+
+(defun denote-add-front-matter-prompt (file)
+  "Prompt to add a front-matter to FILE.
+Return non-nil if a new front matter should be added.
+
+If `denote-rename-confirmations' does not contain
+`add-front-matter', return t without prompting."
+  (or (not (memq 'add-front-matter denote-rename-confirmations))
+      (y-or-n-p
+       (format "Add new front matter to %s?"
+               (propertize (file-name-nondirectory file) 'face 'denote-faces-prompt-new-name)))))
+
+;; NOTE 2023-10-20: We do not need a user option for this, though it
+;; can be useful to have it as a variable.
+(defvar denote-rename-max-mini-window-height 0.33
+  "How much to enlarge `max-mini-window-height' for renaming operations.")
+
+(defun denote--generate-date-for-rename (file)
+  "Generate a date for FILE.
+
+Respect `denote-generate-identifier-automatically'."
+  (if (or (eq denote-generate-identifier-automatically t)
+          (eq denote-generate-identifier-automatically 'on-rename))
+      (or (file-attribute-modification-time (file-attributes file))
+          (current-time))
+    nil))
+
+(defun denote--rename-file (file title keywords signature date)
+  "Rename FILE according to the other parameters.
+Parameters TITLE, KEYWORDS, SIGNATURE and DATE are as described
+in `denote-rename-file' and are assumed to be valid (TITLE and
+SIGNATURE are strings, KEYWORDS is a list, etc.).
+
+This function only does the work necessary to rename a file
+according to its parameters.  In particular, it does not prompt
+for anything.  It is meant to be combined with
+`denote--rename-get-file-info-from-prompts-or-existing' to create
+a renaming command.
+
+Respect `denote-rename-confirmations', `denote-save-buffers' and
+`denote-kill-buffers'."
+  (let* ((initial-state (if (find-buffer-visiting file) 'visited 'not-visited))
+         (file-type (denote-filetype-heuristics file))
+         (keywords (denote-keywords-sort keywords))
+         (directory (file-name-directory file))
+         (extension (denote-get-file-extension file))
+         (date (or date (denote--generate-date-for-rename file)))
+         (old-id (or (denote-retrieve-filename-identifier file) ""))
+         (id (denote-get-identifier date))
+         (id (cond ((or (string-empty-p id) (string= old-id id))
+                    id)
+                   ((and (not (string-empty-p old-id)) (denote--file-has-backlinks-p file))
+                    (user-error "The date cannot be modified because the file has backlinks"))
+                   (t
+                    (denote--find-first-unused-id id))))
+         (date (if (string-empty-p id) nil (date-to-time id)))
+         (new-name (denote-format-file-name directory id keywords title extension signature))
+         (max-mini-window-height denote-rename-max-mini-window-height))
+    (when (and (file-regular-p new-name)
+               (not (string= (expand-file-name file) (expand-file-name new-name))))
+      (user-error "The destination file `%s' already exists" new-name))
+    ;; Modify file name, buffer name, or both
+    (when (denote-rename-file-prompt file new-name)
+      (denote-rename-file-and-buffer file new-name))
+    ;; Handle front matter if new-name is of a supported type (rewrite or add front matter)
+    (when (and (denote-file-has-supported-extension-p file)
+               (denote-file-is-writable-and-supported-p new-name))
+      (if (denote--file-has-front-matter-p new-name file-type)
+          (denote-rewrite-front-matter new-name title keywords signature date id file-type)
+        (when (denote-add-front-matter-prompt new-name)
+          (denote-prepend-front-matter new-name title keywords signature date id file-type))))
+    (when (and denote--used-ids (not (string-empty-p id)))
+      (puthash id t denote--used-ids))
+    (denote--handle-save-and-kill-buffer 'rename new-name initial-state)
+    (setq denote-current-data
+          (list
+           (cons 'title title)
+           (cons 'keywords keywords)
+           (cons 'signature signature)
+           (cons 'directory directory)
+           (cons 'date date)
+           (cons 'id id)
+           (cons 'file-type file-type)
+           (cons 'template "")))
+    (run-hooks 'denote-after-rename-file-hook)
+    new-name))
+
+(defun denote--rename-get-file-info-from-prompts-or-existing (file)
+  "Retrieve existing info from FILE and prompt according to `denote-prompts'.
+
+It is meant to be combined with `denote--rename-file' to create
+renaming commands."
+  (let* ((file-in-prompt (propertize (file-relative-name file) 'face 'denote-faces-prompt-current-name))
+         (file-type (denote-filetype-heuristics file))
+         (id (or (denote-retrieve-filename-identifier file) ""))
+         (date (or (denote-valid-date-p id) (denote--generate-date-for-rename file)))
+         (title (or (denote-retrieve-title-or-filename file file-type) ""))
+         (keywords (denote-extract-keywords-from-path file))
+         (signature (or (denote-retrieve-filename-signature file) "")))
+    (dolist (prompt denote-prompts)
+      (pcase prompt
+        ('title
+         (setq title (denote-title-prompt
+                      title
+                      (format "Rename `%s' with TITLE (empty to remove)" file-in-prompt))))
+        ('keywords
+         (setq keywords (denote-keywords-prompt
+                         (format "Rename `%s' with KEYWORDS (empty to remove)" file-in-prompt)
+                         (string-join keywords ","))))
+        ('signature
+         (setq signature (denote-signature-prompt
+                          signature
+                          (format "Rename `%s' with SIGNATURE (empty to remove)" file-in-prompt))))
+        ('date
+         (setq date (denote-valid-date-p (denote-date-prompt
+                                          date
+                                          (format "Rename `%s' with DATE" file-in-prompt)))))))
+    (list title keywords signature date)))
+
+;;;###autoload
+(defun denote-rename-file (file title keywords signature date)
+  "Rename file and update existing front matter if appropriate.
+
+Always rename the file where it is located in the file system:
+never move it to another directory.
+
+If in Dired, consider FILE to be the one at point, else the
+current file, else prompt with minibuffer completion for one.
+When called from Lisp, FILE is a file system path represented as
+a string.
+
+If FILE has a Denote-compliant identifier, retain it while
+updating components of the file name referenced by the user
+option `denote-prompts'.  By default, these are the TITLE and
+KEYWORDS.  The SIGNATURE is another one.  When called from Lisp,
+TITLE and SIGNATURE are strings, while KEYWORDS is a list of
+strings.
+
+If there is no identifier, create an identifier based on the
+following conditions:
+
+1. If the `denote-prompts' includes an entry for date prompts,
+   then prompt for DATE and take its input to produce a new
+   identifier.  For use in Lisp, DATE must conform with
+   `denote-valid-date-p'.
+
+2. If DATE is nil (e.g. when `denote-prompts' does not include a
+   date entry), use the file attributes to determine the last
+   modified date of FILE and format it as an identifier.
+
+3. As a fallback, derive an identifier from the current date and
+   time.
+
+4. At any rate, if the resulting identifier is not unique among
+   the files in the variable `denote-directory', increment it
+   such that it becomes unique.
+
+In interactive use, and assuming `denote-prompts' includes a
+title entry, make the TITLE prompt have prefilled text in the
+minibuffer that consists of the current title of FILE.  The
+current title is either retrieved from the front matter (such as
+the #+title in Org) or from the file name.
+
+Do the same for the SIGNATURE prompt, subject to `denote-prompts',
+by prefilling the minibuffer with the current signature of FILE,
+if any.
+
+Same principle for the KEYWORDS prompt: convert the keywords in
+the file name into a comma-separated string and prefill the
+minibuffer with it (the KEYWORDS prompt accepts more than one
+keywords, each separated by a comma, else the `crm-separator').
+
+For all prompts, interpret an empty input as an instruction to
+remove that file name component.  For example, if a TITLE prompt
+is available and FILE is 20240211T093531--some-title__keyword1.org
+then rename FILE to 20240211T093531__keyword1.org.
+
+In interactive use, if there is no entry for a file name
+component in `denote-prompts', keep it as-is.
+
+When called from Lisp, the special symbol `keep-current' can be
+used for the TITLE, KEYWORDS, SIGNATURE and DATE parameters to
+keep them as-is.
+
+[ NOTE: Please check with your minibuffer user interface how to
+  provide an empty input.  The Emacs default setup accepts the
+  empty minibuffer contents as they are, though popular packages
+  like `vertico' use the first available completion candidate
+  instead.  For `vertico', the user must either move one up to
+  select the prompt and then type RET there with empty contents,
+  or use the command `vertico-exit-input' with empty contents.
+  That Vertico command is bound to M-RET as of this writing on
+  2024-02-13 08:08 +0200. ]
+
+As a final step, ask for confirmation, showing the difference
+between old and new file names.  Do not ask for confirmation if
+the user option `denote-rename-confirmations' does not contain
+the symbol `modify-file-name'.
+
+If FILE has front matter for TITLE and KEYWORDS, ask to rewrite
+their values in order to reflect the new input, unless
+`denote-rename-confirmations' lacks `rewrite-front-matter'.  When
+the `denote-save-buffers' is nil (the default), do not save the
+underlying buffer, thus giving the user the option to
+double-check the result, such as by invoking the command
+`diff-buffer-with-file'.  The rewrite of the TITLE and KEYWORDS
+in the front matter should not affect the rest of the front
+matter.
+
+If the file does not have front matter but is among the supported file
+types (per the user option `denote-file-type'), add front matter to the
+top of it and leave the buffer unsaved for further inspection.  Save the
+buffer if `denote-save-buffers' is non-nil.
+
+When `denote-kill-buffers' is t or `on-rename', kill the buffer
+if it was not already being visited before the rename operation.
+
+For the front matter of each file type, refer to the variables:
+
+- `denote-org-front-matter'
+- `denote-text-front-matter'
+- `denote-toml-front-matter'
+- `denote-yaml-front-matter'
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'.
+
+Run the `denote-after-rename-file-hook' after renaming FILE.
+
+This command is intended to (i) rename Denote files, (ii) convert
+existing supported file types to Denote notes, and (ii) rename
+non-note files (e.g. PDF) that can benefit from Denote's
+file-naming scheme.
+
+For a version of this command that works with multiple files
+one-by-one, use `denote-dired-rename-files'."
+  (interactive
+   (let* ((file (denote--rename-dired-file-or-current-file-or-prompt)))
+     (append (list file) (denote--rename-get-file-info-from-prompts-or-existing file))))
+  (let* ((file-type (denote-filetype-heuristics file))
+         (title (if (eq title 'keep-current)
+                    (or (denote-retrieve-title-or-filename file file-type) "")
+                  title))
+         (keywords (if (eq keywords 'keep-current)
+                       (denote-extract-keywords-from-path file)
+                     keywords))
+         (signature (if (eq signature 'keep-current)
+                        (or (denote-retrieve-filename-signature file) "")
+                      signature))
+         (date (if (eq date 'keep-current)
+                   (denote-retrieve-filename-identifier file)
+                 date))
+         ;; Make the data valid
+         (date (denote-valid-date-p date))
+         (new-name (denote--rename-file file title keywords signature date)))
+    (denote-update-dired-buffers)
+    new-name))
+
+(defun denote-rename-file-title ()
+  "Convenience command to change the title of a file.
+Like `denote-rename-file', but prompts only for the title.
+
+Add or remove a title in one go.  Do this by prepopulating the
+minibuffer prompt with the existing title.  The user can then modify it
+accordingly.  An empty input means to remove the title altogether.
+
+Please check the documentation of `denote-rename-file' with regard to
+how a completion User Interface may accept an empty input."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts '(title)))
+    (call-interactively #'denote-rename-file)))
+
+(defun denote-rename-file-keywords ()
+  "Convenience command to change the keywords of a file.
+Like `denote-rename-file', but prompts only for keywords.
+
+Add or remove keywords in one go.  Do this by prepopulating the
+minibuffer prompt with the existing keywords.  The user can then insert
+the `crm-separator' (normally a comma), to write new keywords or edit
+what is in the prompt to rewrite them accordingly.  An empty input means
+to remove all keywords.
+
+Please check the documentation of `denote-rename-file' with regard to
+how a completion User Interface may accept an empty input."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts '(keywords)))
+    (call-interactively #'denote-rename-file)))
+
+(defun denote-rename-file-date ()
+  "Convenience command to change the date of a file.
+Like `denote-rename-file', but prompts only for the date.
+
+Modify a date in one go."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts '(date)))
+    (call-interactively #'denote-rename-file)))
+
+(define-obsolete-function-alias 'denote-keywords-add 'denote-rename-file-keywords "3.0.0")
+(define-obsolete-function-alias 'denote-rename-add-keywords 'denote-rename-file-keywords "3.0.0")
+(define-obsolete-function-alias 'denote-keywords-remove 'denote-rename-file-keywords "3.0.0")
+(define-obsolete-function-alias 'denote-rename-rename-keywords 'denote-rename-file-keywords "3.0.0")
+
+(defun denote-rename-file-signature ()
+  "Convenience command to change the signature of a file.
+Like `denote-rename-file', but prompts only for the signature.
+
+Add or remove a signature in one go.  Do this by prepopulating the
+minibuffer prompt with the existing signature.  The user can then modify
+it accordingly.  An empty input means to remove the signature
+altogether.
+
+Please check the documentation of `denote-rename-file' with regard to
+how a completion User Interface may accept an empty input."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts '(signature)))
+    (call-interactively #'denote-rename-file)))
+
+(define-obsolete-function-alias 'denote-add-signature 'denote-rename-file-signature "3.0.0")
+(define-obsolete-function-alias 'denote-remove-signature 'denote-rename-file-signature "3.0.0")
+
+;;;###autoload
+(defun denote-dired-rename-files ()
+  "Rename Dired marked files same way as `denote-rename-file'.
+Rename each file in sequence, making all the relevant prompts.
+Unlike `denote-rename-file', do not prompt for confirmation of
+the changes made to the file: perform them outright (same as
+setting `denote-rename-confirmations' to a nil value)."
+  (declare (interactive-only t))
+  (interactive nil dired-mode)
+  (let ((denote--used-ids (denote--get-all-used-ids))
+        (denote-rename-confirmations nil))
+    (if-let* ((marks (dired-get-marked-files)))
+        (progn
+          (dolist (file marks)
+            (pcase-let ((`(,title ,keywords ,signature ,date)
+                         (denote--rename-get-file-info-from-prompts-or-existing file)))
+              (denote--rename-file file title keywords signature date)))
+          (denote-update-dired-buffers))
+      (user-error "No marked files; aborting"))))
+
+(defalias 'denote-dired-rename-marked-files 'denote-dired-rename-files
+  "Alias for `denote-dired-rename-files'.")
+
+(defun denote-keywords--combine (combination-type user-input-keywords keywords)
+  "COMBINATION-TYPE is either `:add', `:remove' or `:replace'.
+
+USER-INPUT-KEYWORDS are new keywords collected from the end-user.
+KEYWORDS are the existing keywords for the underlying file.
+
+This function is an internal implementation function."
+  (cond
+   ((eq combination-type :add)
+    (seq-union keywords user-input-keywords))
+   ((eq combination-type :replace)
+    user-input-keywords)
+   ((eq combination-type :remove)
+    (seq-difference keywords user-input-keywords))
+   (t
+    (error "Unknown operation in denote-keywords--combine: %s"
+           combination-type))))
+
+(defun denote-dired-rename-marked-files--change-keywords (combination-type keywords-prompt)
+  "COMBINATION-TYPE is either `:add', `:remove' or `:replace'.
+
+KEYWORDS-PROMPT is the prompt we show the end-user, when taking keywords
+as input.
+
+This function is an internal implementation function."
+  (if-let* ((marks (dired-get-marked-files)))
+      (let ((denote-prompts '())
+            (denote-rename-confirmations nil)
+            (user-input-keywords (denote-keywords-prompt keywords-prompt))
+            (denote--used-ids (denote--get-all-used-ids)))
+        (dolist (file marks)
+          (pcase-let* ((`(,title ,keywords ,signature ,date)
+                        (denote--rename-get-file-info-from-prompts-or-existing file))
+                       (new-keywords (denote-keywords-sort (denote-keywords--combine combination-type user-input-keywords keywords))))
+            (denote--rename-file file title new-keywords signature date)))
+        (denote-update-dired-buffers))
+    (user-error "No marked files; aborting")))
+
+;;;###autoload
+(defun denote-dired-rename-marked-files-with-keywords ()
+  "Rename marked files in Dired to a Denote file name by writing keywords.
+
+Specifically, do the following:
+
+- retain the file's existing name and make it the TITLE field,
+  per Denote's file-naming scheme;
+
+- sluggify the TITLE, according to our conventions (check the
+  user option `denote-file-name-slug-functions');
+
+- prepend an identifier to the TITLE;
+
+- preserve the file's extension, if any;
+
+- prompt once for KEYWORDS and apply the user's input to the
+  corresponding field in the file name, rewriting any keywords
+  that may exist while removing keywords that do exist if
+  KEYWORDS is empty;
+
+- add or rewrite existing front matter to the underlying file, if it is
+  recognized as a Denote note (per the user option `denote-file-type'),
+  such that it includes the new keywords.
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'.
+
+Run the `denote-after-rename-file-hook' after renaming is done.
+
+Also see the specialized commands to only add or remove keywords:
+
+- `denote-dired-rename-marked-files-add-keywords'.
+- `denote-dired-rename-marked-files-remove-keywords'."
+  (declare (interactive-only t))
+  (interactive nil dired-mode)
+  (denote-dired-rename-marked-files--change-keywords
+   :replace "Rename marked files with KEYWORDS, overwriting existing (empty to ignore/remove)"))
+
+;;;###autoload
+(defun denote-dired-rename-marked-files-add-keywords ()
+  "Like `denote-dired-rename-marked-files-with-keywords' to only add keywords."
+  (declare (interactive-only t))
+  (interactive nil dired-mode)
+  (denote-dired-rename-marked-files--change-keywords
+   :add "Add KEYWORDS to marked files"))
+
+;;;###autoload
+(defun denote-dired-rename-marked-files-remove-keywords ()
+  "Like `denote-dired-rename-marked-files-with-keywords' to only remove keywords."
+  (declare (interactive-only t))
+  (interactive nil dired-mode)
+  (denote-dired-rename-marked-files--change-keywords
+   :remove "Remove KEYWORDS from marked files"))
+
+;;;###autoload
+(defun denote-rename-file-using-front-matter (file)
+  "Rename FILE using its front matter as input.
+When called interactively, FILE is the variable `buffer-file-name' or
+the Dired file at point, which is subsequently inspected for the
+requisite front matter.  It is thus implied that the FILE has a file
+type that is supported by Denote, per the user option `denote-file-type'.
+
+The values of `denote-rename-confirmations',
+`denote-save-buffers' and `denote-kill-buffers' are respected.
+
+Only the front matter lines that appear in the front matter template (as
+defined in `denote-file-types') will be handled.
+
+To change the identifier (date) of the note with this command, the
+identifier line (if present) of the front matter must be modified.
+Modifying the date line has no effect.
+
+While this command generally does not modify the front matter, there are
+exceptions.  The value of the `date' line will follow that of the
+`identifier' line.  If they are both in the front matter template and
+the `date' line is missing, it will be added again.  Similarly, if they
+are both in the front matter template and the `date' line is present and
+the `identifier' line has been removed, the `date' line will be removed
+as well.  Also, if the keywords are out of order and
+`denote-sort-keywords' is non-nil, they will be sorted.  There will be a
+prompt for this if `denote-rename-confirmations' contains
+`rewrite-front-matter'.
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'."
+  (interactive (list (or (dired-get-filename nil t) buffer-file-name)))
+  (unless (denote-file-is-writable-and-supported-p file)
+    (user-error "The file is not writable or does not have a supported file extension"))
+  (let ((file-type (denote-filetype-heuristics file)))
+    (unless (denote--file-has-front-matter-p file file-type)
+      (user-error "The file does not appear to have a front matter"))
+    (let* ((front-matter-template (denote--front-matter file-type))
+           (components-in-template (denote--get-front-matter-components-order front-matter-template file-type))
+           (title (if (memq 'title components-in-template)
+                      (or (denote-retrieve-front-matter-title-value file file-type) "")
+                    (or (denote-retrieve-filename-title file) "")))
+           (keywords (if (memq 'keywords components-in-template)
+                         (denote-retrieve-front-matter-keywords-value file file-type)
+                       (denote-retrieve-filename-keywords-as-list file)))
+           (signature (if (memq 'signature components-in-template)
+                          (or (denote-retrieve-front-matter-signature-value file file-type) "")
+                        (or (denote-retrieve-filename-signature file) "")))
+           ;; We need to use the identifier because the date line may
+           ;; not contain all the information.  For example,
+           ;; "2024-01-01" does not have the time of the note.
+           (date (if (memq 'identifier components-in-template)
+                     (when-let* ((id-value (denote-retrieve-front-matter-identifier-value file file-type)))
+                       (denote-valid-date-p id-value))
+                   (denote-valid-date-p (or (denote-retrieve-filename-identifier file) "")))))
+      (denote--rename-file file title keywords signature date)
+      (denote-update-dired-buffers))))
+
+;;;###autoload
+(defun denote-dired-rename-marked-files-using-front-matter ()
+  "Call `denote-rename-file-using-front-matter' over the Dired marked files.
+Refer to the documentation of that command for the technicalities.
+
+Marked files must count as notes for the purposes of Denote, which means
+that they at least have an identifier in their file name and use a
+supported file type, per the user option `denote-file-type'.  Files that
+do not meet this criterion are ignored because Denote cannot know if
+they have front matter and what that may be."
+  (interactive nil dired-mode)
+  (if-let* ((marks (seq-filter
+                    (lambda (m)
+                      (and (file-regular-p m)
+                           (denote-file-is-writable-and-supported-p m)
+                           (denote-file-has-identifier-p m)))
+                    (dired-get-marked-files))))
+      (let ((denote--used-ids (denote--get-all-used-ids)))
+        (dolist (file marks)
+          (denote-rename-file-using-front-matter file))
+        (denote-update-dired-buffers))
+    (user-error "No marked Denote files; aborting")))
+
+;;;;; Creation of front matter
+
+(make-obsolete 'denote-add-front-matter nil "Use `denote-rename-file' or related. Starting with version 4.0.0.")
+
+;;;###autoload
+(defun denote-change-file-type-and-front-matter (file new-file-type)
+  "Change file type of FILE and add an appropriate front matter.
+
+If in Dired, consider FILE to be the one at point, else the
+current file, else prompt with minibuffer completion for one.
+
+Add a front matter in the format of the NEW-FILE-TYPE at the
+beginning of the file.
+
+Retrieve the title of FILE from a line starting with a title
+field in its front matter, depending on the previous file
+type (e.g.  #+title for Org).  The same process applies for
+keywords.
+
+As a final step, ask for confirmation, showing the difference
+between old and new file names.
+
+Important note: No attempt is made to modify any other elements
+of the file.  This needs to be done manually.
+
+Construct the file name in accordance with the user option
+`denote-file-name-components-order'."
+  (interactive
+   (list
+    (denote--rename-dired-file-or-current-file-or-prompt)
+    (denote--valid-file-type (or (denote-file-type-prompt) denote-file-type))))
+  (let* ((initial-state (if (find-buffer-visiting file) 'visited 'not-visited))
+         (dir (file-name-directory file))
+         (old-file-type (denote-filetype-heuristics file))
+         (id (or (denote-retrieve-filename-identifier file) ""))
+         (date (if (string-empty-p id) nil (date-to-time id)))
+         (title (or (denote-retrieve-title-or-filename file old-file-type) ""))
+         (keywords (denote-retrieve-front-matter-keywords-value file old-file-type))
+         (signature (or (denote-retrieve-filename-signature file) ""))
+         (new-extension (denote--file-extension new-file-type))
+         (new-name (denote-format-file-name dir id keywords title new-extension signature))
+         (max-mini-window-height denote-rename-max-mini-window-height))
+    (when (denote-rename-file-prompt file new-name)
+      (denote-rename-file-and-buffer file new-name)
+      (denote-update-dired-buffers)
+      (when (and (denote-file-is-writable-and-supported-p new-name)
+                 (denote-add-front-matter-prompt new-name))
+        (denote-prepend-front-matter new-name title keywords signature date id new-file-type)
+        (denote--handle-save-and-kill-buffer 'rename new-name initial-state)))))
+
+;;;; The Denote faces
+
+(defgroup denote-faces ()
+  "Faces for Denote."
+  :group 'denote)
+
+(defface denote-faces-link '((t :inherit link))
+  "Face used to style Denote links in the buffer."
+  :group 'denote-faces
+  :package-version '(denote . "0.5.0"))
+
+(defface denote-faces-query-link '((t :inherit link-visited))
+  "Face used to style Denote query links in the buffer."
+  :group 'denote-faces
+  :package-version '(denote . "4.0.0"))
+
+(defface denote-faces-subdirectory '((t :inherit bold))
+  "Face for subdirectory of file name.
+This should only ever needed in the backlinks' buffer (or
+equivalent), not in Dired."
+  :group 'denote-faces
+  :package-version '(denote . "0.2.0"))
+
+(defface denote-faces-date '((t :inherit font-lock-variable-name-face))
+  "Face for file name date in Dired buffers.
+This is the part of the identifier that covers the year, month,
+and day."
+  :group 'denote-faces
+  :package-version '(denote . "0.1.0"))
+
+(defface denote-faces-time '((t :inherit denote-faces-date))
+  "Face for file name time in Dired buffers.
+This is the part of the identifier that covers the hours, minutes,
+and seconds."
+  :group 'denote-faces
+  :package-version '(denote . "0.1.0"))
+
+(defface denote-faces-title nil
+  "Face for file name title in Dired buffers."
+  :group 'denote-faces
+  :package-version '(denote . "0.1.0"))
+
+(defface denote-faces-year '((t :inherit denote-faces-date))
+  "Face for file name year in Dired buffers.
+This is the part of the identifier that covers the year, month, and day."
+  :group 'denote-faces
+  :package-version '(denote . "2.3.0"))
+
+(defface denote-faces-month '((t :inherit denote-faces-date))
+  "Face for file name month in Dired buffers.
+This is the part of the identifier that covers the year, month, and day."
+  :group 'denote-faces
+  :package-version '(denote . "2.3.0"))
+
+(defface denote-faces-day '((t :inherit denote-faces-date))
+  "Face for file name day in Dired buffers.
+This is the part of the identifier that covers the year, month, and day."
+  :group 'denote-faces
+  :package-version '(denote . "2.3.0"))
+
+(defface denote-faces-hour '((t :inherit denote-faces-date))
+  "Face for file name hours in Dired buffers.
+This is the part of the identifier that covers the hours, minutes,
+and seconds."
+  :group 'denote-faces
+  :package-version '(denote . "2.3.0"))
+
+(defface denote-faces-minute '((t :inherit denote-faces-date))
+  "Face for file name minutes in Dired buffers.
+This is the part of the identifier that covers the hours, minutes,
+and seconds."
+  :group 'denote-faces
+  :package-version '(denote . "2.3.0"))
+
+(defface denote-faces-second '((t :inherit denote-faces-date))
+  "Face for file name seconds in Dired buffers.
+This is the part of the identifier that covers the hours, minutes,
+and seconds."
+  :group 'denote-faces
+  :package-version '(denote . "2.3.0"))
+
+(defface denote-faces-extension '((t :inherit shadow))
+  "Face for file extension type in Dired buffers."
+  :group 'denote-faces
+  :package-version '(denote . "0.1.0"))
+
+(defface denote-faces-keywords '((t :inherit font-lock-builtin-face))
+  "Face for file name keywords in Dired buffers."
+  :group 'denote-faces
+  :package-version '(denote . "0.1.0"))
+
+(defface denote-faces-signature '((t :inherit font-lock-warning-face))
+  "Face for file name signature in Dired buffers."
+  :group 'denote-faces
+  :package-version '(denote . "2.0.0"))
+
+(defface denote-faces-delimiter
+  '((((class color) (min-colors 88) (background light))
+     :foreground "gray70")
+    (((class color) (min-colors 88) (background dark))
+     :foreground "gray30")
+    (t :inherit shadow))
+  "Face for file name delimiters in Dired buffers."
+  :group 'denote-faces
+  :package-version '(denote . "0.1.0"))
+
+(defface denote-faces-time-delimiter '((t :inherit shadow))
+  "Face for the delimiter between date and time in Dired buffers."
+  :group 'denote-faces
+  :package-version '(denote . "2.1.0"))
+
+;; The following matchers must obey the doc of `font-lock-keywords':
+;;   - Have one parameter, the limit of the search
+;;   - Set match-data (and restore it on failure)
+;;   - Move point after the match (or restore it on failure).
+;;   - Return t on success and nil on failure. re-search-forward returns (point) on success. It may be better to do the same.
+
+(defun denote-faces-dired-file-name-matcher (limit)
+  "Find the file name in a Dired line, not looking beyond LIMIT."
+  (let ((initial-match-data (match-data))
+        (initial-point (point))
+        (line-found nil))
+    ;; Find the next non empty line that contains a Dired file name
+    (while (and (not line-found)
+                (re-search-forward "^.+$" limit t))
+      ;; dired-move-to-filename moves the point even if it returns nil
+      (let ((saved-point (point)))
+        (if (and (dired-move-to-filename)
+                 (save-match-data
+                   (denote-file-has-denoted-filename-p (buffer-substring (point) (line-end-position)))))
+            (setq line-found t)
+          (goto-char saved-point))))
+    (if line-found
+        (let ((beginning-point (point)))
+          (goto-char (match-end 0))
+          (set-match-data (list beginning-point (match-end 0)))
+          (point))
+      (goto-char initial-point)
+      (set-match-data initial-match-data)
+      nil)))
+
+(defun denote-faces-directory-matcher (limit)
+  "Match the directory in a Dired line, not looking beyond LIMIT."
+  (let ((initial-match-data (match-data))
+        (initial-point (point)))
+    (if (re-search-forward "\\(?1:.*/\\)[^/]*$" limit t)
+        (progn
+          (goto-char (match-end 1))
+          (set-match-data (list (match-beginning 1) (match-end 1)))
+          (point))
+      (goto-char initial-point)
+      (set-match-data initial-match-data)
+      nil)))
+
+(defun denote-faces-signature-matcher (limit)
+  "Match the signature in a Dired line, not looking beyond LIMIT."
+  (let ((initial-match-data (match-data))
+        (initial-point (point)))
+    (if (or (re-search-forward "==\\(?1:[^/]*?\\)\\(@@\\|--\\|__\\|==\\|\\.\\)[^/]*$" limit t)
+            (re-search-forward "==\\(?1:[^/]*\\)$" limit t))
+        (progn
+          (goto-char (match-end 1))
+          (set-match-data (list (match-beginning 1) (match-end 1)))
+          (point))
+      (goto-char initial-point)
+      (set-match-data initial-match-data)
+      nil)))
+
+(defun denote-faces-identifier-matcher (limit)
+  "Match a general identifier in a Dired line, not looking beyond LIMIT."
+  (let ((initial-match-data (match-data))
+        (initial-point (point)))
+    (if (or (re-search-forward "@@\\(?1:[^/]*?\\)\\(@@\\|--\\|__\\|==\\|\\.\\)[^/]*$" limit t)
+            (re-search-forward "@@\\(?1:[^/]*\\)$" limit t))
+        (progn
+          (goto-char (match-end 1))
+          (set-match-data (list (match-beginning 1) (match-end 1)))
+          (point))
+      (goto-char initial-point)
+      (set-match-data initial-match-data)
+      nil)))
+
+(defun denote-faces-title-matcher (limit)
+  "Match the title in a Dired line, not looking beyond LIMIT."
+  (let ((initial-match-data (match-data))
+        (initial-point (point)))
+    (if (or (re-search-forward "--\\(?1:[^/]*?\\)\\(@@\\|__\\|==\\|\\.\\)[^/]*$" limit t)
+            (re-search-forward "--\\(?1:[^/]*\\)$" limit t))
+        (progn
+          (goto-char (match-end 1))
+          (set-match-data (list (match-beginning 1) (match-end 1)))
+          (point))
+      (goto-char initial-point)
+      (set-match-data initial-match-data)
+      nil)))
+
+(defun denote-faces-keywords-matcher (limit)
+  "Match the keywords in a Dired line, not looking beyond LIMIT."
+  (let ((initial-match-data (match-data))
+        (initial-point (point)))
+    (if (or (re-search-forward "__\\(?1:[^/]*?\\)\\(@@\\|--\\|__\\|==\\|\\.\\)[^/]*$" limit t)
+            (re-search-forward "__\\(?1:[^/]*\\)$" limit t))
+        (progn
+          (goto-char (match-end 1))
+          (set-match-data (list (match-beginning 1) (match-end 1)))
+          (point))
+      (goto-char initial-point)
+      (set-match-data initial-match-data)
+      nil)))
+
+(defconst denote-faces-matchers
+  `((denote-faces-directory-matcher
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-subdirectory nil t))
+    ;; Identifier with format 00000000T000000
+    ("\\(?1:[0-9]\\{4\\}\\)\\(?2:[0-9]\\{2\\}\\)\\(?3:[0-9]\\{2\\}\\)\\(?7:T\\)\\(?4:[0-9]\\{2\\}\\)\\(?5:[0-9]\\{2\\}\\)\\(?6:[0-9]\\{2\\}\\)"
+     (goto-char (match-beginning 0)) ; pre-form, executed before looking for the first identifier
+     (goto-char (match-end 0))       ; post-form, executed after all matches (identifiers here) are found
+     (1 'denote-faces-year nil t)
+     (2 'denote-faces-month nil t)
+     (3 'denote-faces-day nil t)
+     (4 'denote-faces-hour nil t)
+     (5 'denote-faces-minute nil t)
+     (6 'denote-faces-second nil t)
+     (7 'denote-faces-delimiter nil t))
+    ;; Identifier with general format (not yet possible)
+    (denote-faces-identifier-matcher
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-date nil t))
+    ;; Title
+    (denote-faces-title-matcher
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-title nil t))
+    ;; Keywords
+    (denote-faces-keywords-matcher
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-keywords nil t))
+    ;; Signature
+    (denote-faces-signature-matcher
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-signature nil t))
+    ;; Delimiters
+    ("\\(@@\\|--\\|__\\|==\\)"
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-delimiter nil t))
+    ;; Extension
+    ("\\..*$"
+     (goto-char (match-beginning 0))
+     (goto-char (match-end 0))
+     (0 'denote-faces-extension nil t)))
+  "Matchers for fontification of file names.")
+
+(defconst denote-faces-file-name-keywords-for-dired
+  `((denote-faces-dired-file-name-matcher ,@denote-faces-matchers))
+  "Keywords for fontification of file names.")
+
+(make-obsolete-variable 'denote-faces-file-name-keywords-for-backlinks nil "4.0.0")
+
+(defface denote-faces-prompt-old-name '((t :inherit error))
+  "Face for the old name shown in the prompt of `denote-rename-file' etc."
+  :group 'denote-faces
+  :package-version '(denote . "2.2.0"))
+
+(defface denote-faces-prompt-new-name '((t :inherit success))
+  "Face for the new name shown in the prompt of `denote-rename-file' etc."
+  :group 'denote-faces
+  :package-version '(denote . "2.2.0"))
+
+(defface denote-faces-prompt-current-name '((t :inherit denote-faces-prompt-old-name))
+  "Face for the current file shown in the prompt of `denote-rename-file' etc."
+  :group 'denote-faces
+  :package-version '(denote . "2.2.0"))
+
+;;;; Fontification in Dired
+
+(defgroup denote-dired ()
+  "Integration between Denote and Dired."
+  :group 'denote)
+
+(defcustom denote-dired-directories (list denote-directory)
+  "List of directories where `denote-dired-mode' should apply to.
+For this to take effect, add `denote-dired-mode-in-directories',
+to the `dired-mode-hook'.
+
+If `denote-dired-directories-include-subdirectories' is non-nil,
+also apply the effect to all subdirectories of those specified in
+the list."
+  :type '(repeat directory)
+  :package-version '(denote . "0.1.0")
+  :link '(info-link "(denote) Fontification in Dired")
+  :group 'denote-dired)
+
+(defcustom denote-dired-directories-include-subdirectories nil
+  "If non-nil `denote-dired-directories' also affects all subdirectories.
+Otherwise `denote-dired-directories' works only with exact matches."
+  :package-version '(denote . "2.2.0")
+  :link '(info-link "(denote) Fontification in Dired")
+  :type 'boolean
+  :group 'denote-dired)
+
+;; FIXME 2022-08-12: Make `denote-dired-mode' work with diredfl.  This
+;; may prove challenging.
+
+(defun denote-dired-add-font-lock (&rest _)
+  "Append `denote-faces-file-name-keywords' to font lock keywords."
+  ;; NOTE 2023-10-28: I tried to add the first argument and then
+  ;; experimented with various combinations of keywords, such as
+  ;; `(,@dired-font-lock-keywords ,@denote-faces-file-name-keywords).
+  ;; None of them could be unset upon disabling `denote-dired-mode'.
+  ;; As such, I am using the `when' here.
+  (when (derived-mode-p 'dired-mode)
+    (font-lock-add-keywords nil denote-faces-file-name-keywords-for-dired t)))
+
+(defun denote-dired-remove-font-lock (&rest _)
+  "Remove `denote-faces-file-name-keywords' from font lock keywords."
+  ;; See NOTE in `denote-dired-add-font-lock'.
+  (when (derived-mode-p 'dired-mode)
+    (font-lock-remove-keywords nil denote-faces-file-name-keywords-for-dired)))
+
+(declare-function wdired-change-to-wdired-mode "wdired")
+(declare-function wdired-finish-edit "wdired")
+
+;;;###autoload
+(define-minor-mode denote-dired-mode
+  "Fontify all Denote-style file names.
+Add this or `denote-dired-mode-in-directories' to
+`dired-mode-hook'."
+  :global nil
+  :group 'denote-dired
+  (if denote-dired-mode
+      (progn
+        (denote-dired-add-font-lock)
+        (advice-add #'wdired-change-to-wdired-mode :after #'denote-dired-add-font-lock)
+        (advice-add #'wdired-finish-edit :after #'denote-dired-add-font-lock))
+    (denote-dired-remove-font-lock)
+    (advice-remove #'wdired-change-to-wdired-mode #'denote-dired-add-font-lock)
+    (advice-remove #'wdired-finish-edit #'denote-dired-add-font-lock))
+  (font-lock-flush (point-min) (point-max)))
+
+(defun denote-dired--modes-dirs-as-dirs ()
+  "Return `denote-dired-directories' as directories.
+The intent is to basically make sure that however a path is
+written, it is always returned as a directory."
+  (mapcar
+   (lambda (dir)
+     (file-name-as-directory (file-truename dir)))
+   denote-dired-directories))
+
+;;;###autoload
+(defun denote-dired-mode-in-directories ()
+  "Enable `denote-dired-mode' in `denote-dired-directories'.
+Add this function to `dired-mode-hook'.
+
+If `denote-dired-directories-include-subdirectories' is non-nil,
+also enable it in all subdirectories."
+  (when-let* ((dirs (denote-dired--modes-dirs-as-dirs))
+              ;; Also include subdirs
+              ((or (member (file-truename default-directory) dirs)
+                   (and denote-dired-directories-include-subdirectories
+                        (seq-some
+                         (lambda (dir)
+                           (string-prefix-p dir (file-truename default-directory)))
+                         dirs)))))
+    (denote-dired-mode 1)))
+
+;;;; The linking facility
+
+;;;;; Link to note
+
+(defvar denote-org-link-format "[[denote:%s][%s]]"
+  "Format of Org link to note.
+The value is passed to `format' with IDENTIFIER and TITLE
+arguments, in this order.
+
+Also see `denote-org-link-in-context-regexp'.")
+
+(defvar denote-md-link-format "[%2$s](denote:%1$s)"
+  "Format of Markdown link to note.
+The %N$s notation used in the default value is for `format' as
+the supplied arguments are IDENTIFIER and TITLE, in this order.
+
+Also see `denote-md-link-in-context-regexp'.")
+
+(defvar denote-id-only-link-format "[[denote:%s]]"
+  "Format of identifier-only link to note.
+The value is passed to `format' with IDENTIFIER as its sole
+argument.
+
+Also see `denote-id-only-link-in-context-regexp'.")
+
+(defvar denote-org-link-in-context-regexp
+  (concat "\\[\\[" "denote:"
+          "\\(?1:[^][]*?\\)"
+          "\\(?:::.*\\)?" "]"
+          "\\[" "\\(?2:" ".*?" "\\)" "]]")
+  "Regexp to match an Org link in its context.
+The format of such links is `denote-org-link-format'.")
+
+(defvar denote-md-link-in-context-regexp
+  (concat "\\[" "\\(?2:" ".*?" "\\)" "]"
+          "(denote:"  "\\(?1:[^][]*?\\)" ")")
+  "Regexp to match a Markdown link in its context.
+The format of such links is `denote-md-link-format'.")
+
+(defvar denote-id-only-link-in-context-regexp
+  (concat "\\[\\[" "denote:"  "\\(?1:[^][]*?\\)" "]]")
+  "Regexp to match an identifier-only link in its context.
+The format of such links is `denote-id-only-link-format'."  )
+
+(defun denote-format-link (file description file-type id-only &optional include-date)
+  "Prepare link to FILE using DESCRIPTION.
+
+FILE-TYPE and ID-ONLY are used to get the format of the link.
+See the `:link' property of `denote-file-types'.
+
+With optional INCLUDE-DATE, convert the identifier using
+`denote--id-to-date' and append it to DESCRIPTION."
+  (let* ((identifier (denote-retrieve-filename-identifier file))
+         (desc (if include-date
+                   (format "%s (%s)" description (denote--id-to-date identifier))
+                 description)))
+    (format
+     (cond
+      ((or id-only (null description) (string-empty-p description))
+       denote-id-only-link-format)
+      ;; NOTE 2024-05-20: If there is no file type, we want to use the
+      ;; Org format because it is still a usable link with the help of
+      ;; the command `org-open-at-point-global'.
+      ((null file-type)
+       (denote--link-format 'org))
+      (t
+       (denote--link-format file-type)))
+     identifier
+     desc)))
+
+(defun denote-link-description-with-signature-and-title (file)
+  "Return link description for FILE.
+
+- If the region is active, use it as the description.
+
+- If FILE has a signature, then format the description as a sequence of
+  the signature text and the title with two spaces between them.
+
+- If FILE does not have a signature, then use its title as the
+  description.
+
+This is useful as the value of the user option
+`denote-link-description-function'."
+  (let* ((file-type (denote-filetype-heuristics file))
+         (signature (denote-retrieve-filename-signature file))
+         (title (denote-retrieve-title-or-filename file file-type))
+         (region-text (denote--get-active-region-content)))
+    (cond
+     (region-text region-text)
+     ((and signature title) (format "%s  %s" signature title))
+     (title (format "%s" title))
+     (signature (format "%s" signature))
+     (t ""))))
+
+(defun denote--get-active-region-content ()
+  "Return the text of the active region, else nil."
+  (when-let* (((region-active-p))
+              (beg (region-beginning))
+              (end (region-end)))
+    (string-trim (buffer-substring-no-properties beg end))))
+
+(defun denote--delete-active-region-content ()
+  "Delete the content of the active region, if any."
+  (when-let* (((region-active-p))
+              (beg (region-beginning))
+              (end (region-end)))
+    (delete-region beg end)))
+
+(defun denote-get-link-description (file)
+  "Return a link description for FILE.
+
+If `denote-link-description-format' is a function, call it with FILE as
+an argument.  The function should return a string, representing the link
+description.
+
+If the user option `denote-link-description-format' is a string, parse
+it to substitute any format specifiers therein with their respective
+values (see the documentation of that user option).  If the region is
+active, use it as the description."
+  (cond
+   ((functionp denote-link-description-format)
+    (funcall denote-link-description-format file))
+   ((stringp denote-link-description-format)
+    (if-let* ((region (denote--get-active-region-content)))
+        region
+      (let ((type (denote-filetype-heuristics file)))
+        (string-trim
+         (format-spec denote-link-description-format
+                      (list (cons ?t (cond
+                                      ((denote-retrieve-front-matter-title-value file (denote-filetype-heuristics file)))
+                                      ((denote-retrieve-filename-title file))
+                                      (t  "")))
+                            (cons ?T (or (denote-retrieve-filename-title file) ""))
+                            (cons ?i (or (denote-retrieve-filename-identifier file) ""))
+                            ;; TODO 2025-04-03: Maybe we can have something like `denote-date-format' here,
+                            ;; but I think we are okay with a hardcoded value.
+                            (cons ?I (or (when-let* ((id (denote-retrieve-filename-identifier file))
+                                                     (_ (denote-valid-date-p id)))
+                                           (format-time-string "%A, %e %B %Y" (date-to-time (denote--id-to-date id))))
+                                         ""))
+                            (cons ?D (cond
+                                      ((denote-retrieve-front-matter-title-value file type))
+                                      ((denote-retrieve-filename-title file))
+                                      ((when-let* ((id (denote-retrieve-filename-identifier file)))
+                                         (if (denote-valid-date-p id)
+                                             (format-time-string "%A, %e %B %Y" (date-to-time (denote--id-to-date id)))
+                                           id)))
+                                      (t  "")))
+                            (cons ?d (or (denote-retrieve-filename-identifier file) ""))
+                            (cons ?s (or (denote-retrieve-filename-signature file) ""))
+                            (cons ?k (or (denote-retrieve-filename-keywords file) ""))
+                            (cons ?% "%"))
+                      'delete)))))
+   (t
+    (error "The `denote-link-description-format' must be a function or string"))))
+
+(define-obsolete-function-alias
+  'denote--link-get-description
+  'denote-get-link-description
+  "4.0.0")
+
+;;;###autoload
+(defun denote-link (file file-type description &optional id-only)
+  "Create link to FILE note in variable `denote-directory' with DESCRIPTION.
+
+When called interactively, prompt for FILE using completion.  In this
+case, derive FILE-TYPE from the current buffer.  FILE-TYPE is used to
+determine the format of the link.
+
+Return the DESCRIPTION of the link in the format specified by
+`denote-link-description-format'.  The default is to return the text of
+the active region or the title of the note (plus the signature if
+present).
+
+With optional ID-ONLY as a non-nil argument, such as with a universal
+prefix (\\[universal-argument]), insert links with just the identifier
+and no further description.  In this case, the link format is always
+[[denote:IDENTIFIER]].
+
+If the DESCRIPTION is empty, format the link the same as with ID-ONLY.
+
+When called from Lisp, FILE is a string representing a full file system
+path.  FILE-TYPE is a symbol as described in the user option
+`denote-file-type'.  DESCRIPTION is a string.  Whether the caller treats
+the active region specially, is up to it."
+  (interactive
+   (let* ((file (denote-file-prompt nil "Link to FILE"))
+          (file-type (denote-filetype-heuristics buffer-file-name))
+          (description (when (file-exists-p file)
+                         (denote-get-link-description file))))
+     (list file file-type description current-prefix-arg)))
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (unless (file-exists-p file)
+    (user-error "The linked file does not exist"))
+  (denote--delete-active-region-content)
+  (insert (denote-format-link file description file-type id-only)))
+
+(defalias 'denote-insert-link 'denote-link
+  "Alias for `denote-link' command.")
+
+(make-obsolete 'denote-link-with-signature nil " 4.0.0: Use the `denote-link-description-format'.")
+
+(defun denote-link--collect-identifiers (regexp)
+  "Return collection of identifiers in buffer matching REGEXP."
+  (let (matches)
+    (save-excursion
+      (goto-char (point-min))
+      (while (or (re-search-forward regexp nil t)
+                 (re-search-forward denote-id-only-link-in-context-regexp nil t))
+        (push (match-string-no-properties 1) matches)))
+    matches))
+
+(defun denote-link--expand-identifiers (regexp)
+  "Expend identifiers matching REGEXP into file paths."
+  (let ((files (denote-directory-files))
+        found-files)
+    (dolist (file files)
+      (dolist (i (denote-link--collect-identifiers regexp))
+        (when (string= i (denote-retrieve-filename-identifier file))
+          (push file found-files))))
+    found-files))
+
+(defvar denote-link-find-file-history nil
+  "History for `denote-find-link'.")
+
+(defalias 'denote-link--find-file-history 'denote-link-find-file-history
+  "Compatibility alias for `denote-link-find-file-history'.")
+
+(defun denote-select-linked-file-prompt (files)
+  "Prompt for linked file among FILES."
+  (let ((file-names (mapcar #'denote-get-file-name-relative-to-denote-directory files)))
+    (completing-read
+     "Find linked file: "
+     (denote--completion-table 'file file-names)
+     nil t nil 'denote-link-find-file-history)))
+
+(define-obsolete-function-alias
+  'denote-link--find-file-prompt
+  'denote-select-linked-file-prompt
+  "3.0.0")
+
+(defun denote-link-return-links (&optional file)
+  "Return list of links in current or optional FILE.
+Also see `denote-link-return-backlinks'."
+  (when-let* ((current-file (or file (buffer-file-name)))
+              ((denote-file-has-supported-extension-p current-file))
+              (file-type (denote-filetype-heuristics current-file))
+              (regexp (denote--link-in-context-regexp file-type))
+              (files (denote-directory-files))
+              (file-identifiers
+               (with-temp-buffer
+                 (insert-file-contents current-file)
+                 (denote-link--collect-identifiers regexp)))
+              (file-identifiers-hash-table (make-hash-table :test 'equal)))
+    (dolist (id file-identifiers)
+      (puthash id t file-identifiers-hash-table))
+    (let ((found-files))
+      (dolist (file files)
+        (when (gethash (denote-retrieve-filename-identifier file) file-identifiers-hash-table)
+          (push file found-files)))
+      found-files)))
+
+(defalias 'denote-link-return-forelinks 'denote-link-return-links
+  "Alias for `denote-link-return-links'.")
+
+;;;###autoload
+(defun denote-find-link ()
+  "Use minibuffer completion to visit linked file.
+Also see `denote-find-backlink'."
+  (declare (interactive-only t))
+  (interactive)
+  (find-file
+   (concat
+    (denote-directory)
+    (denote-select-linked-file-prompt
+     (or (denote-link-return-links)
+         (user-error "No links found"))))))
+
+;;;###autoload
+(defun denote-link-after-creating (&optional id-only)
+  "Create new note in the background and link to it directly.
+
+Use `denote' interactively to produce the new note.  Its doc
+string explains which prompts will be used and under what
+conditions.
+
+With optional ID-ONLY as a prefix argument create a link that
+consists of just the identifier.  Else try to also include the
+file's title.  This has the same meaning as in `denote-link'.
+
+For a variant of this, see `denote-link-after-creating-with-command'.
+
+IMPORTANT NOTE: Normally, `denote' does not save the buffer it
+produces for the new note.  This is a safety precaution to not
+write to disk unless the user wants it (e.g. the user may choose
+to kill the buffer, thus cancelling the creation of the note).
+However, for this command the creation of the note happens in the
+background and the user may miss the step of saving their buffer.
+We thus have to save the buffer in order to (i) establish valid
+links, and (ii) retrieve whatever front matter from the target
+file.  Though see `denote-save-buffer-after-creation'."
+  (interactive "P")
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (let* ((type (denote-filetype-heuristics (buffer-file-name)))
+         (path (denote--command-with-features #'denote nil nil :save :in-background))
+         (description (denote-get-link-description path)))
+    (denote-link path type description id-only)))
+
+;;;###autoload
+(defun denote-link-after-creating-with-command (command &optional id-only)
+  "Like `denote-link-after-creating' but prompt for note-making COMMAND.
+Use this to, for example, call `denote-signature' so that the
+newly created note has a signature as part of its file name.
+
+Optional ID-ONLY has the same meaning as in the command
+`denote-link-after-creating'."
+  (interactive
+   (list
+    (denote-command-prompt)
+    current-prefix-arg))
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (let* ((type (denote-filetype-heuristics (buffer-file-name)))
+         (path (denote--command-with-features command nil nil :save :in-background))
+         (description (denote-get-link-description path)))
+    (denote-link path type description id-only)))
+
+;;;###autoload
+(defun denote-link-or-create (target &optional id-only)
+  "Use `denote-link' on TARGET file, creating it if necessary.
+
+If TARGET file does not exist, call `denote-link-after-creating' which
+runs the `denote' command interactively to create the file.  The
+established link will then be targeting that new file.  In that case,
+use the last input at the file prompt as the default value of the title
+prompt.
+
+With optional ID-ONLY as a prefix argument create a link that
+consists of just the identifier.  Else try to also include the
+file's title.  This has the same meaning as in `denote-link'."
+  (interactive
+   (let* ((target (denote-file-prompt nil "Select file (RET on no match to create it)" :no-require-match)))
+     (unless (and target (file-exists-p target))
+       (setq target (denote--command-with-features #'denote :use-file-prompt-as-def-title :ignore-region :save :in-background)))
+     (list target current-prefix-arg)))
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (denote-link target
+               (denote-filetype-heuristics (buffer-file-name))
+               (denote-get-link-description target)
+               id-only))
+
+(defalias 'denote-link-to-existing-or-new-note 'denote-link-or-create
+  "Alias for `denote-link-or-create' command.")
+
+;;;;; Links' buffer (query links and backlinks using `denote-query-mode')
+
+(define-obsolete-function-alias
+  'denote-backlinks-mode
+  'denote-query-mode
+  "4.0.0")
+
+(declare-function outline-cycle "outline" (&optional event))
+(declare-function outline-cycle-buffer "outline" (&optional level))
+(declare-function outline-next-heading "outline" ())
+(declare-function outline-previous-heading "outline" ())
+
+(defvar denote-query-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "a" #'outline-cycle-buffer)
+    (define-key map "f" #'denote-query-focus-last-search)
+    (define-key map "k" #'outline-previous-heading)
+    (define-key map "j" #'outline-next-heading)
+    (define-key map "o" #'delete-other-windows)
+    (define-key map "s" #'denote-grep)
+    (define-key map "v" #'outline-cycle)
+    (define-key map "x" #'denote-query-exclude-files)
+    (define-key map "i" #'denote-query-only-include-files)
+    (define-key map "l" #'recenter-current-error)
+    (define-key map "X" #'denote-query-exclude-files-with-keywords)
+    (define-key map "I" #'denote-query-only-include-files-with-keywords)
+    (define-key map "G" #'denote-query-clear-all-filters)
+    map)
+  "Keymap for `denote-query-mode' buffers.")
+
+(define-derived-mode denote-query-mode xref--xref-buffer-mode "Denote Query"
+  "Major mode for queries found in the variable `denote-directory'.
+This is used by the commands `denote-backlinks', `denote-grep',
+`denote-query-contents-link', among others."
+  :interactive nil
+  (setq-local outline-minor-mode-use-buttons 'in-margins)
+  (outline-minor-mode 1))
+
+(make-obsolete 'denote-link--backlink-find-file nil "4.0.0")
+(make-obsolete 'denote-link--display-buffer nil "4.0.0")
+(make-obsolete 'denote-backlinks-mode-next nil "4.0.0")
+(make-obsolete 'denote-backlinks-mode-previous nil "4.0.0")
+(make-obsolete 'denote-backlinks-toggle-context nil "4.0.0")
+(make-obsolete-variable 'denote-backlinks-mode-map nil "4.0.0")
+
+(define-obsolete-function-alias
+  'denote-link--prepare-backlinks
+  'denote-make-links-buffer
+  "4.0.0")
+
+(make-obsolete-variable 'denote-backlinks-show-context nil "4.0.0")
+
+(define-obsolete-variable-alias
+  'denote-link-backlinks-display-buffer-action
+  'denote-backlinks-display-buffer-action
+  "3.1.0")
+
+(defgroup denote-query ()
+  "Integration between Denote and Xref for grep/query/backlink buffers."
+  :group 'denote)
+
+(defcustom denote-backlinks-display-buffer-action
+  '((display-buffer-reuse-mode-window display-buffer-below-selected)
+    (mode . denote-query-mode)
+    (window-height . fit-window-to-buffer))
+  "The action used to display the current file's backlinks buffer.
+
+The value has the form (FUNCTION . ALIST), where FUNCTION is
+either an \"action function\", a list thereof, or possibly an
+empty list.  ALIST is a list of \"action alist\" which may be
+omitted (or be empty).
+
+Sample configuration to display the buffer in a side window on
+the left of the Emacs frame:
+
+    (setq denote-backlinks-display-buffer-action
+          (quote ((display-buffer-reuse-window display-buffer-in-side-window)
+                  (side . left)
+                  (slot . 99)
+                  (window-width . 0.3)
+                  (dedicated . t)
+                  (preserve-size . (t . t)))))
+
+See Info node `(elisp) Displaying Buffers' for more details
+and/or the documentation string of `display-buffer'."
+  :risky t
+  :type `(choice
+          (alist :key-type
+                 (choice :tag "Condition"
+                         regexp
+                         (function :tag "Matcher function"))
+                 :value-type ,display-buffer--action-custom-type)
+          (function :tag "Custom function to return an action alist"))
+  :package-version '(denote . "3.1.0")
+  :group 'denote-query)
+
+(defcustom denote-query-links-display-buffer-action
+  '((display-buffer-reuse-mode-window display-buffer-below-selected)
+    (mode . (denote-query-mode dired))
+    (window-height . 0.3)
+    (preserve-size . (t . t)))
+  "The action used to display query links.
+This is the same as `denote-backlinks-display-buffer-action'.  Refer to
+its documentation for the technicalities."
+  :risky t
+  :type `(choice
+          (alist :key-type
+                 (choice :tag "Condition"
+                         regexp
+                         (function :tag "Matcher function"))
+                 :value-type ,display-buffer--action-custom-type)
+          (function :tag "Custom function to return an action alist"))
+  :package-version '(denote . "4.0.0")
+  :group 'denote-query)
+
+(defcustom denote-query-format-heading-function #'identity
+  "Function used to construct headings for files matched by a query.
+
+It is called with a single argument, the path to the note file, and it
+should always return a string."
+  :package-version '(denote . "4.0.0")
+  :link '(info-link "(denote) Use denote-grep to search inside files")
+  :group 'denote-query
+  :type 'function)
+
+(defcustom denote-query-untitled-string "[Untitled]"
+  "String to use as heading for untitled notes in links' buffer.
+
+Used only by `denote-query-extract-title'."
+  :package-version '(denote . "4.0.0")
+  :link '(info-link "(denote) Use denote-grep to search inside files")
+  :group 'denote-query
+  :type 'string)
+
+(defun denote-query-extract-title (file)
+  "Extract note title from FILE front matter.
+
+When no title is found, return title found in FILE name.
+
+When that doesn't work, return `denote-grep-untitled-string'.
+
+Intended to be used as `denote-query-format-heading-function'."
+  (if-let* ((type (denote-filetype-heuristics file))
+            (title (denote-retrieve-title-or-filename file type))
+            (_ (not (string-blank-p title))))
+      title
+    denote-query-untitled-string))
+
+;; NOTE 2025-03-24: The `&rest' is there because we used to have an
+;; extra SHOW-CONTEXT parameter.  This way we do not break anybody's
+;; code, even if we slightly modify the behaviour.
+(defun denote-make-links-buffer (query &optional files buffer-name display-buffer-action &rest _)
+  "Create links' buffer called BUFFER-NAME for QUERY.
+
+Optional FILES can be a list of files to search for.  It can also be a
+regexp, which limits the files accordingly per `denote-directory-files'.
+
+Optional DISPLAY-BUFFER-ACTION is a `display-buffer' action and
+concomitant alist, such as `denote-backlinks-display-buffer-action'."
+  (let* ((inhibit-read-only t)
+         (file buffer-file-name)
+         (buffer (or buffer-name (format-message "Denote query for `%s'" query)))
+         ;; We retrieve results in absolute form and change the
+         ;; absolute path to a relative path below. We could add a
+         ;; suitable function and the results would be automatically
+         ;; in relative form, but eventually notes may not be all
+         ;; under a common directory (or project).
+         (xref-alist (denote-retrieve-xref-alist query files))
+         (dir (denote-directory)))
+    (unless xref-alist
+      (error "No matches for query `%s'" query))
+    ;; Update internal variables
+    (setq denote-query--last-files nil)
+    (setq denote-query--last-query query)
+    (dolist (x xref-alist)
+      (let* ((file-xref (car x))
+             (file
+              ;; NOTE: Unfortunately, the car of the xref construct is
+              ;; not reliable; sometimes it's absolute, sometimes it
+              ;; is not
+              (if (file-name-absolute-p file-xref)
+                  file-xref
+                (xref-location-group
+                 (xref-match-item-location (car (last x)))))))
+        ;; Add to current set of files
+        (push file denote-query--last-files)
+        ;; Format heading
+        (setf (car x) (funcall denote-query-format-heading-function file))))
+    (delete-dups denote-query--last-files)
+    ;; Insert results
+    (with-current-buffer (get-buffer-create buffer)
+      (erase-buffer)
+      (denote-query-mode)
+      ;; In the links' buffer, the values of variables set in a
+      ;; `.dir-locals.el` do not apply.  We need to set
+      ;; `denote-directory' here because the buttons depend on it.
+      ;; Moreover, its value is overwritten after enabling the major
+      ;; mode, so it needs to be set after.
+      (setq-local denote-directory dir)
+      (setq overlay-arrow-position nil)
+      (goto-char (point-min))
+      (xref--insert-xrefs xref-alist)
+      (goto-char (point-min))
+      (setq-local revert-buffer-function
+                  (lambda (_ignore-auto _noconfirm)
+                    (when-let* ((buffer-file-name file))
+                      (denote-make-links-buffer query files buffer-name display-buffer-action)))))
+    (display-buffer buffer display-buffer-action)))
+
+(defvar denote-query-links-buffer-function #'denote-make-links-buffer
+  "Function to make an Xref buffer showing query link results.
+It accepts the same arguments as `denote-make-links-buffer'.")
+
+(defun denote-query-focus-last-search (query)
+  "Search QUERY in the content of files which matched the last search.
+\"Last search\" here means any call to `denote-grep',
+`denote-backlinks', `denote-query-contents-link', or, generally, any
+command that relies on the `denote-make-links-buffer'."
+  (interactive (list (denote-grep-query-prompt :focused)) denote-query-mode)
+  (unless (derived-mode-p 'denote-query-mode)
+    (user-error "Only use this command inside the `denote-query-mode'"))
+  (denote-make-links-buffer
+   query denote-query--last-files
+   nil '(display-buffer-same-window))
+  (message "Searching `%s' in files matched previously" query))
+
+(defun denote-query-exclude-files (regexp)
+  "Exclude files whose name matches REGEXP from current search buffer.
+
+This is useful even if you don't know regular expressions, given the
+Denote file-naming scheme.  For instance, to exclude notes with the
+keyword \"philosophy\" from current search buffer, type
+‘\\<denote-query-mode-map>\\[denote-query-exclude-files] _philosophy
+RET’.
+
+Internally, this works by generating a new call to
+`denote-make-links-buffer' with the same QUERY as the last one, but with
+a set of files gotten from checking REGEXP against last matched files.
+
+When called from Lisp, REGEXP can be a list; in that case, it should be
+a list of fixed strings (NOT regexps) to check against last matched
+files.  Files that match any of the strings get excluded.  Internally,
+the list is processed using `regexp-opt'.  For an example of this usage,
+see `denote-query-exclude-files-with-keywords'."
+  (interactive (list (denote-grep-file-regexp-prompt)) denote-query-mode)
+  (unless (derived-mode-p 'denote-query-mode)
+    (user-error "Only use this command inside the `denote-query-mode'"))
+  (let (final-files)
+    (dolist (file denote-query--last-files)
+      (unless (string-match
+               ;; Support list of strings as REGEXP
+               (if (listp regexp)
+                   (regexp-opt regexp)
+                 regexp)
+               file)
+        (push file final-files)))
+    (if final-files
+        (denote-make-links-buffer denote-query--last-query final-files)
+      (user-error "No remaining files when applying that filter"))
+    (message "Excluding files matching `%s'" regexp)))
+
+(defun denote-query-only-include-files (regexp)
+  "Exclude file names not matching REGEXP from current query buffer.
+
+See `denote-query-exclude-files' for details, including the behaviour
+when REGEXP is a list."
+  (interactive (list (denote-grep-file-regexp-prompt :include)) denote-query-mode)
+  (unless (derived-mode-p 'denote-query-mode)
+    (user-error "Only use this command inside the `denote-query-mode'"))
+  (let (final-files)
+    (dolist (file denote-query--last-files)
+      (when (string-match
+             ;; Support list of strings as REGEXP
+             (if (listp regexp)
+                 (regexp-opt regexp)
+               regexp)
+             file)
+        (push file final-files)))
+    (if final-files
+        (denote-make-links-buffer denote-query--last-query final-files)
+      (user-error "No remaining files when applying that filter"))
+    (message "Only including files matching `%s'" regexp)))
+
+(defun denote-query-exclude-files-with-keywords (keywords)
+  "Exclude files with KEYWORDS from current query buffer.
+
+KEYWORDS should be a list of keywords (without underscore).
+
+Interactively, KEYWORDS are read from the minibuffer using
+`completing-read-multiple', which see."
+  (interactive
+   (list (denote-keywords-prompt "Exclude files with keywords"))
+   denote-query-mode)
+  (unless (derived-mode-p 'denote-query-mode)
+    (user-error "Only use this command inside the `denote-query-mode'"))
+  (denote-query-exclude-files
+   (mapcar (lambda (kw) (concat "_" kw)) keywords)))
+
+(defun denote-query-only-include-files-with-keywords (keywords)
+  "Exclude files without KEYWORDS from current query buffer.
+
+See `denote-query-exclude-files-with-keywords' for details."
+  (interactive
+   (list (denote-keywords-prompt "Only include files with keywords"))
+   denote-query-mode)
+  (unless (derived-mode-p 'denote-query-mode)
+    (user-error "Only use this command inside the `denote-query-mode'"))
+  (denote-query-only-include-files
+   (mapcar (lambda (kw) (concat "_" kw)) keywords)))
+
+(defun denote-query-clear-all-filters ()
+  "Run last search with the full set of files in the variable `denote-directory'.
+
+This effectively gets ride of any interactive filter applied (by the
+means of e.g. `denote-query-exclude-files')."
+  (interactive nil denote-query-mode)
+  (unless (derived-mode-p 'denote-query-mode)
+    (user-error "Only use this command inside the `denote-query-mode'"))
+  (denote-make-links-buffer denote-query--last-query)
+  (message "Cleared all filters"))
+
+;;;;;; Additional features for searching file contents
+
+(defvar denote-grep-history nil
+  "Minibuffer history of content searches performed by `denote-grep'.
+Also see `denote-grep-file-regexp-history'.")
+
+(defcustom denote-grep-display-buffer-action
+  '((display-buffer-same-window)
+    (mode . denote-query-mode))
+  "The action used to display search results from `denote-grep'.
+This is the same as `denote-backlinks-display-buffer-action'.  Refer to
+its documentation for the technicalities."
+  :risky t
+  :type `(choice
+          (alist :key-type
+                 (choice :tag "Condition"
+                         regexp
+                         (function :tag "Matcher function"))
+                 :value-type ,display-buffer--action-custom-type)
+          (function :tag "Custom function to return an action alist"))
+  :package-version '(denote . "4.0.0")
+  :group 'denote-query)
+
+(defun denote-grep-query-prompt (&optional type)
+  "Prompt for a grep query in the minibuffer.
+
+The prompt assumes a search in all files, unless TYPE is non-nil.
+
+TYPE can be one of :focused (for a focused search (a search among
+matching files), see `denote-query-focus-last-search'), :dired (for a
+search in marked Dired files, see `denote-grep-marked-dired-files') or
+:region (for a search in files referenced in region, see
+`denote-grep-files-referenced-in-region').
+
+TYPE only affects the prompt, not the returned value."
+  (read-string
+   (cond ((eq type :focused)
+          "Search (only files matched last): ")
+         ((eq type :dired)
+          "Search (only marked dired files): ")
+         ((eq type :region)
+          "Search (only files referenced in region): ")
+         (t "Search (all Denote files): "))
+   nil 'denote-grep-history))
+
+(defvar denote-grep-file-regexp-history nil
+  "Minibuffer history for `denote-grep' commands asking for a file regexp.
+Also see `denote-grep-history'.")
+
+(defun denote-grep-file-regexp-prompt (&optional include)
+  "Prompt for a file regexp in the minibuffer.
+
+The prompt assumes the user wants to exclude files, unless INCLUDE is
+non-nil."
+  (read-string
+   (if (not include)
+       "Exclude file names matching: "
+     "Only include file names matching: ")
+   nil 'denote-grep-file-regexp-history))
+
+;;;###autoload
+(defun denote-grep (query)
+  "Search QUERY in the content of Denote files.
+QUERY should be a regular expression accepted by `xref-search-program'.
+
+The files to search for are those returned by `denote-directory-files'
+with a non-nil TEXT-ONLY argument.
+
+Results are put in a buffer which allows folding and further
+filtering (see the manual for details).
+
+You can insert a link to a grep search in any note by using the command
+`denote-query-contents-link'."
+  (interactive (list (denote-grep-query-prompt)))
+  (let (denote-query--omit-current)
+    (denote-make-links-buffer query nil nil denote-grep-display-buffer-action)))
+
+;;;###autoload
+(defun denote-grep-marked-dired-files (query)
+  "Do the equivalent of `denote-grep' for QUERY in marked Dired files."
+  (interactive (list (denote-grep-query-prompt :dired)))
+  (if-let* ((files (dired-get-marked-files)))
+      (denote-make-links-buffer query files nil denote-grep-display-buffer-action)
+    (user-error "No marked files")))
+
+(defun denote-grep--get-files-referenced-in-region (start end)
+  "Return a list with all Denote files referenced between START and END.
+START and END are buffer positions, as integers.  A reference to a file
+is the mere presence of its identifier.
+
+Return a list with the absoulte path of referenced files."
+  (let (id-list)
+    (save-excursion
+      (save-restriction
+        (narrow-to-region start end)
+        (goto-char (point-min))
+        (while (re-search-forward denote-id-regexp nil t)
+          (push (denote-get-path-by-id (match-string 0)) id-list))))
+    id-list))
+
+;;;###autoload
+(defun denote-grep-files-referenced-in-region (query start end)
+  "Perform `denote-grep' QUERY in files referenced between START and END.
+When called interactively, prompt for QUERY.  Also get START and END as
+the buffer positions that delimit the marked region.  When called from
+Lisp, QUERY is a string, while START and END are buffer positions, as
+integers.
+
+Find references to files by their identifier.  This includes links with
+just the identifier (as described in `denote-link' and related), links
+written by an Org dynamic block (see the `denote-org' package), or even
+file listings such as those of `dired' and the command-line `ls' program."
+  (interactive
+   (if (region-active-p)
+       (list
+        (denote-grep-query-prompt :region)
+        (region-beginning)
+        (region-end))
+     (user-error "No region is active; aborting")))
+  (if-let* ((files (denote-grep--get-files-referenced-in-region start end)))
+      (denote-make-links-buffer query files nil denote-grep-display-buffer-action)
+    (user-error "No files referenced in region")))
+
+;;;;;; Backlinks
+
+(defun denote--backlinks-get-buffer-name (file id)
+  "Format a buffer name for `denote-backlinks'.
+Use FILE to detect a suitable title with which to name the buffer.  Else
+use the ID."
+  (if-let* ((type (denote-filetype-heuristics file))
+            (title (denote-retrieve-front-matter-title-value file type)))
+      (format "*Denote FILE backlinks for %S*" title)
+    (format "*Denote FILE backlinks for %s*" id)))
+
+;;;###autoload
+(defun denote-backlinks ()
+  "Produce a buffer with backlinks to the current note.
+
+Show the names of files linking to the current file.  Include the
+context of each link if the user option `denote-backlinks-show-context'
+is non-nil.
+
+Place the buffer below the current window or wherever the user option
+`denote-backlinks-display-buffer-action' specifies."
+  (interactive)
+  (if-let* ((file buffer-file-name))
+      (when-let* ((identifier (denote-retrieve-filename-identifier-with-error file)))
+        (funcall denote-query-links-buffer-function
+                 identifier nil
+                 (denote--backlinks-get-buffer-name file identifier)
+                 denote-backlinks-display-buffer-action))
+    (user-error "Buffer `%s' is not associated with a file" (current-buffer))))
+
+(defalias 'denote-show-backlinks-buffer 'denote-backlinks
+  "Alias for `denote-backlinks' command.")
+
+
+(defun denote-link-return-backlinks (&optional file)
+  "Return list of backlinks in current or optional FILE.
+Also see `denote-link-return-links'."
+  (when-let* ((current-file (or file (buffer-file-name)))
+              (id (denote-retrieve-filename-identifier-with-error current-file)))
+    (delete current-file (denote-retrieve-files-xref-query id))))
+
+;; TODO 2024-09-04: Instead of using `denote-link-return-backlinks' we
+;; should have a function that does not try to find all backlinks but
+;; simply exits as soon as it finds one.
+(defun denote--file-has-backlinks-p (file)
+  "Return non-nil if FILE has backlinks."
+  (not (zerop (length (denote-link-return-backlinks file)))))
+
+;;;###autoload
+(defun denote-find-backlink ()
+  "Use minibuffer completion to visit backlink to current file.
+Alo see `denote-find-link'."
+  (declare (interactive-only t))
+  (interactive)
+  (find-file
+   (denote-get-path-by-id
+    (denote-extract-id-from-string
+     (denote-select-linked-file-prompt
+      (or (denote-link-return-backlinks)
+          (user-error "No backlinks found")))))))
+
+;;;;;; Query links
+
+(defvar denote-query-link-history nil
+  "Minibuffer history of `denote-query-link-prompt'.")
+
+(defun denote-query-link-prompt (&optional initial-query prompt-text)
+  "Prompt for query string.
+With optional INITIAL-QUERY use it as the initial minibuffer text.  With
+optional PROMPT-TEXT use it in the minibuffer instead of the default
+prompt.
+
+Previous inputs at this prompt are available for minibuffer completion
+if the user option `denote-history-completion-in-prompts' is set to a
+non-nil value."
+  (when (and initial-query (string-empty-p initial-query))
+    (setq initial-query nil))
+  (denote--with-conditional-completion
+   'denote-query-link-prompt
+   (format-prompt (or prompt-text "Query for") nil)
+   denote-query-link-history
+   initial-query))
+
+(defconst denote-query-link-types '(query-contents query-filenames)
+  "Types of query links.")
+
+;; NOTE 2025-03-27: Should we expose a user option for this?  And/or
+;; should we add a DESCRIPTION parameter to `denote--format-query-link'?
+;;
+;; What would make for a good default description in that scenario?
+;; Maybe "QC:query text here" and "QF:query text here" for
+;; `query-contents' and `query-filenames' respectively.
+(defvar denote-query-description-prefix ""
+  "Prefix string for query links to format their description text.
+The description text constists of the value of this variable followed by
+the query")
+
+(defun denote--format-query-link (type query file-type)
+  "Format QUERY link of TYPE for the given FILE-TYPE.
+Return an error if TYPE is not one among the symbols specified in
+`denote-query-link-types'.
+
+If FILE-TYPE is nil, use that of Org."
+  (unless (memq type denote-query-link-types)
+    (error "Type `%s' is not one among `denote-query-link-types'" type))
+  (format (or (denote--link-format file-type) (denote--link-format 'org))
+          (format "%s:%s" type query)
+          (format "%s%s" denote-query-description-prefix query)))
+
+;;;###autoload
+(defun denote-query-contents-link (query)
+  "Insert query link for file contents.
+Prompt for QUERY or use the text of the active region.  When the user
+follows this link, place any matches in a separate buffer (using the
+built-in Xref mechanism).  This is the equivalent of a Unix grep command
+across the variable `denote-directory'."
+  (interactive
+   (list
+    (or (denote--get-active-region-content)
+        (denote-query-link-prompt nil "Query in file CONTENTS"))))
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (denote--delete-active-region-content)
+  (insert (denote--format-query-link 'query-contents query (denote-filetype-heuristics buffer-file-name))))
+
+;;;###autoload
+(defun denote-query-filenames-link (query)
+  "Insert query link for file names.
+Prompt for QUERY or use the text of the active region.  When the user
+follows this link, place any matches in a separate buffer (using the
+built-in Dired mechanism).  This is the equivalent of a Unix find
+command across the variable `denote-directory'."
+  (interactive
+   (list
+    (or (denote--get-active-region-content)
+        (denote-query-link-prompt nil "Query in file NAMES"))))
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (denote--delete-active-region-content)
+  (insert (denote--format-query-link 'query-filenames query (denote-filetype-heuristics buffer-file-name))))
+
+(defvar denote--query-last-dired-buffer nil
+  "Buffer object produced by the last query for file names.")
+
+(defun denote--act-on-query-link (query)
+  "Act on QUERY link.
+QUERY is a string of the form TYPE:SEARCH, where TYPE is one among
+`denote-query-link-types' while SEARCH is the regular expression to
+search for."
+  (cond
+   ((string-prefix-p "query-contents:" query)
+    (setq query (replace-regexp-in-string "query-contents:" "" query))
+    (funcall denote-query-links-buffer-function query nil nil denote-query-links-display-buffer-action))
+   ((string-prefix-p "query-filenames:" query)
+    (setq query (replace-regexp-in-string "query-filenames:" "" query))
+    ;; NOTE 2025-03-27: I do not think we need to add another
+    ;; parameter to `denote-sort-dired' for handling the
+    ;; `display-buffer'.  This is a special case, but we can always
+    ;; change it later if the need arises.
+    ;;
+    ;; Here we handle the buffer and window state to make it behave
+    ;; like the Xref buffer.  Otherwise, Dired does not reuse its
+    ;; buffer (which is generally okay).
+    (let ((buffer (save-window-excursion (denote-sort-dired query nil nil nil))))
+      (when (bufferp denote--query-last-dired-buffer)
+        (when-let* ((window (get-buffer-window denote--query-last-dired-buffer))
+                    (_ (window-live-p window)))
+          (delete-window window))
+        (kill-buffer denote--query-last-dired-buffer))
+      (display-buffer buffer denote-query-links-display-buffer-action)
+      (setq denote--query-last-dired-buffer buffer)))
+   (t
+    (error "Cannot open `%s' of unknown link type" query))))
+
+;;;;; Link buttons
+
+(make-obsolete 'denote-link--find-file-at-button nil "4.0.0")
+
+(make-obsolete
+ 'denote-link-buttonize-buffer
+ 'denote-fontify-links-mode
+ "Use the `denote-fontify-links-mode', as it works better than buttonization. Since 3.0.0")
+
+;; NOTE 2025-03-24: This does not work for query links because of how
+;; `markdown-follow-link-at-point' is implemented to always check for
+;; links.
+(defun denote-link-markdown-follow (link)
+  "Function to open Denote file present in LINK.
+To be assigned to `markdown-follow-link-functions'."
+  (when (ignore-errors (string-match denote-id-regexp link))
+    (funcall denote-open-link-function
+             (denote-get-path-by-id (match-string 0 link)))))
+
+(eval-after-load 'markdown-mode
+  '(add-hook 'markdown-follow-link-functions #'denote-link-markdown-follow))
+
+;;;;; Link fontification
+
+;; TODO 2024-06-19: We need to bind RET and maybe even C-c C-o to a
+;; command that opens the link at point.  Then we may also rename this
+;; keymap.
+(defvar denote-link-mouse-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [mouse-2] #'denote-link-open-at-mouse)
+    (define-key map [mouse-3] #'denote-link-open-at-mouse)
+    (define-key map [follow-link] 'mouse-face)
+    map)
+  "Keymap for mouse actions over fontified Denote links.")
+
+(defun denote--link-open-at-point-subr ()
+  "Open link at point."
+  (let ((query (get-text-property (point) 'denote-link-query-part)))
+    (if-let* ((path (denote-get-path-by-id query)))
+        (funcall denote-open-link-function path)
+      (denote--act-on-query-link query))))
+
+(defun denote-link-open-at-point ()
+  "Open Denote link at point."
+  (interactive)
+  (denote--link-open-at-point-subr))
+
+(defun denote-link-open-at-mouse (ev)
+  "Open Denote link for mouse EV click."
+  (interactive "e")
+  (mouse-set-point ev)
+  (denote--link-open-at-point-subr))
+
+(defun denote-get-link-face (query)
+  "Return appropriate face for QUERY."
+  (if (denote-identifier-p (string-trim-right query ":[^/]+.*"))
+      'denote-faces-link
+    'denote-faces-query-link))
+
+(defun denote--fontify-links-subr (query limit)
+  "Do the work of the font-lock match for QUERY up to LIMIT.
+Implementation based on the function `org-activate-links'."
+  (catch :exit
+    (while (re-search-forward query limit t)
+      (save-match-data  ; to return the matches to font-lock
+        (let* ((start (match-beginning 0))
+               (end (match-end 0))
+               (visible-start (or (match-beginning 2) start))
+               (visible-end (or (match-end 2) end))
+               (query (match-string-no-properties 1)))
+          (let* ((properties `( face ,(denote-get-link-face query)
+                                mouse-face highlight
+                                keymap ,denote-link-mouse-map
+                                denote-link-query-part ,query
+                                help-echo query
+                                htmlize-link (:uri ,query)
+                                font-lock-multiline t))
+                 (non-sticky-props
+                  '(rear-nonsticky (mouse-face highlight keymap invisible intangible help-echo htmlize-link)))
+                 (face-property 'link)
+                 (hidden (append '(invisible 'denote-link) properties)))
+            (remove-text-properties start end '(invisible nil))
+            (add-text-properties start visible-start hidden)
+            (add-face-text-property start end face-property)
+            (add-text-properties visible-start visible-end properties)
+            (add-text-properties visible-end end hidden)
+            (dolist (pos (list end visible-start visible-end))
+              (add-text-properties (1- pos) pos non-sticky-props)))
+          (throw :exit t))))      ; signal success
+    nil))
+
+(defun denote-fontify-links (limit)
+  "Provide font-lock matcher to fontify links up to LIMIT."
+  (when-let* ((type (denote-filetype-heuristics (buffer-file-name))))
+    (denote--fontify-links-subr (denote--link-in-context-regexp type) limit)))
+
+(define-obsolete-function-alias
+  'denote-get-identifier-at-point
+  'denote-get-link-identifier-or-query-term-at-point
+  "4.0.0")
+
+(defun denote-get-link-identifier-or-query-term-at-point (&optional point)
+  "Return the Denote identifier or query term at point or optional POINT."
+  (when-let* ((position (or point (point)))
+              (face-at-point (get-text-property position 'face))
+              ((or (eq face-at-point 'denote-faces-link)
+                   (member 'denote-faces-link face-at-point))))
+    (or (get-text-property position 'denote-link-query-part)
+        (when-let* ((link-data (get-text-property position 'htmlize-link))
+                    (link (cadr link-data)))
+          (string-match denote-id-regexp link)
+          (match-string-no-properties 0 link)))))
+
+(defun denote--get-link-file-path-at-point (&optional point)
+  "Return link to the Denote file path at point or optional POINT.
+To be used as a `thing-at' provider."
+  (when-let* ((position (or point (point)))
+              (id (get-text-property position 'denote-link-query-part))
+              (path (denote-get-path-by-id id)))
+    (concat "file:" path)))
+
+(defvar thing-at-point-provider-alist)
+
+;;;###autoload
+(defun denote-fontify-links-mode-maybe ()
+  "Enable `denote-fontify-links-mode' in a denote file unless in `org-mode'."
+  (when (and buffer-file-name
+             (not (derived-mode-p 'org-mode))
+             (denote-file-is-note-p buffer-file-name))
+    (denote-fontify-links-mode)))
+
+;;;###autoload
+(define-minor-mode denote-fontify-links-mode
+  "A minor mode to fontify and fold Denote links.
+
+Enabled this mode only when the current buffer is a Denote note and the
+major mode is not `org-mode' (or derived therefrom).  Consider using
+`denote-fontify-links-mode-maybe' for this purpose."
+  :init-value nil
+  :global nil
+  :group 'denote
+  (require 'thingatpt)
+  (if denote-fontify-links-mode
+      (progn
+        (add-to-invisibility-spec 'denote-link)
+        (font-lock-add-keywords nil '((denote-fontify-links)))
+        (setq-local thing-at-point-provider-alist
+                    (append thing-at-point-provider-alist
+                            '((url . denote--get-link-file-path-at-point)))))
+    (remove-from-invisibility-spec 'denote-link)
+    (font-lock-remove-keywords nil '((denote-fontify-links)))
+    (setq-local thing-at-point-provider-alist
+                (delete
+                 '(url . denote--get-link-file-path-at-point)
+                 thing-at-point-provider-alist)))
+  (font-lock-update))
+
+;;;;; Add links matching regexp
+
+(defvar denote-link--prepare-links-format "- %s\n"
+  "Format specifiers for `denote-add-links'.")
+
+(make-obsolete-variable 'denote-link-add-links-sort nil "3.1.0")
+
+(defun denote-link--prepare-links (files current-file-type id-only &optional no-sort include-date)
+  "Prepare links to FILES from CURRENT-FILE-TYPE.
+When ID-ONLY is non-nil, use a generic link format.
+
+With optional NO-SORT do not try to sort the inserted lines.
+Otherwise sort lines while accounting for `denote-link-add-links-sort'.
+
+Optional INCLUDE-DATE has the same meaning as in `denote-format-link'."
+  (let ((links))
+    (dolist (file files)
+      (let* ((description (denote-get-link-description file))
+             (link (denote-format-link file description current-file-type id-only include-date))
+             (link-as-list-item (format denote-link--prepare-links-format link)))
+        (push link-as-list-item links)))
+    (if no-sort
+        (nreverse links)
+      (sort links #'string-collate-lessp))))
+
+(defun denote-link--insert-links (files current-file-type &optional id-only no-sort include-date)
+  "Insert at point a typographic list of links matching FILES.
+
+With CURRENT-FILE-TYPE as a symbol among those specified in variable
+`denote-file-type' (or the `car' of each element in `denote-file-types'),
+format the link accordingly.  With a nil or unknown non-nil value,
+default to the Org notation.
+
+With ID-ONLY as a non-nil value, produce links that consist only
+of the identifier, thus deviating from CURRENT-FILE-TYPE.
+
+Optional NO-SORT is passed to `denote-link--prepare-links'.
+
+Optional INCLUDE-DATE has the same meaning as in `denote-format-link'."
+  (when-let* ((links (denote-link--prepare-links files current-file-type id-only no-sort include-date)))
+    (dolist (link links)
+      (insert link))))
+
+;;;###autoload
+(defun denote-add-links (regexp &optional id-only)
+  "Insert links to all files whose file names match REGEXP.
+Use this command to reference multiple files at once.  Particularly
+useful for the creation of metanotes (read the manual for more on the
+matter).
+
+Optional ID-ONLY has the same meaning as in `denote-link': it
+inserts links with just the identifier."
+  (interactive
+   (list
+    (denote-files-matching-regexp-prompt "Insert links to files matching REGEXP")
+    current-prefix-arg))
+  (unless (or (denote--file-type-org-extra-p)
+              (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+    (user-error "The current file type is not recognized by Denote"))
+  (let ((file-type (denote-filetype-heuristics (buffer-file-name))))
+    (if-let* ((files (denote-directory-files regexp :omit-current)))
+        (denote-link--insert-links files file-type id-only)
+      (message "No links matching `%s'" regexp))))
+
+;;;;; Link to file with matching contents
+
+;;;###autoload
+(defun denote-link-to-file-with-contents (query &optional id-only)
+  "Link to a file whose contents match QUERY.
+This is similar to `denote-link', except that the file prompt is limited
+to files matching QUERY.  Optional ID-ONLY has the same meaning as in
+`denote-link'."
+  (interactive
+   (list (denote-query-link-prompt nil "Files whose contents include QUERY")))
+  (if-let* ((files (denote-retrieve-files-xref-query query))
+            ;; NOTE 2025-03-29: Maybe we should have a named prompt
+            ;; for this case, but I think we do not need it right now.
+            (file (completing-read
+                   (format "Select FILE with contents `%s': "
+                           (propertize query 'face 'denote-faces-prompt-current-name))
+                   (denote--completion-table 'file files)
+                   nil t nil 'denote-file-history)))
+      (denote-link file
+                   (denote-filetype-heuristics buffer-file-name)
+                   (denote-get-link-description file)
+                   id-only)
+    (user-error "No files include the query `%s' in their contents" query)))
+
+;;;###autoload
+(defun denote-link-to-all-files-with-contents (query &optional id-only)
+  "Link to all files whose contents match QUERY.
+This is similar to `denote-add-links', except it searches inside file
+contents, not file names.  Optional ID-ONLY has the same meaning as in
+`denote-link' and `denote-add-links'."
+  (interactive
+   (list (denote-query-link-prompt nil "Files whose contents include QUERY")))
+  (if-let* ((files (denote-retrieve-files-xref-query query)))
+      (denote-link--insert-links files (denote-filetype-heuristics buffer-file-name) id-only)
+    (user-error "No files include the query `%s' in their contents" query)))
+
+;;;;; Links from Dired marks
+
+;; NOTE 2022-07-21: I don't think we need a history for this one.
+(defun denote-link--buffer-file-prompt (buffer-file-names)
+  "Select file from BUFFER-FILE-NAMES of Denote notes."
+  (let ((relative-buffer-file-names (mapcar #'denote-get-file-name-relative-to-denote-directory buffer-file-names)))
+    (concat (denote-directory)
+            (completing-read
+             "Select open note to add links to: "
+             (denote--completion-table 'file relative-buffer-file-names)
+             nil t))))
+
+(defun denote-link--map-over-notes ()
+  "Return list of `denote-file-has-denoted-filename-p' from Dired marked items."
+  (seq-filter (lambda (file) (and (denote-file-has-denoted-filename-p file)
+                                  (denote-file-has-identifier-p file)))
+              (dired-get-marked-files)))
+
+;;;###autoload
+(defun denote-link-dired-marked-notes (files buffer &optional id-only)
+  "Insert Dired marked FILES as links in BUFFER.
+
+FILES conform with the Denote file-naming scheme, such that they can be
+linked to using the `denote:' link type.
+
+The BUFFER is one which visits a Denote note file.  If there are
+multiple BUFFER candidates in buffers, prompt with completion for
+one among them.  If there is none, throw an error.
+
+With optional ID-ONLY as a prefix argument, insert links with
+just the identifier (same principle as with `denote-link').
+
+This command is meant to be used from a Dired buffer."
+  (interactive
+   (if (derived-mode-p 'dired-mode)
+       (list
+        (denote-link--map-over-notes)
+        (let ((file-names (denote--buffer-file-names)))
+          (find-buffer-visiting
+           (cond
+            ((null file-names)
+             (user-error "No buffers visiting Denote notes"))
+            ((eq (length file-names) 1)
+             (car file-names))
+            (t
+             (denote-link--buffer-file-prompt file-names)))))
+        current-prefix-arg)
+     (user-error "This command only works inside a Dired buffer"))
+   dired-mode)
+  (when (null files)
+    (user-error "No note files to link to"))
+  (unless (buffer-live-p buffer)
+    (error "The buffer `%s' is not live" buffer))
+  (let ((body (lambda ()
+                (unless (or (denote--file-type-org-extra-p)
+                            (and buffer-file-name (denote-file-has-supported-extension-p buffer-file-name)))
+                  (user-error "The target file's type is not recognized by Denote"))
+                (when (y-or-n-p (format "Create links at point in `%s'?" buffer))
+                  (denote-link--insert-links files (denote-filetype-heuristics buffer-file-name) id-only)
+                  (message "Added links to `%s'; displaying it now"
+                           ;; TODO 2024-12-26: Do we need our face here?  I think
+                           ;; not, but let me keep a note of it.
+                           (propertize (format "%s" buffer) 'face 'success))))))
+    (if-let* ((window (get-buffer-window buffer))
+              ((window-live-p window)))
+        (with-selected-window window (funcall body))
+      (with-current-buffer buffer (funcall body))
+      (display-buffer-below-selected buffer nil))))
+
+(defalias 'denote-dired-link-marked-notes 'denote-link-dired-marked-notes
+  "Alias for `denote-link-dired-marked-notes' command.")
+
+;;;; Define menu
+
+(defvar denote--menu-contents
+  '(["Create a note" denote
+     :help "Create a new note in the `denote-directory'"]
+    ["Create a note with given file type" denote-type
+     :help "Create a new note with a given file type in the `denote-directory'"]
+    ["Create a note in subdirectory" denote-subdirectory
+     :help "Create a new note in a subdirectory of the `denote-directory'"]
+    ["Create a note with date" denote-date
+     :help "Create a new note with a given date in the `denote-directory'"]
+    ["Create a note with signature" denote-signature
+     :help "Create a new note with a given signature in the `denote-directory'"]
+    ["Open a note or create it if missing" denote-open-or-create
+     :help "Open an existing note in the `denote-directory' or create it if missing"]
+    ["Open a note or create it with the chosen command" denote-open-or-create-with-command
+     :help "Open an existing note or create it with the chosen command if missing"]
+    "---"
+    ["Rename a file" denote-rename-file
+     :help "Rename file interactively"
+     :enable (derived-mode-p 'dired-mode 'text-mode)]
+    ["Rename this file using its front matter" denote-rename-file-using-front-matter
+     :help "Rename the current file using its front matter as input"
+     :enable (derived-mode-p 'text-mode)]
+    ["Rename Dired marked files interactively" denote-dired-rename-files
+     :help "Rename marked files in Dired by prompting for all file name components"
+     :enable (derived-mode-p 'dired-mode)]
+    ["Rename Dired marked files with keywords" denote-dired-rename-marked-files-with-keywords
+     :help "Rename marked files in Dired by prompting for keywords"
+     :enable (derived-mode-p 'dired-mode)]
+    ["Rename Dired marked files using their front matter" denote-dired-rename-marked-files-using-front-matter
+     :help "Rename marked files in Dired using their front matter as input"
+     :enable (derived-mode-p 'dired-mode)]
+    "---"
+    ["Insert a direct link" denote-link
+     :help "Insert link to a file in the `denote-directory'"
+     :enable (derived-mode-p 'text-mode)]
+    ["Insert a direct link to file with contents" denote-link-to-file-with-contents
+     :help "Insert link to a file in the `denote-directory' whose contents include a query"
+     :enable (derived-mode-p 'text-mode)]
+    ["Insert a query link for file contents" denote-query-contents-link
+     :help "Insert query link searching for file contents in the `denote-directory'"
+     :enable (derived-mode-p 'text-mode)]
+    ["Insert a query link for file names" denote-query-filenames-link
+     :help "Insert query link searching for file names in the `denote-directory'"
+     :enable (derived-mode-p 'text-mode)]
+    "---"
+    ["Insert links to file names matching regexp" denote-add-links
+     :help "Insert links to file names in the `denote-directory' matching regexp"
+     :enable (derived-mode-p 'text-mode)]
+    ["Insert links to files whose contents match regexp" denote-link-to-all-files-with-contents
+     :help "Insert links to file in the `denote-directory' whose contents match regexp"
+     :enable (derived-mode-p 'text-mode)]
+    ["Insert Dired marked files as links" denote-link-dired-marked-notes
+     :help "Rename marked files in Dired as links in a Denote buffer"
+     :enable (derived-mode-p 'dired-mode)]
+    ["Show file backlinks" denote-backlinks
+     :help "Insert link to a file in the `denote-directory'"
+     :enable (derived-mode-p 'text-mode)]
+    ["Link to existing note or newly created one" denote-link-or-create
+     :help "Insert a link to an existing file, else create it and link to it"
+     :enable (derived-mode-p 'text-mode)]
+    ["Create note in the background and link to it directly" denote-link-after-creating
+     :help "Create new note and link to it from the current file"
+     :enable (derived-mode-p 'text-mode)]
+    ["Create note in the background with chosen command and link to it directly" denote-link-after-creating-with-command
+     :help "Create new note with the chosen command and link to it from the current file"
+     :enable (derived-mode-p 'text-mode)]
+    "---"
+    ["Generate sorted and filtered Dired listing" denote-sort-dired
+     :help "Generate a sorted and filtered Dired listing of files in the `denote-directory'"]
+    "---"
+    ["Highlight Dired file names" denote-dired-mode
+     :help "Apply colors to Denote file name components in Dired"
+     :enable (derived-mode-p 'dired-mode)
+     :style toggle
+     :selected (bound-and-true-p denote-dired-mode)])
+  "Contents of the Denote menu.")
+
+(defun denote--menu-bar-enable ()
+  "Enable Denote menu bar."
+  (define-key-after global-map [menu-bar denote]
+    (easy-menu-binding
+     (easy-menu-create-menu "Denote" denote--menu-contents) "Denote")
+    "Tools"))
+
+;; Enable Denote menu bar by default
+(denote--menu-bar-enable)
+
+;;;###autoload
+(define-minor-mode denote-menu-bar-mode "Show Denote menu bar."
+  :global t
+  :init-value t
+  (if denote-menu-bar-mode
+      (denote--menu-bar-enable)
+    (define-key global-map [menu-bar denote] nil)))
+
+(defun denote-context-menu (menu _click)
+  "Populate MENU with Denote commands at CLICK."
+  (define-key menu [denote-separator] menu-bar-separator)
+  (let ((easy-menu (make-sparse-keymap "Denote")))
+    (easy-menu-define nil easy-menu nil
+      denote--menu-contents)
+    (dolist (item (reverse (lookup-key easy-menu [menu-bar])))
+      (when (consp item)
+        (define-key menu (vector (car item)) (cdr item)))))
+  menu)
+
+;;;; Register `denote:' custom Org hyperlink
+
+(declare-function org-link-open-as-file "ol" (path arg))
+
+(defun denote-link--ol-resolve-link-to-target (link &optional full-data)
+  "Resolve LINK to target file, with or without additioanl file-search terms.
+With optional FULL-DATA return a list in the form of (path query file-search)."
+  (let* ((file-search (and (string-match "::\\(.*\\)\\'" link)
+                           (match-string 1 link)))
+         (query (if (and file-search (not (string-empty-p file-search)))
+                    (substring link 0 (match-beginning 0))
+                  link))
+         (path (denote-get-path-by-id query)))
+    (cond
+     (full-data
+      (list path query file-search))
+     ((and file-search (not (string-empty-p file-search)))
+      (concat path "::" file-search))
+     (t (or path query)))))
+
+;;;###autoload
+(defun denote-link-ol-follow (link)
+  "Find file of type `denote:' matching LINK.
+LINK is the identifier of the note, optionally followed by a file search
+option akin to that of standard Org `file:' link types.  Read Info
+node `(org) Query Options'.
+
+If LINK is not an identifier, then it is not pointing to a file but to a
+query of file contents or file names (see the commands
+`denote-query-contents-link' and `denote-query-filenames-link').
+
+Uses the function `denote-directory' to establish the path to the file."
+  (if-let* ((match (denote-link--ol-resolve-link-to-target link))
+            (_ (file-exists-p (string-trim-right match ":[^/]+.*"))))
+      (org-link-open-as-file match nil)
+    (denote--act-on-query-link match)))
+
+;;;###autoload
+(defun denote-link-ol-complete ()
+  "Like `denote-link' but for Org integration.
+This lets the user complete a link through the `org-insert-link'
+interface by first selecting the `denote:' hyperlink type."
+  (if-let* ((file (denote-file-prompt)))
+      (concat "denote:" (denote-retrieve-filename-identifier file))
+    (user-error "No files in `denote-directory'")))
+
+(declare-function org-link-store-props "ol.el" (&rest plist))
+(defvar org-store-link-plist)
+
+(declare-function org-entry-put "org" (pom property value))
+(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
+(declare-function org-id-new "org-id" (&optional prefix))
+
+(defun denote-link-ol-get-id ()
+  "Get the CUSTOM_ID of the current entry.
+If the entry already has a CUSTOM_ID, return it as-is, else
+create a new one."
+  (let* ((pos (point))
+         (id (org-entry-get pos "CUSTOM_ID")))
+    (if (and (stringp id) (string-match-p "\\S-" id))
+        id
+      (setq id (org-id-new "h"))
+      (org-entry-put pos "CUSTOM_ID" id)
+      id)))
+
+(declare-function org-get-heading "org" (no-tags no-todo no-priority no-comment))
+
+(defun denote-link-ol-get-heading ()
+  "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))
+
+;;;###autoload
+(defun denote-link-ol-store (&optional interactive?)
+  "Handler for `org-store-link' adding support for denote: links.
+Optional INTERACTIVE? is used by `org-store-link'.
+
+Also see the user option `denote-org-store-link-to-heading'."
+  (when interactive?
+    (when-let* ((file (buffer-file-name))
+                ((denote-file-is-note-p file))
+                (file-id (denote-retrieve-filename-identifier file))
+                (description (denote-get-link-description file)))
+      (let ((heading-links (and denote-org-store-link-to-heading
+                                (derived-mode-p 'org-mode)
+                                (denote--org-capture-link-specifiers-p)))
+            (heading (denote-link-ol-get-heading)))
+        (org-link-store-props
+         :type "denote"
+         :description (if (and heading-links heading)
+                          (denote-link-format-heading-description
+                           description
+                           heading)
+                        description)
+         :link (cond
+                ((when-let* ((id (org-entry-get (point) "CUSTOM_ID")))
+                   (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 heading)
+                 (format "denote:%s::#%s" file-id (denote-link-ol-get-id)))
+                (t
+                 (concat "denote:" file-id))))
+        org-store-link-plist))))
+
+;;;###autoload
+(defun denote-link-ol-export (link description format)
+  "Export a `denote:' link from Org files.
+The LINK, DESCRIPTION, and FORMAT are handled by the export
+backend."
+  (pcase-let* ((`(,path ,query ,file-search) (denote-link--ol-resolve-link-to-target link :full-data))
+               (anchor (when path (file-relative-name (file-name-sans-extension path))))
+               (desc (cond
+                      (description)
+                      (file-search (format "denote:%s::%s" query file-search))
+                      (t (concat "denote:" query)))))
+    (if path
+        (pcase format
+          ('html (if file-search
+                     (format "<a href=\"%s.html%s\">%s</a>" anchor file-search desc)
+                   (format "<a href=\"%s.html\">%s</a>" anchor desc)))
+          ('latex (format "\\href{%s}{%s}" (replace-regexp-in-string "[\\{}$%&_#~^]" "\\\\\\&" path) desc))
+          ('texinfo (format "@uref{%s,%s}" path desc))
+          ('ascii (format "[%s] <denote:%s>" desc path))
+          ('md (format "[%s](%s)" desc path))
+          (_ path))
+      (format-message "[[Denote query for `%s']]" query))))
+
+(defun denote-link-ol-help-echo (_window _object position)
+  "Echo the full file path of the identifier at POSITION."
+  (when-let* ((htmlize-link (get-text-property position 'htmlize-link))
+              (string (plist-get htmlize-link :uri))
+              (identifier (replace-regexp-in-string "denote:\\(.*?\\)\\(#.*\\)?" "\\1" string))
+              (path (denote-get-path-by-id identifier)))
+    path))
+
+;; The `eval-after-load' part with the quoted lambda is adapted from
+;; Elfeed: <https://github.com/skeeto/elfeed/>.
+
+;;;###autoload
+(eval-after-load 'org
+  `(funcall
+    ;; The extra quote below is necessary because uncompiled closures
+    ;; do not evaluate to themselves. The quote is harmless for
+    ;; byte-compiled function objects.
+    ',(lambda ()
+        (with-no-warnings
+          (org-link-set-parameters
+           "denote"
+           :follow #'denote-link-ol-follow
+           :face #'denote-get-link-face
+           :help-echo #'denote-link-ol-help-echo
+           :complete #'denote-link-ol-complete
+           :store #'denote-link-ol-store
+           :export #'denote-link-ol-export)))))
+
+;;;; Glue code for org-capture
+
+(defgroup denote-org-capture ()
+  "Integration between Denote and Org Capture."
+  :group 'denote)
+
+(defcustom denote-org-capture-specifiers "%l\n%i\n%?"
+  "String with format specifiers for `org-capture-templates'.
+Check that variable's documentation for the details.
+
+The string can include arbitrary text.  It is appended to new
+notes via the `denote-org-capture' function.  Every new note has
+the standard front matter we define."
+  :type 'string
+  :package-version '(denote . "0.1.0")
+  :group 'denote-org-capture)
+
+(defun denote--org-capture-link-specifiers-p ()
+  "Return non-nil if `denote-org-capture-specifiers' uses link specifiers."
+  (when (stringp denote-org-capture-specifiers)
+    (string-match-p "%^?[aAlL]" denote-org-capture-specifiers)))
+
+(defvar denote-last-path nil "Store last path.")
+
+;;;###autoload
+(defun denote-org-capture ()
+  "Create new note through `org-capture-templates'.
+Use this as a function that returns the path to the new file.
+The file is populated with Denote's front matter.  It can then be
+expanded with the usual specifiers or strings that
+`org-capture-templates' supports.
+
+This function obeys `denote-prompts', but it ignores `file-type',
+if present: it always sets the Org file extension for the created
+note to ensure that the capture process works as intended,
+especially for the desired output of the
+`denote-org-capture-specifiers' (which can include arbitrary
+text).
+
+Consult the manual for template samples."
+  (pcase-let* ((denote-prompts (remove 'file-type denote-prompts)) ; Do not prompt for file-type. We use org.
+               (`(,title ,keywords _ ,directory ,date ,template ,signature)
+                (denote--creation-get-note-data-from-prompts))
+               (`(,title ,keywords _ ,directory ,date ,id ,template ,signature)
+                (denote--creation-prepare-note-data title keywords 'org directory date template signature))
+               (front-matter (denote--format-front-matter title date keywords id signature 'org))
+               (template-string (cond ((stringp template) template)
+                                      ((functionp template) (funcall template))
+                                      (t (user-error "Invalid template")))))
+    (setq denote-last-path
+          (denote-format-file-name directory id keywords title ".org" signature))
+    (when (file-regular-p denote-last-path)
+      (user-error "A file named `%s' already exists" denote-last-path))
+    (denote--keywords-add-to-history keywords)
+    (concat front-matter template-string denote-org-capture-specifiers)))
+
+;; TODO 2023-12-02: Maybe simplify `denote-org-capture-with-prompts'
+;; by passing a single PROMPTS that is the same value as `denote-prompts'?
+
+;;;###autoload
+(defun denote-org-capture-with-prompts (&optional title keywords subdirectory date template)
+  "Like `denote-org-capture' but with optional prompt parameters.
+
+When called without arguments, do not prompt for anything.  Just
+return the front matter with title and keyword fields empty and
+the date and identifier fields specified.  Also make the file
+name consist of only the identifier plus the Org file name
+extension.
+
+Otherwise produce a minibuffer prompt for every non-nil value
+that corresponds to the TITLE, KEYWORDS, SUBDIRECTORY, DATE, and
+TEMPLATE arguments.  The prompts are those used by the standard
+`denote' command and all of its utility commands.
+
+When returning the contents that fill in the Org capture
+template, the sequence is as follows: front matter, TEMPLATE, and
+then the value of the user option `denote-org-capture-specifiers'.
+
+Important note: in the case of SUBDIRECTORY actual subdirectories
+must exist---Denote does not create them.  Same principle for
+TEMPLATE as templates must exist and are specified in the user
+option `denote-templates'."
+  (let ((denote-prompts '()))
+    (when template (push 'template denote-prompts))
+    (when date (push 'date denote-prompts))
+    (when subdirectory (push 'subdirectory denote-prompts))
+    (when keywords (push 'keywords denote-prompts))
+    (when title (push 'title denote-prompts))
+    (denote-org-capture)))
+
+(defun denote-org-capture-delete-empty-file ()
+  "Delete file if capture with `denote-org-capture' is aborted."
+  (when-let* ((file denote-last-path)
+              ((denote--file-empty-p file)))
+    (delete-file denote-last-path)))
+
+(add-hook 'org-capture-after-finalize-hook #'denote-org-capture-delete-empty-file)
+
+;;;; The `denote-rename-buffer-mode'
+
+(defgroup denote-rename-buffer nil
+  "Rename Denote buffers to be shorter and easier to read."
+  :group 'denote
+  :link '(info-link "(denote) Top")
+  :link '(url-link :tag "Homepage" "https://protesilaos.com/emacs/denote"))
+
+(defvaralias 'denote-buffer-has-backlinks-string 'denote-rename-buffer-backlinks-indicator
+  "Alias for `denote-rename-buffer-backlinks-indicator'.")
+
+(defcustom denote-rename-buffer-backlinks-indicator " <-->"
+  "A string used to indicate that a buffer has backlinks pointing to it."
+  :type 'string
+  :package-version '(denote . "3.1.0")
+  :group 'denote-rename-buffer)
+
+(defcustom denote-rename-buffer-format "[D] %D%b"
+  "The format of the buffer name `denote-rename-buffer' should use.
+The value is a string that treats specially the following specifiers:
+
+- The %t is the Denote TITLE in the front matter or the file name.
+- The %T is the Denote TITLE in the file name.
+- The %i is the Denote IDENTIFIER of the file.
+- The %I is the identifier converted to DAYNAME, DAYNUM MONTHNUM YEAR.
+- The %d is the same as %i (DATE mnemonic).
+- The %D is a \"do what I mean\" which behaves the same as %t and if
+  that returns nothing, it falls back to %I, then %i.
+- The %s is the Denote SIGNATURE of the file.
+- The %k is the Denote KEYWORDS of the file.
+- The %b inserts `denote-rename-buffer-backlinks-indicator'.
+- The %% is a literal percent sign.
+
+In addition, the following flags are available for each of the specifiers:
+
+- 0 :: Pad to the width, if given, with zeros instead of spaces.
+- - :: Pad to the width, if given, on the right instead of the left.
+- < :: Truncate to the width and precision, if given, on the left.
+- > :: Truncate to the width and precision, if given, on the right.
+- ^ :: Convert to upper case.
+- _ :: Convert to lower case.
+
+When combined all together, the above are written thus:
+
+    %<flags><width><precision>SPECIFIER-CHARACTER
+
+Any other string it taken as-is.  Users may want, for example, to
+include some text that makes Denote buffers stand out, such as
+a [D] prefix."
+  :type 'string
+  :package-version '(denote . "4.0.0")
+  :group 'denote-rename-buffer)
+
+(defcustom denote-rename-buffer-function #'denote-rename-buffer
+  "Symbol of function that is called to rename the Denote file buffer.
+The default `denote-rename-buffer' function uses the pattern
+described in `denote-rename-buffer-format'.
+
+Users can set this variable to an arbitrary function that does
+something else.  The function is called without arguments from
+the `find-file-hook' and `denote-after-new-note-hook'.
+
+A nil value for this variable means that the title of the Denote
+buffer will be used, if available."
+  :type '(choice
+          (const :tag "Rename using the `denote-rename-buffer-format'" denote-rename-buffer)
+          (function :tag "Use a custom renaming function"))
+  :package-version '(denote . "2.1.0")
+  :group 'denote-rename-buffer)
+
+(defun denote-rename-buffer--format (buffer)
+  "Parse the BUFFER through the `denote-rename-buffer-format'."
+  (when-let* ((file (buffer-file-name buffer)))
+    (let ((type (denote-filetype-heuristics file))
+          (should-show-backlink-indicator (and ; only do search if format contains "%b"
+                                           (string-match-p "%b" denote-rename-buffer-format)
+                                           (denote--file-has-backlinks-p file))))
+      (string-trim
+       (format-spec denote-rename-buffer-format
+                    (list (cons ?t (cond
+                                    ((denote-retrieve-front-matter-title-value file type))
+                                    ((denote-retrieve-filename-title file))
+                                    (t  "")))
+                          (cons ?T (or (denote-retrieve-filename-title file) ""))
+                          (cons ?b (if should-show-backlink-indicator denote-rename-buffer-backlinks-indicator ""))
+                          (cons ?i (or (denote-retrieve-filename-identifier file) ""))
+                          ;; TODO 2025-04-03: Maybe we can have something like `denote-date-format' here,
+                          ;; but I think we are okay with a hardcoded value.
+                          (cons ?I (or (when-let* ((id (denote-retrieve-filename-identifier file))
+                                                   (_ (denote-valid-date-p id)))
+                                         (format-time-string "%A, %e %B %Y" (date-to-time (denote--id-to-date id))))
+                                       ""))
+                          (cons ?d (or (denote-retrieve-filename-identifier file) ""))
+                          (cons ?D (cond
+                                    ((denote-retrieve-front-matter-title-value file type))
+                                    ((denote-retrieve-filename-title file))
+                                    ((when-let* ((id (denote-retrieve-filename-identifier file)))
+                                       (if (denote-valid-date-p id)
+                                           (format-time-string "%A, %e %B %Y" (date-to-time (denote--id-to-date id)))
+                                         id)))
+                                    (t  "")))
+                          (cons ?s (or (denote-retrieve-filename-signature file) ""))
+                          (cons ?k (or (denote-retrieve-filename-keywords file) ""))
+                          (cons ?% "%"))
+                    'delete)))))
+
+(defun denote-rename-buffer (&optional buffer)
+  "Rename current buffer or optional BUFFER with `denote-rename-buffer-format'.
+The symbol of this function is the default value of the user
+option `denote-rename-buffer-function' and is thus used by the
+`denote-rename-buffer-mode'."
+  (when-let* ((file (buffer-file-name buffer))
+              ((denote-file-has-identifier-p file))
+              (new-name (denote-rename-buffer--format (or buffer (current-buffer))))
+              ((not (string-blank-p new-name))))
+    (rename-buffer new-name :unique)))
+
+(defun denote-rename-buffer--fallback (&optional buffer)
+  "Fallback to rename BUFFER or `current-buffer'.
+This is called if `denote-rename-buffer-rename-function' is nil."
+  (let ((denote-rename-buffer-format "%t"))
+    (denote-rename-buffer buffer)))
+
+(defun denote-rename-buffer-rename-function-or-fallback ()
+  "Call `denote-rename-buffer-function' or its fallback to rename with title.
+Add this to `find-file-hook' and `denote-after-new-note-hook'."
+  (funcall (or denote-rename-buffer-function #'denote-rename-buffer--fallback)))
+
+;;;###autoload
+(define-minor-mode denote-rename-buffer-mode
+  "Automatically rename Denote buffers to be easier to read.
+A buffer is renamed upon visiting the underlying file.  This
+means that existing buffers are not renamed until they are
+visited again in a new buffer (files are visited with the command
+`find-file' or related)."
+  :global t
+  (if denote-rename-buffer-mode
+      (progn
+        (add-hook 'denote-after-new-note-hook #'denote-rename-buffer-rename-function-or-fallback)
+        (add-hook 'denote-after-rename-file-hook #'denote-rename-buffer-rename-function-or-fallback)
+        (add-hook 'find-file-hook #'denote-rename-buffer-rename-function-or-fallback))
+    (remove-hook 'denote-after-new-note-hook #'denote-rename-buffer-rename-function-or-fallback)
+    (remove-hook 'denote-after-rename-file-hook #'denote-rename-buffer-rename-function-or-fallback)
+    (remove-hook 'find-file-hook #'denote-rename-buffer-rename-function-or-fallback)))
+
+(provide 'denote)
+;;; denote.el ends here
blob - /dev/null
blob + dd891fd99baccd292a21829dfff25ae0881f2082 (mode 644)
Binary files /dev/null and elpa/denote-4.0.0/denote.info differ
blob - /dev/null
blob + f87165c99de687bfbadf03e7d99cf25a1a5a2530 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/dir
@@ -0,0 +1,19 @@
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+
+File: dir,	Node: Top	This is the top of the INFO tree
+
+  This (the Directory node) gives a menu of major topics.
+  Typing "q" exits, "H" lists all Info commands, "d" returns here,
+  "h" gives a primer for first-timers,
+  "mEmacs<Return>" visits the Emacs manual, etc.
+
+  In Emacs, you can click mouse button 2 on a menu item or cross reference
+  to select it.
+
+* Menu:
+
+Emacs misc features
+* Denote: (denote).             Simple notes with an efficient file-naming 
+                                  scheme.
blob - /dev/null
blob + 1025c345c029f57bf021a7791a18ed79ab2099a0 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0/tests/denote-test.el
@@ -0,0 +1,545 @@
+;;; denote-test.el --- Unit tests for Denote -*- lexical-binding: t -*-
+
+;; Copyright (C) 2023-2025  Free Software Foundation, Inc.
+
+;; Author: Protesilaos Stavrou <info@protesilaos.com>
+;; Maintainer: Protesilaos Stavrou <info@protesilaos.com>
+;; URL: https://github.com/protesilaos/denote
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for Denote.  Note that we are using Shorthands in this file,
+;; so the "dt-" prefix really is "denote-test-".  Evaluate the
+;; following to learn more:
+;;
+;;    (info "(elisp) Shorthands")
+
+;;; Code:
+
+(require 'ert)
+
+;;;; Tests for denote.el
+
+(require 'denote)
+
+(ert-deftest dt-denote--make-denote-directory ()
+  "Test that `denote--make-denote-directory' creates the directory."
+  (should (null (denote--make-denote-directory))))
+
+(ert-deftest dt-denote-directory ()
+  "Test that variable `denote-directory' returns an absolute directory name."
+  (let ((path (denote-directory)))
+    (should (and (file-directory-p path)
+                 (file-name-absolute-p path)))))
+
+(ert-deftest dt-denote-sluggify-title ()
+  "Test that `denote-sluggify-title' removes punctuation from the string.
+Concretely, remove anything specified in `denote-sluggify-title'."
+  (should (equal (denote-sluggify-title "this-is-!@#test")
+                 "this-is-test")))
+
+(ert-deftest dt-denote-slug-keep-only-ascii ()
+  "Test that `denote-slug-keep-only-ascii' removes non-ASCII characters."
+  (should (equal
+           (denote-slug-keep-only-ascii "There are no-ASCII : characters | here 😀")
+           "There are no-ASCII   characters   here  ")))
+
+(ert-deftest dt-denote-slug-hyphenate ()
+  "Test that `denote-slug-hyphenate' hyphenates the string.
+Also replace multiple hyphens with a single one and remove any
+leading and trailing hyphen."
+  (should (equal (denote-slug-hyphenate "__  This is   a    test  __  ")
+                 "This-is-a-test")))
+
+(ert-deftest dt-denote-sluggify ()
+  "Test that `denote-sluggify' sluggifies the string.
+To sluggify is to (i) downcase, (ii) hyphenate, (iii) de-punctuate, and (iv) remove spaces from the string."
+  (should (equal (denote-sluggify 'title " ___ !~!!$%^ This iS a tEsT ++ ?? ")
+                 "this-is-a-test")))
+
+(ert-deftest Ddenote--slug-put-equals ()
+  "Test that `denote-slug-put-equals' replaces spaces/underscores with =.
+Otherwise do the same as what is described in
+`dt-denote-slug-hyphenate'.
+
+The use of the equals sign is for the SIGNATURE field of the
+Denote file name."
+  (should (equal (denote-slug-put-equals "__  This is   a    test  __  ")
+                 "This=is=a=test")))
+
+(ert-deftest dt-denote-sluggify-signature ()
+  "Test that `denote-sluggify-signature' sluggifies the string for file signatures.
+This is like `dt-denote-sluggify', except that it also
+accounts for what we describe in `dt-denote-slug-put-equals'."
+  (should (equal (denote-sluggify-signature "--- ___ !~!!$%^ This -iS- a tEsT ++ ?? ")
+                 "this=is=a=test")))
+
+(ert-deftest dt-denote-sluggify-keyword ()
+  "Test that `denote-sluggify-keyword' sluggifies the string while joining words.
+In this context, to join words is to elimitate any space or
+delimiter between them.
+
+Otherwise, this is like `dt-denote-sluggify'."
+  (should (equal (denote-sluggify-keyword "--- ___ !~!!$%^ This iS a - tEsT ++ ?? ")
+                 "thisisatest")))
+
+(ert-deftest dt-denote-sluggify-keywords ()
+  "Test that `denote-sluggify-keywords' sluggifies a list of strings.
+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--file-empty-p ()
+  "Test that `denote--file-empty-p' returns non-nil on empty file."
+  ;; (should (null (denote--file-empty-p user-init-file))
+  (should (let ((file (make-temp-file "denote-test")))
+            (prog1
+                (denote--file-empty-p file)
+              (delete-file file)))))
+
+(ert-deftest dt-denote-file-is-note-p ()
+  "Test that `denote-file-is-note-p' checks that files is a Denote note.
+For our purposes, a note must note be a directory, must satisfy
+`file-regular-p', its path must be part of the variable
+`denote-directory', it must have a Denote identifier in its name,
+and use one of the extensions implied by the variable `denote-file-type'."
+  (should (let* ((tmp (temporary-file-directory))
+                 (denote-directory tmp)
+                 (file (concat tmp "20230522T154900--test__keyword.txt")))
+            (with-current-buffer (find-file-noselect file)
+              (write-file file))
+            (prog1
+                (denote-file-is-note-p file)
+              (delete-file file)))))
+
+(ert-deftest dt-denote-file-has-identifier-p ()
+  "Test that `denote-file-has-identifier-p' checks for a Denote identifier."
+  (should (denote-file-has-identifier-p "20230522T154900--test__keyword.txt"))
+  (should (null (denote-file-has-identifier-p "T154900--test__keyword.txt"))))
+
+(ert-deftest dt-denote-file-has-signature-p ()
+  "Test that `denote-file-has-signature-p' checks for a Denote signature."
+  (should (denote-file-has-signature-p "20230522T154900==sig--test__keyword.txt"))
+  (should (null (denote-file-has-signature-p "20230522T154900--test__keyword.txt"))))
+
+(ert-deftest dt-denote-file-has-supported-extension-p ()
+  "Test that `denote-file-has-supported-extension-p' matches a supported extension."
+  (should
+   (member
+    (file-name-extension "20230522T154900==sig--test__keyword.txt" :period)
+    (denote-file-type-extensions-with-encryption)))
+  (should
+   (null
+    (member
+     (file-name-extension "20230522T154900==sig--test__keyword" :period)
+     (denote-file-type-extensions-with-encryption)))))
+
+(ert-deftest dt-denote-file-type-extensions ()
+  "Test that `denote-file-type-extensions' returns file extensions.
+We check for the common file type extensions, though the user can
+theoretically set `denote-file-types' to nil and handle things on
+their own.  We do not have to test for that scenario, because
+such a user will be redefining large parts of Denote's behaviour
+with regard to file types."
+  (let ((extensions (denote-file-type-extensions)))
+    (should (or (member ".md" extensions)
+                (member ".org" extensions)
+                (member ".txt" extensions)))))
+
+(ert-deftest dt-denote-file-type-extensions-with-encryption ()
+  "Test that `denote-file-type-extensions-with-encryption' covers encryption.
+Extend what we do in `dt-denote-file-type-extensions'."
+  (let ((extensions (denote-file-type-extensions-with-encryption)))
+    (should (or (member ".md" extensions)
+                (member ".org" extensions)
+                (member ".txt" extensions)
+                (member ".md.gpg" extensions)
+                (member ".org.gpg" extensions)
+                (member ".txt.gpg" extensions)
+                (member ".md.age" extensions)
+                (member ".org.age" extensions)
+                (member ".txt.age" extensions)))))
+
+(ert-deftest dt-denote--format-front-matter ()
+  "Test that `denote--format-front-matter' formats front matter correctly.
+To make the test reproducible, set `denote-date-format' to a value that
+does not involve the time zone."
+  (let ((denote-date-format "%Y-%m-%d")
+        (denote-front-matter-components-present-even-if-empty-value '(title keywords signature date identifier)))
+    (should (and (equal (denote--format-front-matter "" (date-to-time "20240101T120000") '("") "" "" 'text)
+                        (mapconcat #'identity
+                                   '("title:      "
+                                     "date:       2024-01-01"
+                                     "tags:       "
+                                     "identifier: "
+                                     "signature:  "
+                                     "---------------------------\n\n")
+                                   "\n"))
+
+                 (equal
+                  (denote--format-front-matter
+                   "Some test" (date-to-time "2023-06-05") '("one" "two")
+                   "20230605T102234" "sig" 'text)
+                  (mapconcat #'identity
+                             '("title:      Some test"
+                               "date:       2023-06-05"
+                               "tags:       one  two"
+                               "identifier: 20230605T102234"
+                               "signature:  sig"
+                               "---------------------------\n\n")
+                             "\n"))))
+
+    (should (and (equal (denote--format-front-matter "" (date-to-time "20240101T120000") nil "" "" 'org)
+                        (mapconcat #'identity
+                                   '("#+title:      "
+                                     "#+date:       2024-01-01"
+                                     "#+filetags:   "
+                                     "#+identifier: "
+                                     "#+signature:  "
+                                     "\n")
+                                   "\n"))
+
+                 (equal
+                  (denote--format-front-matter
+                   "Some test" (date-to-time "2023-06-05") '("one" "two")
+                   "20230605T102234" "sig" 'org)
+                  (mapconcat #'identity
+                             '("#+title:      Some test"
+                               "#+date:       2023-06-05"
+                               "#+filetags:   :one:two:"
+                               "#+identifier: 20230605T102234"
+                               "#+signature:  sig"
+                               "\n")
+                             "\n"))))
+
+    (should (and (equal (denote--format-front-matter "" (date-to-time "20240101T120000") nil "" "" 'markdown-yaml)
+                        (mapconcat #'identity
+                                   '("---"
+                                     "title:      \"\""
+                                     "date:       2024-01-01"
+                                     "tags:       []"
+                                     "identifier: \"\""
+                                     "signature:  \"\""
+                                     "---"
+                                     "\n")
+                                   "\n"))
+
+                 (equal
+                  (denote--format-front-matter
+                   "Some test" (date-to-time "2023-06-05") '("one" "two")
+                   "20230605T102234" "sig" 'markdown-yaml)
+                  (mapconcat #'identity
+                             '("---"
+                               "title:      \"Some test\""
+                               "date:       2023-06-05"
+                               "tags:       [\"one\", \"two\"]"
+                               "identifier: \"20230605T102234\""
+                               "signature:  \"sig\""
+                               "---"
+                               "\n")
+                             "\n"))))
+
+    (should (and (equal (denote--format-front-matter "" (date-to-time "20240101T120000") nil "" "" 'markdown-toml)
+                        (mapconcat #'identity
+                                   '("+++"
+                                     "title      = \"\""
+                                     "date       = 2024-01-01"
+                                     "tags       = []"
+                                     "identifier = \"\""
+                                     "signature  = \"\""
+                                     "+++"
+                                     "\n")
+                                   "\n"))
+
+                 (equal
+                  (denote--format-front-matter
+                   "Some test" (date-to-time "2023-06-05") '("one" "two")
+                   "20230605T102234" "sig" 'markdown-toml)
+                  (mapconcat #'identity
+                             '("+++"
+                               "title      = \"Some test\""
+                               "date       = 2023-06-05"
+                               "tags       = [\"one\", \"two\"]"
+                               "identifier = \"20230605T102234\""
+                               "signature  = \"sig\""
+                               "+++"
+                               "\n")
+                             "\n"))))))
+
+(ert-deftest dt-denote-format-file-name ()
+  "Test that `denote-format-file-name' returns all expected paths."
+  (let* ((title "Some test")
+         (id (format-time-string denote-id-format (denote-valid-date-p "2023-11-28 05:53:11")))
+         (denote-directory "/tmp/test-denote")
+         (kws '("one" "two")))
+    (should-error (denote-format-file-name
+                    nil
+                    id
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    ""))
+
+    (should-error (denote-format-file-name
+                    ""
+                    id
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    ""))
+
+    (should-error (denote-format-file-name
+                   denote-directory ; notice this is the `let' bound value without the suffix
+                   id
+                   kws
+                   title
+                   (denote--file-extension 'org)
+                   ""))
+
+    (should-error (denote-format-file-name
+                   (denote-directory)
+                   ""
+                   nil
+                   ""
+                   (denote--file-extension 'org)
+                   ""))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    nil
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    "")
+                   "/tmp/test-denote/--some-test__one_two.org"))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    ""
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    "")
+                   "/tmp/test-denote/--some-test__one_two.org"))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    "0123456"
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    "")
+                   "/tmp/test-denote/@@0123456--some-test__one_two.org"))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    id
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    "")
+                   "/tmp/test-denote/20231128T055311--some-test__one_two.org"))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    id
+                    nil
+                    ""
+                    (denote--file-extension 'org)
+                    "")
+                   "/tmp/test-denote/20231128T055311.org"))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    id
+                    nil
+                    nil
+                    (denote--file-extension 'org)
+                    nil)
+                   "/tmp/test-denote/20231128T055311.org"))
+
+    (should (equal (denote-format-file-name
+                    (denote-directory)
+                    id
+                    kws
+                    title
+                    (denote--file-extension 'org)
+                    "sig")
+                   "/tmp/test-denote/20231128T055311==sig--some-test__one_two.org"))))
+
+(ert-deftest dt-denote-get-file-extension ()
+  "Test that `denote-get-file-extension' gets the correct file extension."
+  (should (and (equal (denote-get-file-extension "20231010T105034--some-test-file__denote_testing") "")
+               (equal (denote-get-file-extension "20231010T105034--some-test-file__denote_testing.org") ".org")
+               (equal (denote-get-file-extension "20231010T105034--some-test-file__denote_testing.org.gpg") ".org.gpg")
+               (equal (denote-get-file-extension "20231010T105034--some-test-file__denote_testing.org.age") ".org.age"))))
+
+(ert-deftest dt-denote-get-file-extension-sans-encryption ()
+  "Test that `denote-get-file-extension-sans-encryption' gets the file extension without encryption."
+  (should (and (equal (denote-get-file-extension-sans-encryption "20231010T105034--some-test-file__denote_testing") "")
+               (equal (denote-get-file-extension-sans-encryption "20231010T105034--some-test-file__denote_testing.org") ".org")
+               (equal (denote-get-file-extension-sans-encryption "20231010T105034--some-test-file__denote_testing.org.gpg") ".org")
+               (equal (denote-get-file-extension-sans-encryption "20231010T105034--some-test-file__denote_testing.org.age") ".org"))))
+
+(ert-deftest dt-denote-filetype-heuristics ()
+  "Test that `denote-filetype-heuristics' gets the correct file type."
+  (should (and (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing") nil)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.org") 'org)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.org.gpg") 'org)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.org.age") 'org)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.txt") 'text)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.txt.gpg") 'text)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.txt.age") 'text)
+               ;; NOTE 2023-10-11: It returns `markdown-yaml' as a fallback.  In
+               ;; an actual file, it reads the file contents to determine what
+               ;; it is and can return `markdown-toml'.  In principle, we should
+               ;; be testing this here, though I prefer to keep things simple.
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.md") 'markdown-yaml)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.md.gpg") 'markdown-yaml)
+               (eq (denote-filetype-heuristics "20231010T105034--some-test-file__denote_testing.md.age") 'markdown-yaml))))
+
+(ert-deftest dt-denote-get-identifier ()
+  "Test that `denote-get-identifier' returns an identifier."
+  (should (and (equal (denote-get-identifier nil) "")
+               (equal (denote-get-identifier 1705644188) "20240119T080308")
+               (equal (denote-get-identifier '(26026 4251)) "20240119T080307"))))
+
+(ert-deftest dt-denote-retrieve-filename-identifier ()
+  "Test that `denote-retrieve-filename-identifier' returns only the identifier."
+  (should (and (null
+                (denote-retrieve-filename-identifier "/path/to/testing/--this-is-a-test-reordered__denote_testing.org"))
+               (equal
+                (denote-retrieve-filename-identifier "/path/to/testing/20240610T194654--this-is-a-test-reordered__denote_testing.org")
+                "20240610T194654")
+               (equal
+                (denote-retrieve-filename-identifier "/path/to/testing/20240610T194654==signature--this-is-a-test-reordered__denote_testing.org")
+                "20240610T194654")
+               (equal
+                (denote-retrieve-filename-identifier "/path/to/testing/--this-is-a-test-reordered__denote_testing@@20240610T194654.org")
+                "20240610T194654")
+               (equal
+                (denote-retrieve-filename-identifier "/path/to/testing/__denote_testing--this-is-a-test-reordered@@20240610T194654.org")
+                "20240610T194654")
+               (equal
+                (denote-retrieve-filename-identifier "/path/to/testing/__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "20240610T194654")
+               (equal
+                (denote-retrieve-filename-identifier "/path/to/testing/==signature__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "20240610T194654"))))
+
+(ert-deftest dt-denote-retrieve-filename-title ()
+  "Test that `denote-retrieve-filename-title' returns only the title."
+  (should (and (null
+                (denote-retrieve-filename-title "/path/to/testing/20240610T194654__denote_testing.org"))
+               (equal
+                (denote-retrieve-filename-title "/path/to/testing/20240610T194654--this-is-a-test-reordered__denote_testing.org")
+                "this-is-a-test-reordered")
+               (equal
+                (denote-retrieve-filename-title "/path/to/testing/20240610T194654==signature--this-is-a-test-reordered__denote_testing.org")
+                "this-is-a-test-reordered")
+               (equal
+                (denote-retrieve-filename-title "/path/to/testing/--this-is-a-test-reordered__denote_testing@@20240610T194654.org")
+                "this-is-a-test-reordered")
+               (equal
+                (denote-retrieve-filename-title "/path/to/testing/__denote_testing--this-is-a-test-reordered@@20240610T194654.org")
+                "this-is-a-test-reordered")
+               (equal
+                (denote-retrieve-filename-title "/path/to/testing/__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "this-is-a-test-reordered")
+               (equal
+                (denote-retrieve-filename-title "/path/to/testing/==signature__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "this-is-a-test-reordered"))))
+
+(ert-deftest dt-denote-retrieve-filename-keywords ()
+  "Test that `denote-retrieve-filename-keywords' returns only the keywords."
+  (should (and (null
+                (denote-retrieve-filename-keywords "/path/to/testing/20240610T194654--this-is-a-test-reordered.org"))
+               (equal
+                (denote-retrieve-filename-keywords "/path/to/testing/20240610T194654--this-is-a-test-reordered__denote_testing.org")
+                "denote_testing")
+               (equal
+                (denote-retrieve-filename-keywords "/path/to/testing/20240610T194654==signature--this-is-a-test-reordered__denote_testing.org")
+                "denote_testing")
+               (equal
+                (denote-retrieve-filename-keywords "/path/to/testing/--this-is-a-test-reordered__denote_testing@@20240610T194654.org")
+                "denote_testing")
+               (equal
+                (denote-retrieve-filename-keywords "/path/to/testing/__denote_testing--this-is-a-test-reordered@@20240610T194654.org")
+                "denote_testing")
+               (equal
+                (denote-retrieve-filename-keywords "/path/to/testing/__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "denote_testing")
+               (equal
+                (denote-retrieve-filename-keywords "/path/to/testing/==signature__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "denote_testing"))))
+
+(ert-deftest dt-denote-retrieve-filename-signature ()
+  "Test that `denote-retrieve-filename-signature' returns only the signature."
+  (should (and (null
+                (denote-retrieve-filename-signature "/path/to/testing/20240610T194654--this-is-a-test-reordered__denote_testing.org"))
+               (equal
+                (denote-retrieve-filename-signature "/path/to/testing/20240610T194654==signature--this-is-a-test-reordered__denote_testing.org")
+                "signature")
+               (equal
+                (denote-retrieve-filename-signature "/path/to/testing/--this-is-a-test-reordered==signature__denote_testing@@20240610T194654.org")
+                "signature")
+               (equal
+                (denote-retrieve-filename-signature "/path/to/testing/__denote_testing--this-is-a-test-reordered==signature@@20240610T194654.org")
+                "signature")
+               (equal
+                (denote-retrieve-filename-signature "/path/to/testing/__denote_testing@@20240610T194654--this-is-a-test-reordered==signature.org")
+                "signature")
+               (equal
+                (denote-retrieve-filename-signature "/path/to/testing/==signature__denote_testing@@20240610T194654--this-is-a-test-reordered.org")
+                "signature"))))
+
+(ert-deftest dt-denote-identifier-p ()
+  "Test that `denote-identifier-p' works for Denote identifiers."
+  (should (and (denote-identifier-p "20240901T090910")
+               (null (denote-identifier-p "20240901T090910-not-identifier-format")))))
+
+(ert-deftest dt-denote--id-to-date ()
+  "Test that `denote--id-to-date' returns the date from an identifier."
+  (should (equal (denote--id-to-date "20240901T090910") "2024-09-01"))
+  (should-error (denote--id-to-date "20240901T090910-not-identifier-format")))
+
+(ert-deftest dt-denote--date-convert ()
+  "Test that `denote--date-convert' works with dates."
+  (should (and
+           (equal (denote--date-convert '(26454 45206 461174 657000) :list)
+                  '(26454 45206 461174 657000))
+
+           (equal (denote--date-convert '(26454 45206 461174 657000) :string)
+                  "2024-12-09 10:55:50")
+
+           (equal (denote--date-convert nil :string)
+                  "")
+
+           (equal (denote--date-convert nil :list)
+                  nil)))
+  (should-error (denote--date-convert '(26454 45206 461174 657000) :not-valid-type))
+  (should-error (denote--date-convert nil :not-valid-type)))
+
+(provide 'denote-test)
+;;; denote-test.el ends here
+
+;; Local Variables:
+;; read-symbol-shorthands: (("dt" . "denote-test-"))
+;; End:
blob - /dev/null
blob + 02a9d0609cc8457e6e5090424ec533b0e65a7c26 (mode 644)
--- /dev/null
+++ elpa/denote-4.0.0.signed
@@ -0,0 +1 @@
+Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2025-04-15T23:10:04+0200 using EDDSA
\ No newline at end of file
blob - /dev/null
blob + b25586baccfaf0140555f8c08a091c50ef46582d (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/.elpaignore
@@ -0,0 +1,2 @@
+COPYING
+doclicense.texi
blob - /dev/null
blob + 3fff0b808826c4f93d106ceea1e95751f6c6cd6c (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/README-elpa
@@ -0,0 +1,737 @@
+           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+             DENOTE-ORG: EXTENSIONS TO BETTER INTEGRATE ORG
+                              WITH DENOTE
+
+                          Protesilaos Stavrou
+                          info@protesilaos.com
+           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+
+This manual, written by Protesilaos Stavrou, describes the customization
+options for the Emacs package called `denote' (or `denote.el'), and
+provides every other piece of information pertinent to it.
+
+The documentation furnished herein corresponds to stable version 0.1.0,
+released on 2025-04-15.  Any reference to a newer feature which does not
+yet form part of the latest tagged commit, is explicitly marked as such.
+
+Current development target is 0.2.0-dev.
+
+⁃ Package name (GNU ELPA): `denote-org'
+⁃ Official manual: <https://protesilaos.com/emacs/denote-org>
+⁃ Git repository: <https://github.com/protesilaos/denote-org>
+⁃ Backronym: Denote… Ordinarily Restricts Gyrations.
+
+If you are viewing the README.org version of this file, please note that
+the GNU ELPA machinery automatically generates an Info manual out of it.
+
+Table of Contents
+─────────────────
+
+1. COPYING
+2. Overview
+3. Use Org dynamic blocks
+.. 1. Org dynamic blocks to insert links
+.. 2. The Org dynamic block to insert missing links only
+.. 3. The Org dynamic block to insert backlinks
+.. 4. Org dynamic block to insert file contents
+.. 5. Org dynamic block to insert Org files as headings
+4. Create a note from the current Org subtree
+5. Insert link to an Org file with a further pointer to a heading
+.. 1. Backlinks for Org headings
+6. Convert `denote:' links to `file:' links in Org and vice versa
+7. Installation
+.. 1. GNU ELPA package
+.. 2. Manual installation
+8. Sample configuration
+9. Acknowledgements
+10. GNU Free Documentation License
+11. Indices
+.. 1. Function index
+.. 2. Variable index
+.. 3. Concept index
+
+
+1 COPYING
+═════════
+
+  Copyright (C) 2022-2025 Free Software Foundation, Inc.
+
+        Permission is granted to copy, distribute and/or modify
+        this document under the terms of the GNU Free
+        Documentation License, Version 1.3 or any later version
+        published by the Free Software Foundation; with no
+        Invariant Sections, with the Front-Cover Texts being “A
+        GNU Manual,” and with the Back-Cover Texts as in (a)
+        below.  A copy of the license is included in the section
+        entitled “GNU Free Documentation License.”
+
+        (a) The FSF’s Back-Cover Text is: “You have the freedom to
+        copy and modify this GNU manual.”
+
+
+2 Overview
+══════════
+
+  The `denote-org' package contains extra features that better integrate
+  Denote with Org mode. These used to be available as part of the main
+  `denote' package in a file called `denote-org-extras.el', but now live
+  in this standalone package to main things easier to maintain and
+  understand.
+
+  With `denote-org', users have Org-specific extensions such as dynamic
+  blocks, links to headings, and splitting an Org subtree into its own
+  standalone file. The following sections cover the technicalities.
+
+
+3 Use Org dynamic blocks
+════════════════════════
+
+  Denote can optionally integrate with Org mode’s “dynamic blocks”
+  facility. This means that it can use special blocks that are evaluated
+  with `C-c C-x C-u' (`org-dblock-update') to generate their contents.
+  The following subsections describe the types of Org dynamic blocks
+  provided by Denote.
+
+  • [Org dynamic blocks to insert links or backlinks]
+  • [Org dynamic block to insert file contents]
+
+  A dynamic block gets its contents by evaluating a function that
+  corresponds to the type of block. The block type and its parameters
+  are stated in the opening `#+BEGIN' line. Typing `C-c C-x C-u'
+  (`org-dblock-update') with point on that line runs (or re-runs) the
+  associated function with the given parameters and populates the
+  block’s contents accordingly.
+
+  Dynamic blocks are particularly useful for metanote entries that
+  reflect on the status of earlier notes (read the Denote manual’s
+  section about writing metanotes).
+
+  The Org manual describes the technicalities of Dynamic Blocks.
+  Evaluate:
+
+  ┌────
+  │ (info "(org) Dynamic Blocks")
+  └────
+
+
+[Org dynamic blocks to insert links or backlinks] See section 3.1
+
+[Org dynamic block to insert file contents] See section 3.4
+
+3.1 Org dynamic blocks to insert links
+──────────────────────────────────────
+
+  The `denote-links' block can be inserted at point with the command
+  `denote-org-dblock-insert-links' or by manually including the
+  following in an Org file:
+
+  ┌────
+  │ #+BEGIN: denote-links :regexp "YOUR REGEXP HERE" :not-regexp :excluded-dirs-regexp nil :sort-by-component nil :reverse-sort nil :id-only nil :include-date nil
+  │ 
+  │ #+END:
+  └────
+
+
+  All the parameters except for `:regexp' are optional.
+
+  The `denote-links' block is also registered as an option for the
+  command `org-dynamic-block-insert-dblock'.
+
+  Type `C-c C-x C-u' (`org-dblock-update') with point on the `#+BEGIN'
+  line to update the block.
+
+  • The `:regexp' parameter is mandatory. Its value is a string and its
+    behaviour is the same as that of the standard `denote-add-links'
+    command (part of the main `denote' package). Concretely, it produces
+    a typographic list of links to files matching the giving regular
+    expression. The value of the `:regexp' parameter may also be of the
+    form read by the `rx' macro (Lisp notation instead of a string), as
+    explained in the Emacs Lisp Reference Manual (evaluate this code to
+    read the documentation: `(info "(elisp) Rx Notation")'). Note that
+    you do not need to write an actual regular expression to get
+    meaningful results: even something like `_journal' will work to
+    include all files that have a `journal' keyword.
+
+  • The `:not-regexp' parameter is optional. It is a regular expression
+    that applies after `:regexp' to filter out the matching files.
+
+  • The `:excluded-dirs-regexp' is a string that contains a word or
+    regular expression that matches against directory files names
+    to-be-excluded from the results. This has the same meaning as
+    setting the `denote-excluded-directories-regexp' user option (which
+    is part of the main `denote' package). The user option has a global
+    effect, which is overridden locally in the dynamic block. When the
+    value of `:excluded-dirs-regexp' is nil (the default), the value of
+    `denote-excluded-directories-regexp' is used (which is also nil by
+    default, meaning that all directories are included). When the value
+    of `excluded-dirs-regexp' is `t' or some other symbol, then the
+    `denote-excluded-directories-regexp' is ignored altogether. This is
+    useful in the scenario where the user option is set to exclude some
+    directories but the dynamic blocks wants to lift that restriction.
+
+  • The `:sort-by-component' parameter is optional. It sorts the files
+    by the given Denote file name component. The value it accepts is an
+    unquoted symbol among `title', `keywords', `signature',
+    `identifier'.  When using the command
+    `denote-org-dblock-insert-files', this parameter is automatically
+    inserted together with the (`:regexp' parameter) and the user is
+    prompted for a file name component.
+
+  • The `:reverse-sort' parameter is optional. It reverses the order in
+    which files appear in. This is meaningful even without the presence
+    of the parameter `:sort-by-component', though it also combines with
+    it.
+
+  • The `:id-only' parameter is optional. It accepts a `t' value, in
+    which case links are inserted without a description text but only
+    with the identifier of the given file. This has the same meaning as
+    with the `denote-link' command and related facilities (read the
+    Denote manual’s section about linking to other files in the
+    `denote-directory').
+
+  • The `:include-date' parameter controls whether to display the date
+    of the file name after the title. This is done when its value is
+    `t'. By default (a nil value), no date is shown.
+
+  • An optional `:block-name' parameter can be specified with a string
+    value to add a `#+name' to the results. This is useful for further
+    processing using Org facilities (a feature that is outside Denote’s
+    purview).
+
+  In some workflows, users may want to have a separate block to see what
+  other links they are missing since they last updated the dynamic
+  block. We cover that case as well ([The Org dynamic block to insert
+  missing links only]).
+
+
+[The Org dynamic block to insert missing links only] See section 3.2
+
+
+3.2 The Org dynamic block to insert missing links only
+──────────────────────────────────────────────────────
+
+  The `denote-missing-links' block is available with the command
+  `denote-org-dblock-insert-missing-links'. It is like the
+  aforementioned `denote-links' block, except it only lists links to
+  files that are not present in the current buffer ([Org dynamic blocks
+  to insert links]).  The parameters are otherwise the same and are all
+  optional except for `:regexp':
+
+  ┌────
+  │ #+BEGIN: denote-missing-links :regexp "YOUR REGEXP HERE" :excluded-dirs-regexp nil :sort-by-component nil :reverse-sort nil :id-only nil :include-date nil
+  │ 
+  │ #+END:
+  └────
+
+
+  The `denote-missing-links' block is also registered as an option for
+  the command `org-dynamic-block-insert-dblock'.
+
+  Remember to type `C-c C-x C-u' (`org-dblock-update') with point on the
+  `#+BEGIN' line to update the block.
+
+
+[Org dynamic blocks to insert links] See section 3.1
+
+
+3.3 The Org dynamic block to insert backlinks
+─────────────────────────────────────────────
+
+  Apart from links to files matching a regular expression, we can also
+  produce a list of backlinks to the current file. The dynamic block can
+  be inserted at point with the command
+  `denote-org-dblock-insert-backlinks' or by manually writing this in an
+  Org file:
+
+  ┌────
+  │ #+BEGIN: denote-backlinks :excluded-dirs-regexp nil :sort-by-component nil :reverse-sort nil :id-only nil :this-heading-only nil :include-date nil
+  │ 
+  │ #+END:
+  └────
+
+
+  The `denote-backlinks' block is also registered as an option for the
+  command `org-dynamic-block-insert-dblock'.
+
+  Remember to type `C-c C-x C-u' (`org-dblock-update') with point on the
+  `#+BEGIN' line to update the block.
+
+  The parameters recognised by this dynamic block are almost the same as
+  that for inserting links ([Org dynamic blocks to insert links]). They
+  are all optional in this case and there is no parameter expecting a
+  regular expression for matching files to link to.
+
+  Additionally, the `denote-backlinks' block also recognises the
+  `:this-heading-only' parameter. It determines if the backlinks are
+  about the file or the heading under which the dynamic block is
+  inserted ([Backlinks for Org headings]). When this parameter is
+  omitted or nil (the default), then the backlinks are about the whole
+  file, but if this parameter has a `t' value then the backlinks are
+  specifically for the heading ([Insert link to an Org file with a
+  further pointer to a heading]).
+
+
+[Org dynamic blocks to insert links] See section 3.1
+
+[Backlinks for Org headings] See section 5.1
+
+[Insert link to an Org file with a further pointer to a heading] See
+section 5
+
+
+3.4 Org dynamic block to insert file contents
+─────────────────────────────────────────────
+
+  Denote can optionally use Org’s dynamic blocks facility to produce a
+  section that lists entire file contents ([Use Org dynamic blocks]).
+  This works by instructing Org to match a regular expression of Denote
+  files, the same way we do with Denote links (read the Denote manual’s
+  section about inserting links that match a regular expression).
+
+  This is useful to, for example, compile a dynamically concatenated
+  list of scattered thoughts on a given topic, like `^2023.*_emacs' for
+  a long entry that incorporates all the notes written in 2023 with the
+  keyword `emacs'.
+
+  To produce such a block, call the command
+  `denote-org-dblock-insert-files' or manually write the following block
+  in an Org file and then type `C-c C-x C-u' (`org-dblock-update') on
+  the `#+BEGIN' line to run it (do it again to recalculate the block):
+
+  ┌────
+  │ #+BEGIN: denote-files :regexp "YOUR REGEXP HERE" :not-regexp nil :sort-by-component nil :reverse-sort nil :no-front-matter nil :file-separator nil :add-links nil
+  │ 
+  │ #+END:
+  └────
+
+
+  All parameters are optional except for `:regexp'.
+
+  The `denote-files' block is also registered as an option for the
+  command `org-dynamic-block-insert-dblock'.
+
+  Remember to type `C-c C-x C-u' (`org-dblock-update') with point on the
+  `#+BEGIN' line to update the block.
+
+  To fully control the output, include these additional optional
+  parameters, which are described further below:
+
+  • The `:regexp' parameter is mandatory. Its value is a string,
+    representing a regular expression to match Denote file names. Its
+    value may also be an `rx' expression instead of a string, as noted
+    in the previous section ([Org dynamic blocks to insert links or
+    backlinks]).  Note that you do not need to write an actual regular
+    expression to get meaningful results: even something like `_journal'
+    will work to include all files that have a `journal' keyword.
+
+  • The `:not-regexp' parameter is optional. It is a regular expression
+    that applies after `:regexp' to filter out the matching files.
+
+  • The `:excluded-dirs-regexp' is a string that contains a word or
+    regular expression that matches against directory files names
+    to-be-excluded from the results. This has the same meaning as
+    setting the `denote-excluded-directories-regexp' user option (which
+    is part of the main `denote' package). The user option has a global
+    effect, which is overridden locally in the dynamic block. When the
+    value of `:excluded-dirs-regexp' is nil (the default), the value of
+    `denote-excluded-directories-regexp' is used (which is also nil by
+    default, meaning that all directories are included). When the value
+    of `excluded-dirs-regexp' is `t' or some other symbol, then the
+    `denote-excluded-directories-regexp' is ignored altogether. This is
+    useful in the scenario where the user option is set to exclude some
+    directories but the dynamic blocks wants to lift that restriction.
+
+  • The `:sort-by-component' parameter is optional. It sorts the files
+    by the given Denote file name component. The value it accepts is an
+    unquoted symbol among `title', `keywords', `signature',
+    `identifier'.  When using the command
+    `denote-org-dblock-insert-files', this parameter is automatically
+    inserted together with the (`:regexp' parameter) and the user is
+    prompted for a file name component.
+
+  • The `:reverse-sort' parameter is optional. It reverses the order in
+    which files appear in. This is meaningful even without the presence
+    of the parameter `:sort-by-component', though it also combines with
+    it.
+
+  • The `:file-separator' parameter is optional. If it is omitted, then
+    Denote will use no separator between the files it inserts. If the
+    value is `t' the `denote-org-dblock-file-contents-separator' is
+    applied at the end of each file: it introduces some empty lines and
+    a horizontal rule between them to visually distinguish individual
+    files. If the `:file-separator' value is a string, it is used as the
+    file separator (e.g. use `"\n"' to insert just one empty new line).
+
+  • The `:no-front-matter' parameter is optional. When set to a `t'
+    value, Denote tries to remove front matter from the files it is
+    inserting in the dynamic block. The technique used to perform this
+    operation is by removing all lines from the top of the file until
+    the first empty line. This works with the default front matter that
+    Denote adds, but is not 100% reliable with all sorts of user-level
+    modifications and edits to the file. When the `:no-front-matter' is
+    set to a natural number, Denote will omit that many lines from the
+    top of the file.
+
+  • The `:add-links' parameter is optional. When it is set to a `t'
+    value, all files are inserted as a typographic list and are indented
+    accordingly. The first line in each list item is a link to the file
+    whose contents are inserted in the following lines. When the value
+    is `id-only', then links are inserted without a description text but
+    only with the identifier of the given file. This has the same
+    meaning as with the `denote-link' command and related facilities
+    (those are explained at length in the Denote manual). Remember that
+    Org can fold the items in a typographic list the same way it does
+    with headings. So even long files can be presented in this format
+    without much trouble.
+
+  • An optional `:block-name' parameter can be specified with a string
+    value to add a `#+name' to the results. This is useful for further
+    processing using Org facilities (a feature that is outside Denote’s
+    purview).
+
+
+[Use Org dynamic blocks] See section 3
+
+[Org dynamic blocks to insert links or backlinks] See section 3.1
+
+
+3.5 Org dynamic block to insert Org files as headings
+─────────────────────────────────────────────────────
+
+  [ IMPORTANT NOTE: This dynamic block only works with Org files,
+    because it has to assume the Org notation in order to insert each
+    file’s contents as its own heading. ]
+
+  As a variation of the previously covered block that inserts file
+  contents, we have the `denote-org-dblock-insert-files-as-headings'
+  command ([Org dynamic block to insert file contents]). It Turn the
+  `#+title' of each file into a top-level heading. Then it increments
+  all original headings in the file by one, so that they become
+  subheadings of what once was the `#+title'. Similarly, the
+  `#+filetags' of each file as tags for the top-level heading (what was
+  the `#+title').
+
+  Because of how it is meant to work, this dynamic block only works with
+  Org files.
+
+  In its simplest form, this dynamic block looks like this, with
+  `:regexp' as the only mandatory parameter:
+
+  ┌────
+  │ #+BEGIN: denote-files-as-headings :regexp "YOUR REGEXP HERE"
+  │ 
+  │ #+END:
+  └────
+
+
+  Though when you use the command
+  `denote-org-dblock-insert-files-as-headings' you get all the
+  parameters included:
+
+  ┌────
+  │ #+BEGIN: denote-files-as-headings :regexp "YOUR REGEXP HERE" :not-regexp nil :excluded-dirs-regexp nil :sort-by-component title :reverse-sort nil :add-links t
+  │ 
+  │ #+END:
+  └────
+
+
+  • The `:regexp' parameter is mandatory. Its value is a string,
+    representing a regular expression to match Denote file names. Its
+    value may also be an `rx' expression instead of a string, as noted
+    in the previous section ([Org dynamic blocks to insert links or
+    backlinks]).  Note that you do not need to write an actual regular
+    expression to get meaningful results: even something like `_journal'
+    will work to include all files that have a `journal' keyword.
+
+  • The `:not-regexp' parameter is optional. It is a regular expression
+    that applies after `:regexp' to filter out the matching files.
+
+  • The `:excluded-dirs-regexp' is a string that contains a word or
+    regular expression that matches against directory files names
+    to-be-excluded from the results. This has the same meaning as
+    setting the `denote-excluded-directories-regexp' user option (which
+    is part of the main `denote' package)). The user option has a global
+    effect, which is overridden locally in the dynamic block. When the
+    value of `:excluded-dirs-regexp' is nil (the default), the value of
+    `denote-excluded-directories-regexp' is used (which is also nil by
+    default, meaning that all directories are included). When the value
+    of `excluded-dirs-regexp' is `t' or some other symbol, then the
+    `denote-excluded-directories-regexp' is ignored altogether. This is
+    useful in the scenario where the user option is set to exclude some
+    directories but the dynamic blocks wants to lift that restriction.
+
+  • The `:sort-by-component' parameter is optional. It sorts the files
+    by the given Denote file name component. The value it accepts is an
+    unquoted symbol among `title', `keywords', `signature',
+    `identifier'.  When using the command
+    `denote-org-dblock-insert-files', this parameter is automatically
+    inserted together with the (`:regexp' parameter) and the user is
+    prompted for a file name component.
+
+  • The `:reverse-sort' parameter is optional. It reverses the order in
+    which files appear in. This is meaningful even without the presence
+    of the parameter `:sort-by-component', though it also combines with
+    it.
+
+  • The `:add-links' parameter is optional. When it is set to a `t'
+    value, all the top-level headings (those that were the `#+title' of
+    each file) are generated as links, pointing to the original file.
+    This has the same meaning as with the `denote-link' command and
+    related facilities (those are explained at length in the Denote
+    manual).
+
+  • An optional `:block-name' parameter can be specified with a string
+    value to add a `#+name' to the results. This is useful for further
+    processing using Org facilities (a feature that is outside Denote’s
+    purview).
+
+
+[Org dynamic block to insert file contents] See section 3.4
+
+[Org dynamic blocks to insert links or backlinks] See section 3.1
+
+
+4 Create a note from the current Org subtree
+════════════════════════════════════════════
+
+  In Org parlance, an entry with all its subheadings and other contents
+  is a “subtree”. Denote can operate on the subtree to extract it from
+  the current file and create a new file out of it. One such workflow is
+  to collect thoughts in a single document and produce longer standalone
+  notes out of them upon review.
+
+  The command `denote-org-extract-org-subtree' is used for this
+  purpose. It creates a new Denote note using the current Org subtree.
+  In doing so, it removes the subtree from its current file and moves
+  its contents into a new file. This command is part of the optional
+  `denote-org.el' extension, which is part of the `denote' package. It
+  is loaded automatically as soon as one of its commands is invoked.
+
+  The text of the subtree’s heading becomes the `#+title' of the new
+  note. Everything else is inserted as-is.
+
+  If the heading has any tags, they are used as the keywords of the new
+  note. If the Org file has any `#+filetags' they are taken as well
+  (Org’s `#+filetags' are inherited by the headings). If none of these
+  are true and the user option `denote-prompts' includes an entry for
+  keywords, then `denote-org-extract-org-subtree' prompts for
+  keywords. Else the new note has no keywords.
+
+  If the heading has a `PROPERTIES' drawer, it is retained for further
+  review.
+
+  If the heading’s `PROPERTIES' drawer includes a `DATE' or `CREATED'
+  property, or there exists a `CLOSED' statement with a timestamp value,
+  use that to derive the date (or date and time) of the new note (if
+  there is only a date, the time is taken as 00:00). If more than one of
+  these is present, the order of preference is `DATE', then `CREATED',
+  then `CLOSED'. If none of these is present, the current time is used.
+  If the `denote-prompts' includes an entry for a date, then the command
+  prompts for a date at this stage (also see
+  `denote-date-prompt-use-org-read-date').
+
+  For the rest, it consults the value of the user option
+  `denote-prompts' in the following scenaria:
+
+  • To optionally prompt for a subdirectory, otherwise it produces the
+    new note in the `denote-directory'.
+  • To optionally prompt for a file signature, otherwise to not use any.
+
+  The new note is an Org file regardless of the user option
+  `denote-file-type'.
+
+
+5 Insert link to an Org file with a further pointer to a heading
+════════════════════════════════════════════════════════════════
+
+  As part of the optional `denote-org.el' extension, the command
+  `denote-org-link-to-heading' prompts for a link to an Org file and
+  then asks for a heading therein, using minibuffer completion. Once the
+  user provides input at the two prompts, the command inserts a link at
+  point which has the following pattern:
+  `[[denote:IDENTIFIER::#ORG-HEADING-CUSTOM-ID]][Description::Heading
+  text]]'.
+
+  Because only Org files can have links to individual headings, the
+  command `denote-org-link-to-heading' prompts only for Org files
+  (i.e. files which include the `.org' extension). Remember that Denote
+  works with many file types (read the Denote manual’s section about the
+  file-naming scheme).
+
+  This feature is similar to the concept of the user option
+  `denote-org-store-link-to-heading' (which is part of the main `denote'
+  package). It is, however, interactive and differs in the
+  directionality of the action. With that user option, the command
+  `org-store-link' will generate a `CUSTOM_ID' for the current heading
+  (or capture the value of one as-is), giving the user the option to
+  then call `org-insert-link' wherever they see fit. By contrast, the
+  command `denote-org-link-to-heading' prompts for a file, then a
+  heading, and inserts the link at point.
+
+  Just as with files, it is possible to show backlinks for the given
+  heading ([Backlinks for Org headings]).
+
+
+[Backlinks for Org headings] See section 5.1
+
+5.1 Backlinks for Org headings
+──────────────────────────────
+
+  The optional `denote-org.el' can generate Denote links to individual
+  headings ([Insert link to an Org file with a further pointer to a
+  heading]).  It is then possible to produce a corresponding backlinks
+  buffer with the command `denote-org-backlinks-for-heading'. The
+  resulting buffer behaves the same way as the standard backlinks buffer
+  we provide (read the Denote manual’s section about the backlinks
+  buffer).  An Org dynamic block with backlinks to the current heading
+  is also an option ([Org dynamic blocks to insert links or backlinks]).
+
+
+[Insert link to an Org file with a further pointer to a heading] See
+section 5
+
+[Org dynamic blocks to insert links or backlinks] See section 3.1
+
+
+6 Convert `denote:' links to `file:' links in Org and vice versa
+════════════════════════════════════════════════════════════════
+
+  Sometimes the user needs to translate all `denote:' link types to
+  their `file:' equivalent. This may be because some other tool does not
+  recognise `denote:' links (or other custom links types—which are a
+  standard feature of Org, by the way). The user thus needs to (i)
+  either make a copy of their Denote note or edit the existing one, and
+  (ii) convert all links to the generic `file:' link type that
+  external/other programs understand.
+
+  The optional extension `denote-org.el' contains two commands that are
+  relevant for this use-case:
+
+  Convert `denote:' links to `file:' links
+        The command `denote-org-convert-links-to-file-type' goes through
+        the buffer to find all `denote:' links. It gets the identifier
+        of the link and resolves it to the actual file system path. It
+        then replaces the match so that the link is written with the
+        `file:' type and then the file system path. The optional search
+        terms and/or link description are preserved ([Insert link to an
+        Org file with a further pointer to a heading]).
+
+  Convert `file:' links to `denote:' links
+        The command `denote-org-convert-links-to-denote-type' behaves
+        like the one above. The difference is that it finds the file
+        system path and converts it into its identifier.
+
+
+[Insert link to an Org file with a further pointer to a heading] See
+section 5
+
+
+7 Installation
+══════════════
+
+
+
+
+7.1 GNU ELPA package
+────────────────────
+
+  The package is available as `denote-org'.  Simply do:
+
+  ┌────
+  │ M-x package-refresh-contents
+  │ M-x package-install
+  └────
+
+
+  And search for it.
+
+  GNU ELPA provides the latest stable release.  Those who prefer to
+  follow the development process in order to report bugs or suggest
+  changes, can use the version of the package from the GNU-devel ELPA
+  archive.  Read:
+  <https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/>.
+
+
+7.2 Manual installation
+───────────────────────
+
+  Assuming your Emacs files are found in `~/.emacs.d/', execute the
+  following commands in a shell prompt:
+
+  ┌────
+  │ cd ~/.emacs.d
+  │ 
+  │ # Create a directory for manually-installed packages
+  │ mkdir manual-packages
+  │ 
+  │ # Go to the new directory
+  │ cd manual-packages
+  │ 
+  │ # Clone this repo, naming it "denote-org"
+  │ git clone https://github.com/protesilaos/denote-org denote-org
+  └────
+
+  Finally, in your `init.el' (or equivalent) evaluate this:
+
+  ┌────
+  │ ;; Make Elisp files in that directory available to the user.
+  │ (add-to-list 'load-path "~/.emacs.d/manual-packages/denote-org")
+  └────
+
+  Everything is in place to set up the package.
+
+
+8 Sample configuration
+══════════════════════
+
+  ┌────
+  │ (use-package denote-org
+  │   :ensure t
+  │   :commands
+  │   ;; I list the commands here so that you can discover them more
+  │   ;; easily.  You might want to bind the most frequently used ones to
+  │   ;; the `org-mode-map'.
+  │   ( denote-org-link-to-heading
+  │     denote-org-backlinks-for-heading
+  │ 
+  │     denote-org-extract-org-subtree
+  │ 
+  │     denote-org-convert-links-to-file-type
+  │     denote-org-convert-links-to-denote-type
+  │ 
+  │     denote-org-dblock-insert-files
+  │     denote-org-dblock-insert-links
+  │     denote-org-dblock-insert-backlinks
+  │     denote-org-dblock-insert-missing-links
+  │     denote-org-dblock-insert-files-as-headings))
+  └────
+
+
+9 Acknowledgements
+══════════════════
+
+  Denote Org is meant to be a collective effort.  Every bit of help
+  matters.
+
+  Author/maintainer
+        Protesilaos Stavrou.
+
+
+10 GNU Free Documentation License
+═════════════════════════════════
+
+
+11 Indices
+══════════
+
+11.1 Function index
+───────────────────
+
+
+11.2 Variable index
+───────────────────
+
+
+11.3 Concept index
+──────────────────
blob - /dev/null
blob + 3bbde61a60b27bcd655963f17f77f0eb2a675032 (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/README.md
@@ -0,0 +1,17 @@
+# denote-org: Extras to integrate Org mode with Denote (like Org dynamic blocks)
+
+The `denote-org` package contains extra features that better integrate
+Denote with Org mode. These used to be available as part of the main
+`denote` package in a file called `denote-org-extras.el`, but now live
+in this standalone package to main things easier to maintain and
+understand.
+
+With `denote-org`, users have Org-specific extensions such as dynamic
+blocks, links to headings, and splitting an Org subtree into its own
+standalone file. This package's official manual covers the
+technicalities.
+
++ Package name (GNU ELPA): `denote-org`
++ Official manual: <https://protesilaos.com/emacs/denote-org>
++ Git repository: <https://github.com/protesilaos/denote-org>
++ Backronym: Denote... Ordinarily Restricts Gyrations.
blob - /dev/null
blob + c43f9b8cc549eb3ebefb559193fd172721c4fae0 (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/README.org
@@ -0,0 +1,1152 @@
+#+title: denote-org: Extensions to better integrate Org with Denote
+#+author: Protesilaos Stavrou
+#+email: info@protesilaos.com
+#+language: en
+#+options: ':t toc:nil author:t email:t num:t
+#+startup: content
+#+macro: stable-version 0.1.0
+#+macro: release-date 2025-04-15
+#+macro: development-version 0.2.0-dev
+#+export_file_name: denote-org.texi
+#+texinfo_filename: denote-org.info
+#+texinfo_dir_category: Emacs misc features
+#+texinfo_dir_title: Denote Org: (denote-org)
+#+texinfo_dir_desc: Extensions to better integrate Org with Denote
+#+texinfo_header: @set MAINTAINERSITE @uref{https://protesilaos.com,maintainer webpage}
+#+texinfo_header: @set MAINTAINER Protesilaos Stavrou
+#+texinfo_header: @set MAINTAINEREMAIL @email{info@protesilaos.com}
+#+texinfo_header: @set MAINTAINERCONTACT @uref{mailto:info@protesilaos.com,contact the maintainer}
+
+#+texinfo: @insertcopying
+
+This manual, written by Protesilaos Stavrou, describes the customization
+options for the Emacs package called ~denote~ (or =denote.el=), and
+provides every other piece of information pertinent to it.
+
+The documentation furnished herein corresponds to stable version
+{{{stable-version}}}, released on {{{release-date}}}.  Any reference to
+a newer feature which does not yet form part of the latest tagged
+commit, is explicitly marked as such.
+
+Current development target is {{{development-version}}}.
+
++ Package name (GNU ELPA): ~denote-org~
++ Official manual: <https://protesilaos.com/emacs/denote-org>
++ Git repository: <https://github.com/protesilaos/denote-org>
++ Backronym: Denote... Ordinarily Restricts Gyrations.
+
+If you are viewing the README.org version of this file, please note that
+the GNU ELPA machinery automatically generates an Info manual out of it.
+
+#+toc: headlines 8 insert TOC here, with eight headline levels
+
+* COPYING
+:PROPERTIES:
+:COPYING: t
+:CUSTOM_ID: h:copying
+:END:
+
+Copyright (C) 2022-2025  Free Software Foundation, Inc.
+
+#+begin_quote
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and
+with the Back-Cover Texts as in (a) below.  A copy of the license is
+included in the section entitled “GNU Free Documentation License.”
+
+(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
+modify this GNU manual.”
+#+end_quote
+
+* Overview
+:PROPERTIES:
+:CUSTOM_ID: h:6157c29a-31e6-4ba7-b114-57f94a21d460
+:END:
+
+The ~denote-org~ package contains extra features that better integrate
+Denote with Org mode. These used to be available as part of the main
+~denote~ package in a file called =denote-org-extras.el=, but now live
+in this standalone package to main things easier to maintain and
+understand.
+
+With ~denote-org~, users have Org-specific extensions such as dynamic
+blocks, links to headings, and splitting an Org subtree into its own
+standalone file. The following sections cover the technicalities.
+
+* Use Org dynamic blocks
+:PROPERTIES:
+:CUSTOM_ID: h:8b542c50-dcc9-4bca-8037-a36599b22779
+:END:
+
+Denote can optionally integrate with Org mode's "dynamic blocks"
+facility. This means that it can use special blocks that are evaluated
+with =C-c C-x C-u= (~org-dblock-update~) to generate their contents.
+The following subsections describe the types of Org dynamic blocks
+provided by Denote.
+
+- [[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org dynamic blocks to insert links or backlinks]]
+- [[#h:f15fa143-5036-416f-9bff-1bcabbb03456][Org dynamic block to insert file contents]]
+
+A dynamic block gets its contents by evaluating a function that
+corresponds to the type of block. The block type and its parameters
+are stated in the opening =#+BEGIN= line. Typing =C-c C-x C-u=
+(~org-dblock-update~) with point on that line runs (or re-runs) the
+associated function with the given parameters and populates the
+block's contents accordingly.
+
+Dynamic blocks are particularly useful for metanote entries that
+reflect on the status of earlier notes (read the Denote manual's
+section about writing metanotes).
+
+The Org manual describes the technicalities of Dynamic Blocks.
+Evaluate:
+
+#+begin_src emacs-lisp
+(info "(org) Dynamic Blocks")
+#+end_src
+
+** Org dynamic blocks to insert links
+:PROPERTIES:
+:CUSTOM_ID: h:50160fae-6515-4d7d-9737-995ad925e64b
+:END:
+
+#+findex: denote-org-dblock-insert-links
+The =denote-links= block can be inserted at point with the command
+~denote-org-dblock-insert-links~ or by manually including the
+following in an Org file:
+
+: #+BEGIN: denote-links :regexp "YOUR REGEXP HERE" :not-regexp :excluded-dirs-regexp nil :sort-by-component nil :reverse-sort nil :id-only nil :include-date nil
+:
+: #+END:
+
+All the parameters except for =:regexp= are optional.
+
+The =denote-links= block is also registered as an option for the
+command ~org-dynamic-block-insert-dblock~.
+
+Type =C-c C-x C-u= (~org-dblock-update~) with point on the =#+BEGIN=
+line to update the block.
+
+- The =:regexp= parameter is mandatory. Its value is a string and its
+  behaviour is the same as that of the standard ~denote-add-links~
+  command (part of the main ~denote~ package). Concretely, it produces
+  a typographic list of links to files matching the giving regular
+  expression. The value of the =:regexp= parameter may also be of the
+  form read by the ~rx~ macro (Lisp notation instead of a string), as
+  explained in the Emacs Lisp Reference Manual (evaluate this code to
+  read the documentation: =(info "(elisp) Rx Notation")=). Note that
+  you do not need to write an actual regular expression to get
+  meaningful results: even something like =_journal= will work to
+  include all files that have a =journal= keyword.
+
+- The =:not-regexp= parameter is optional. It is a regular expression
+  that applies after =:regexp= to filter out the matching files.
+
+- The =:excluded-dirs-regexp= is a string that contains a word or
+  regular expression that matches against directory files names
+  to-be-excluded from the results. This has the same meaning as
+  setting the ~denote-excluded-directories-regexp~ user option (which
+  is part of the main ~denote~ package). The user option has a global
+  effect, which is overridden locally in the dynamic block. When the
+  value of =:excluded-dirs-regexp= is nil (the default), the value of
+  ~denote-excluded-directories-regexp~ is used (which is also nil by
+  default, meaning that all directories are included). When the value
+  of =excluded-dirs-regexp= is ~t~ or some other symbol, then the
+  ~denote-excluded-directories-regexp~ is ignored altogether. This is
+  useful in the scenario where the user option is set to exclude some
+  directories but the dynamic blocks wants to lift that restriction.
+
+- The =:sort-by-component= parameter is optional. It sorts the files
+  by the given Denote file name component. The value it accepts is an
+  unquoted symbol among =title=, =keywords=, =signature=, =identifier=.
+  When using the command ~denote-org-dblock-insert-files~, this
+  parameter is automatically inserted together with the (=:regexp=
+  parameter) and the user is prompted for a file name component.
+
+- The =:reverse-sort= parameter is optional. It reverses the order in
+  which files appear in. This is meaningful even without the presence
+  of the parameter =:sort-by-component=, though it also combines with
+  it.
+
+- The =:id-only= parameter is optional. It accepts a ~t~ value, in
+  which case links are inserted without a description text but only
+  with the identifier of the given file. This has the same meaning as
+  with the ~denote-link~ command and related facilities (read the
+  Denote manual's section about linking to other files in the
+  ~denote-directory~).
+
+- The =:include-date= parameter controls whether to display the date
+  of the file name after the title. This is done when its value is
+  ~t~. By default (a nil value), no date is shown.
+
+- An optional =:block-name= parameter can be specified with a string
+  value to add a =#+name= to the results. This is useful for further
+  processing using Org facilities (a feature that is outside Denote's
+  purview).
+
+In some workflows, users may want to have a separate block to see what
+other links they are missing since they last updated the dynamic
+block. We cover that case as well ([[#h:1a81e255-0510-4ee0-bc3a-374de048ef46][The Org dynamic block to insert missing links only]]).
+
+** The Org dynamic block to insert missing links only
+:PROPERTIES:
+:CUSTOM_ID: h:1a81e255-0510-4ee0-bc3a-374de048ef46
+:END:
+
+#+findex: denote-org-dblock-insert-missing-links
+The =denote-missing-links= block is available with the command
+~denote-org-dblock-insert-missing-links~. It is like the
+aforementioned =denote-links= block, except it only lists links to
+files that are not present in the current buffer ([[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org dynamic blocks to insert links]]).
+The parameters are otherwise the same and are all optional except for
+=:regexp=:
+
+: #+BEGIN: denote-missing-links :regexp "YOUR REGEXP HERE" :excluded-dirs-regexp nil :sort-by-component nil :reverse-sort nil :id-only nil :include-date nil
+:
+: #+END:
+
+The =denote-missing-links= block is also registered as an option for the
+command ~org-dynamic-block-insert-dblock~.
+
+Remember to type =C-c C-x C-u= (~org-dblock-update~) with point on the
+=#+BEGIN= line to update the block.
+
+** The Org dynamic block to insert backlinks
+:PROPERTIES:
+:CUSTOM_ID: h:f9a97859-1deb-47dd-bdae-52f8b424ff46
+:END:
+
+#+findex: denote-org-dblock-insert-backlinks
+Apart from links to files matching a regular expression, we can also
+produce a list of backlinks to the current file. The dynamic block can
+be inserted at point with the command ~denote-org-dblock-insert-backlinks~
+or by manually writing this in an Org file:
+
+: #+BEGIN: denote-backlinks :excluded-dirs-regexp nil :sort-by-component nil :reverse-sort nil :id-only nil :this-heading-only nil :include-date nil
+:
+: #+END:
+
+The =denote-backlinks= block is also registered as an option for the
+command ~org-dynamic-block-insert-dblock~.
+
+Remember to type =C-c C-x C-u= (~org-dblock-update~) with point on the
+=#+BEGIN= line to update the block.
+
+The parameters recognised by this dynamic block are almost the same as
+that for inserting links ([[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org dynamic blocks to insert links]]). They
+are all optional in this case and there is no parameter expecting a
+regular expression for matching files to link to.
+
+Additionally, the ~denote-backlinks~ block also recognises the
+=:this-heading-only= parameter. It determines if the backlinks are
+about the file or the heading under which the dynamic block is inserted
+([[#h:604bf92a-908a-485c-98b8-37ccae559afd][Backlinks for Org headings]]). When this parameter is omitted or nil
+(the default), then the backlinks are about the whole file, but if
+this parameter has a ~t~ value then the backlinks are specifically for
+the heading ([[#h:fc1ad245-ec08-41be-8d1e-7153d99daf02][Insert link to an Org file with a further pointer to a heading]]).
+
+** Org dynamic block to insert file contents
+:PROPERTIES:
+:CUSTOM_ID: h:f15fa143-5036-416f-9bff-1bcabbb03456
+:END:
+
+Denote can optionally use Org's dynamic blocks facility to produce a
+section that lists entire file contents ([[#h:8b542c50-dcc9-4bca-8037-a36599b22779][Use Org dynamic blocks]]).
+This works by instructing Org to match a regular expression of Denote
+files, the same way we do with Denote links (read the Denote manual's
+section about inserting links that match a regular expression).
+
+This is useful to, for example, compile a dynamically concatenated
+list of scattered thoughts on a given topic, like =^2023.*_emacs= for
+a long entry that incorporates all the notes written in 2023 with the
+keyword =emacs=.
+
+#+findex: denote-org-dblock-insert-files
+To produce such a block, call the command ~denote-org-dblock-insert-files~
+or manually write the following block in an Org file and then type
+ =C-c C-x C-u= (~org-dblock-update~) on the =#+BEGIN= line to run it
+(do it again to recalculate the block):
+
+: #+BEGIN: denote-files :regexp "YOUR REGEXP HERE" :not-regexp nil :sort-by-component nil :reverse-sort nil :no-front-matter nil :file-separator nil :add-links nil
+:
+: #+END:
+
+All parameters are optional except for =:regexp=.
+
+The =denote-files= block is also registered as an option for the
+command ~org-dynamic-block-insert-dblock~.
+
+Remember to type =C-c C-x C-u= (~org-dblock-update~) with point on the
+=#+BEGIN= line to update the block.
+
+To fully control the output, include these additional optional
+parameters, which are described further below:
+
+- The =:regexp= parameter is mandatory. Its value is a string,
+  representing a regular expression to match Denote file names. Its
+  value may also be an ~rx~ expression instead of a string, as noted
+  in the previous section ([[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org dynamic blocks to insert links or backlinks]]).
+  Note that you do not need to write an actual regular expression to
+  get meaningful results: even something like =_journal= will work to
+  include all files that have a =journal= keyword.
+
+- The =:not-regexp= parameter is optional. It is a regular expression
+  that applies after =:regexp= to filter out the matching files.
+
+- The =:excluded-dirs-regexp= is a string that contains a word or
+  regular expression that matches against directory files names
+  to-be-excluded from the results. This has the same meaning as
+  setting the ~denote-excluded-directories-regexp~ user option (which
+  is part of the main ~denote~ package). The user option has a global
+  effect, which is overridden locally in the dynamic block. When the
+  value of =:excluded-dirs-regexp= is nil (the default), the value of
+  ~denote-excluded-directories-regexp~ is used (which is also nil by
+  default, meaning that all directories are included). When the value
+  of =excluded-dirs-regexp= is ~t~ or some other symbol, then the
+  ~denote-excluded-directories-regexp~ is ignored altogether. This is
+  useful in the scenario where the user option is set to exclude some
+  directories but the dynamic blocks wants to lift that restriction.
+
+- The =:sort-by-component= parameter is optional. It sorts the files
+  by the given Denote file name component. The value it accepts is an
+  unquoted symbol among =title=, =keywords=, =signature=, =identifier=.
+  When using the command ~denote-org-dblock-insert-files~, this
+  parameter is automatically inserted together with the (=:regexp=
+  parameter) and the user is prompted for a file name component.
+
+- The =:reverse-sort= parameter is optional. It reverses the order in
+  which files appear in. This is meaningful even without the presence
+  of the parameter =:sort-by-component=, though it also combines with
+  it.
+
+#+vindex: denote-org-dblock-file-contents-separator
+- The =:file-separator= parameter is optional. If it is omitted, then
+  Denote will use no separator between the files it inserts. If the
+  value is ~t~ the ~denote-org-dblock-file-contents-separator~ is
+  applied at the end of each file: it introduces some empty lines and
+  a horizontal rule between them to visually distinguish individual
+  files. If the =:file-separator= value is a string, it is used as the
+  file separator (e.g. use ="\n"= to insert just one empty new line).
+
+- The =:no-front-matter= parameter is optional. When set to a ~t~
+  value, Denote tries to remove front matter from the files it is
+  inserting in the dynamic block. The technique used to perform this
+  operation is by removing all lines from the top of the file until
+  the first empty line. This works with the default front matter that
+  Denote adds, but is not 100% reliable with all sorts of user-level
+  modifications and edits to the file. When the =:no-front-matter= is
+  set to a natural number, Denote will omit that many lines from the
+  top of the file.
+
+- The =:add-links= parameter is optional. When it is set to a ~t~
+  value, all files are inserted as a typographic list and are indented
+  accordingly. The first line in each list item is a link to the file
+  whose contents are inserted in the following lines. When the value
+  is =id-only=, then links are inserted without a description text but
+  only with the identifier of the given file. This has the same
+  meaning as with the ~denote-link~ command and related facilities
+  (those are explained at length in the Denote manual). Remember that
+  Org can fold the items in a typographic list the same way it does
+  with headings. So even long files can be presented in this format
+  without much trouble.
+
+- An optional =:block-name= parameter can be specified with a string
+  value to add a =#+name= to the results. This is useful for further
+  processing using Org facilities (a feature that is outside Denote's
+  purview).
+
+** Org dynamic block to insert Org files as headings
+:PROPERTIES:
+:CUSTOM_ID: h:d6254a12-b762-4096-a5de-66a0d423e204
+:END:
+
+[ IMPORTANT NOTE: This dynamic block only works with Org files,
+  because it has to assume the Org notation in order to insert each
+  file's contents as its own heading. ]
+
+#+findex: denote-org-dblock-insert-files-as-headings
+As a variation of the previously covered block that inserts file
+contents, we have the ~denote-org-dblock-insert-files-as-headings~
+command ([[#h:f15fa143-5036-416f-9bff-1bcabbb03456][Org dynamic block to insert file contents]]). It Turn the
+=#+title= of each file into a top-level heading. Then it increments
+all original headings in the file by one, so that they become
+subheadings of what once was the =#+title=. Similarly, the
+=#+filetags= of each file as tags for the top-level heading
+(what was the =#+title=).
+
+Because of how it is meant to work, this dynamic block only works with
+Org files.
+
+In its simplest form, this dynamic block looks like this, with
+=:regexp= as the only mandatory parameter:
+
+: #+BEGIN: denote-files-as-headings :regexp "YOUR REGEXP HERE"
+:
+: #+END:
+
+Though when you use the command ~denote-org-dblock-insert-files-as-headings~
+you get all the parameters included:
+
+: #+BEGIN: denote-files-as-headings :regexp "YOUR REGEXP HERE" :not-regexp nil :excluded-dirs-regexp nil :sort-by-component title :reverse-sort nil :add-links t
+:
+: #+END:
+
+- The =:regexp= parameter is mandatory. Its value is a string,
+  representing a regular expression to match Denote file names. Its
+  value may also be an ~rx~ expression instead of a string, as noted
+  in the previous section ([[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org dynamic blocks to insert links or backlinks]]).
+  Note that you do not need to write an actual regular expression to
+  get meaningful results: even something like =_journal= will work to
+  include all files that have a =journal= keyword.
+
+- The =:not-regexp= parameter is optional. It is a regular expression
+  that applies after =:regexp= to filter out the matching files.
+
+- The =:excluded-dirs-regexp= is a string that contains a word or
+  regular expression that matches against directory files names
+  to-be-excluded from the results. This has the same meaning as
+  setting the ~denote-excluded-directories-regexp~ user option (which
+  is part of the main ~denote~ package)). The user option has a global
+  effect, which is overridden locally in the dynamic block. When the
+  value of =:excluded-dirs-regexp= is nil (the default), the value of
+  ~denote-excluded-directories-regexp~ is used (which is also nil by
+  default, meaning that all directories are included). When the value
+  of =excluded-dirs-regexp= is ~t~ or some other symbol, then the
+  ~denote-excluded-directories-regexp~ is ignored altogether. This is
+  useful in the scenario where the user option is set to exclude some
+  directories but the dynamic blocks wants to lift that restriction.
+
+- The =:sort-by-component= parameter is optional. It sorts the files
+  by the given Denote file name component. The value it accepts is an
+  unquoted symbol among =title=, =keywords=, =signature=, =identifier=.
+  When using the command ~denote-org-dblock-insert-files~, this
+  parameter is automatically inserted together with the (=:regexp=
+  parameter) and the user is prompted for a file name component.
+
+- The =:reverse-sort= parameter is optional. It reverses the order in
+  which files appear in. This is meaningful even without the presence
+  of the parameter =:sort-by-component=, though it also combines with
+  it.
+
+- The =:add-links= parameter is optional. When it is set to a ~t~
+  value, all the top-level headings (those that were the =#+title= of
+  each file) are generated as links, pointing to the original file.
+  This has the same meaning as with the ~denote-link~ command and
+  related facilities (those are explained at length in the Denote manual).
+
+- An optional =:block-name= parameter can be specified with a string
+  value to add a =#+name= to the results. This is useful for further
+  processing using Org facilities (a feature that is outside Denote's
+  purview).
+
+* Create a note from the current Org subtree
+:PROPERTIES:
+:CUSTOM_ID: h:d0c7cb79-21e5-4176-a6af-f4f68578c8dd
+:END:
+
+In Org parlance, an entry with all its subheadings and other contents
+is a "subtree". Denote can operate on the subtree to extract it from
+the current file and create a new file out of it. One such workflow is
+to collect thoughts in a single document and produce longer standalone
+notes out of them upon review.
+
+#+findex: denote-org-extract-org-subtree
+The command ~denote-org-extract-org-subtree~ is used for this
+purpose. It creates a new Denote note using the current Org subtree.
+In doing so, it removes the subtree from its current file and moves
+its contents into a new file. This command is part of the optional
+=denote-org.el= extension, which is part of the ~denote~
+package. It is loaded automatically as soon as one of its commands is
+invoked.
+
+The text of the subtree's heading becomes the =#+title= of the new
+note. Everything else is inserted as-is.
+
+If the heading has any tags, they are used as the keywords of the new
+note. If the Org file has any =#+filetags= they are taken as well
+(Org's =#+filetags= are inherited by the headings). If none of these
+are true and the user option ~denote-prompts~ includes an entry for
+keywords, then ~denote-org-extract-org-subtree~ prompts for
+keywords. Else the new note has no keywords.
+
+If the heading has a =PROPERTIES= drawer, it is retained for further
+review.
+
+If the heading's =PROPERTIES= drawer includes a =DATE= or =CREATED=
+property, or there exists a =CLOSED= statement with a timestamp value,
+use that to derive the date (or date and time) of the new note (if
+there is only a date, the time is taken as 00:00). If more than one of
+these is present, the order of preference is =DATE=, then =CREATED=,
+then =CLOSED=. If none of these is present, the current time is used.
+If the ~denote-prompts~ includes an entry for a date, then the command
+prompts for a date at this stage (also see ~denote-date-prompt-use-org-read-date~).
+
+For the rest, it consults the value of the user option
+~denote-prompts~ in the following scenaria:
+
+- To optionally prompt for a subdirectory, otherwise it produces the
+  new note in the ~denote-directory~.
+- To optionally prompt for a file signature, otherwise to not use any.
+
+The new note is an Org file regardless of the user option
+~denote-file-type~.
+
+* Insert link to an Org file with a further pointer to a heading
+:PROPERTIES:
+:CUSTOM_ID: h:fc1ad245-ec08-41be-8d1e-7153d99daf02
+:END:
+
+#+findex: denote-org-link-to-heading
+As part of the optional =denote-org.el= extension, the command
+~denote-org-link-to-heading~ prompts for a link to an Org file
+and then asks for a heading therein, using minibuffer completion. Once
+the user provides input at the two prompts, the command inserts a link
+at point which has the following pattern: =[[denote:IDENTIFIER::#ORG-HEADING-CUSTOM-ID]][Description::Heading text]]=.
+
+Because only Org files can have links to individual headings, the
+command ~denote-org-link-to-heading~ prompts only for Org files
+(i.e. files which include the =.org= extension). Remember that Denote
+works with many file types (read the Denote manual's section about the
+file-naming scheme).
+
+This feature is similar to the concept of the user option
+~denote-org-store-link-to-heading~ (which is part of the main ~denote~
+package). It is, however, interactive and differs in the
+directionality of the action. With that user option, the command
+~org-store-link~ will generate a =CUSTOM_ID= for the current heading
+(or capture the value of one as-is), giving the user the option to
+then call ~org-insert-link~ wherever they see fit. By contrast, the
+command ~denote-org-link-to-heading~ prompts for a file, then a
+heading, and inserts the link at point.
+
+Just as with files, it is possible to show backlinks for the given
+heading ([[#h:604bf92a-908a-485c-98b8-37ccae559afd][Backlinks for Org headings]]).
+
+** Backlinks for Org headings
+:PROPERTIES:
+:CUSTOM_ID: h:604bf92a-908a-485c-98b8-37ccae559afd
+:END:
+
+The optional =denote-org.el= can generate Denote links to
+individual headings ([[#h:fc1ad245-ec08-41be-8d1e-7153d99daf02][Insert link to an Org file with a further pointer to a heading]]).
+It is then possible to produce a corresponding backlinks buffer with
+the command ~denote-org-backlinks-for-heading~. The resulting
+buffer behaves the same way as the standard backlinks buffer we
+provide (read the Denote manual's section about the backlinks buffer).
+An Org dynamic block with backlinks to the current heading is also an
+option ([[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org dynamic blocks to insert links or backlinks]]).
+
+* Convert =denote:= links to =file:= links in Org and vice versa
+:PROPERTIES:
+:CUSTOM_ID: h:ed220cac-7dcb-4bb7-9243-1bb85e452e5f
+:END:
+
+Sometimes the user needs to translate all =denote:= link types to
+their =file:= equivalent. This may be because some other tool does not
+recognise =denote:= links (or other custom links types---which are a
+standard feature of Org, by the way). The user thus needs to (i)
+either make a copy of their Denote note or edit the existing one, and
+(ii) convert all links to the generic =file:= link type that
+external/other programs understand.
+
+The optional extension =denote-org.el= contains two commands
+that are relevant for this use-case:
+
+#+findex: denote-org-convert-links-to-file-type
++ Convert =denote:= links to =file:= links :: The command
+  ~denote-org-convert-links-to-file-type~ goes through the
+  buffer to find all =denote:= links. It gets the identifier of the
+  link and resolves it to the actual file system path. It then
+  replaces the match so that the link is written with the =file:= type
+  and then the file system path. The optional search terms and/or link
+  description are preserved ([[#h:fc1ad245-ec08-41be-8d1e-7153d99daf02][Insert link to an Org file with a further pointer to a heading]]).
+
+#+findex: denote-org-convert-links-to-denote-type
++ Convert =file:= links to =denote:= links :: The command
+  ~denote-org-convert-links-to-denote-type~ behaves like the
+  one above. The difference is that it finds the file system path and
+  converts it into its identifier.
+
+* Installation
+:PROPERTIES:
+:CUSTOM_ID: h:installation
+:END:
+#+cindex: Installation instructions
+
+** GNU ELPA package
+:PROPERTIES:
+:CUSTOM_ID: h:gnu-elpa-package
+:END:
+
+The package is available as =denote-org=.  Simply do:
+
+: M-x package-refresh-contents
+: M-x package-install
+
+And search for it.
+
+GNU ELPA provides the latest stable release.  Those who prefer to follow
+the development process in order to report bugs or suggest changes, can
+use the version of the package from the GNU-devel ELPA archive.  Read:
+https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/.
+
+** Manual installation
+:PROPERTIES:
+:CUSTOM_ID: h:manual-installation
+:END:
+
+Assuming your Emacs files are found in =~/.emacs.d/=, execute the
+following commands in a shell prompt:
+
+#+begin_src sh
+cd ~/.emacs.d
+
+# Create a directory for manually-installed packages
+mkdir manual-packages
+
+# Go to the new directory
+cd manual-packages
+
+# Clone this repo, naming it "denote-org"
+git clone https://github.com/protesilaos/denote-org denote-org
+#+end_src
+
+Finally, in your =init.el= (or equivalent) evaluate this:
+
+#+begin_src emacs-lisp
+;; Make Elisp files in that directory available to the user.
+(add-to-list 'load-path "~/.emacs.d/manual-packages/denote-org")
+#+end_src
+
+Everything is in place to set up the package.
+
+* Sample configuration
+:PROPERTIES:
+:CUSTOM_ID: h:sample-configuration
+:END:
+#+cindex: Package configuration
+
+#+begin_src emacs-lisp
+(use-package denote-org
+  :ensure t
+  :commands
+  ;; I list the commands here so that you can discover them more
+  ;; easily.  You might want to bind the most frequently used ones to
+  ;; the `org-mode-map'.
+  ( denote-org-link-to-heading
+    denote-org-backlinks-for-heading
+
+    denote-org-extract-org-subtree
+
+    denote-org-convert-links-to-file-type
+    denote-org-convert-links-to-denote-type
+
+    denote-org-dblock-insert-files
+    denote-org-dblock-insert-links
+    denote-org-dblock-insert-backlinks
+    denote-org-dblock-insert-missing-links
+    denote-org-dblock-insert-files-as-headings))
+#+end_src
+
+* Acknowledgements
+:PROPERTIES:
+:CUSTOM_ID: h:acknowledgements
+:END:
+#+cindex: Contributors
+
+Denote Org is meant to be a collective effort.  Every bit of help matters.
+
++ Author/maintainer :: Protesilaos Stavrou.
+
+* GNU Free Documentation License
+:PROPERTIES:
+:APPENDIX: t
+:CUSTOM_ID: h:gnu-free-documentation-license
+:END:
+
+#+texinfo: @include doclicense.texi
+
+#+begin_export html
+<pre>
+
+                GNU Free Documentation License
+                 Version 1.3, 3 November 2008
+
+
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+     <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns.  See
+https://www.gnu.org/licenses/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.3
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+</pre>
+#+end_export
+
+#+html: <!--
+
+* Indices
+:PROPERTIES:
+:CUSTOM_ID: h:indices
+:END:
+
+** Function index
+:PROPERTIES:
+:INDEX: fn
+:CUSTOM_ID: h:function-index
+:END:
+
+** Variable index
+:PROPERTIES:
+:INDEX: vr
+:CUSTOM_ID: h:variable-index
+:END:
+
+** Concept index
+:PROPERTIES:
+:INDEX: cp
+:CUSTOM_ID: h:concept-index
+:END:
+
+#+html: -->
blob - /dev/null
blob + 6fa6116de64b21b9817bd575e6957eece875fd5b (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/denote-org-autoloads.el
@@ -0,0 +1,164 @@
+;;; denote-org-autoloads.el --- automatically extracted autoloads (do not edit)   -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+
+;;; Generated autoloads from denote-org.el
+
+(autoload 'denote-org-link-to-heading "denote-org" "\
+Link to file and then specify a heading to extend the link to.
+
+The resulting link has the following pattern:
+
+[[denote:IDENTIFIER::#ORG-HEADING-CUSTOM-ID]][Description::Heading text]].
+
+Because only Org files can have links to individual headings,
+limit the list of possible files to those which include the .org
+file extension (remember that Denote works with many file types,
+per the user option `denote-file-type').
+
+The user option `denote-org-store-link-to-heading'
+determined whether the `org-store-link' function can save a link
+to the current heading.  Such links look the same as those of
+this command, though the functionality defined herein is
+independent of it.
+
+To only link to a file, use the `denote-link' command.
+
+Also see `denote-org-backlinks-for-heading'." '(org-mode))
+(function-put 'denote-org-link-to-heading 'interactive-only 't)
+(autoload 'denote-org-backlinks-for-heading "denote-org" "\
+Produce backlinks for the current heading.
+This otherwise has the same behaviour as `denote-backlinks'---refer to
+that for the details.
+
+Also see `denote-org-link-to-heading'." t)
+(autoload 'denote-org-extract-org-subtree "denote-org" "\
+Create new Denote note using the current Org subtree as input.
+Remove the subtree from its current file and move its contents into a
+new Denote file (a subtree is a heading with all of its contents,
+including subheadings).
+
+Take the text of the subtree's top level heading and use it as the title
+of the new note.
+
+If the heading has any tags, use them as the keywords of the new note.
+If the Org file has any #+filetags use them as well (Org's filetags are
+inherited by the headings).  If none of these are true and the user
+option `denote-prompts' includes an entry for keywords, then prompt for
+keywords.  Else do not include any keywords.
+
+If the heading has a PROPERTIES drawer, retain it for further review.
+
+If the heading's PROPERTIES drawer includes a DATE or CREATED property,
+or there exists a CLOSED statement with a timestamp value, use that to
+derive the date (or date and time) of the new note (if there is only a
+date, the time is taken as 00:00).  If more than one of these is
+present, the order of preference is DATE, then CREATED, then CLOSED.  If
+none of these is present, use the current time.  If the `denote-prompts'
+includes an entry for a date, then prompt for a date at this stage (also
+see `denote-date-prompt-use-org-read-date').
+
+For the rest, consult the value of the user option `denote-prompts' in
+the following scenaria:
+
+- Optionally prompt for a subdirectory, otherwise produce the new note
+  in the variable `denote-directory'.
+
+- Optionally prompt for a file signature, otherwise do not use one.
+
+Make the new note an Org file regardless of the value of the user option
+`denote-file-type'." '(org-mode))
+(autoload 'denote-org-convert-links-to-file-type "denote-org" "\
+Convert denote: links to file: links in the current Org buffer.
+Ignore all other link types.  Also ignore links that do not
+resolve to a file in the variable `denote-directory'." '(org-mode))
+(autoload 'denote-org-convert-links-to-denote-type "denote-org" "\
+Convert file: links to denote: links in the current Org buffer.
+Ignore all other link types.  Also ignore file: links that do not
+point to a file with a Denote file name." '(org-mode))
+(autoload 'denote-org-dblock-insert-links "denote-org" "\
+Create Org dynamic block to insert Denote links matching REGEXP.
+
+(fn REGEXP)" '(org-mode))
+(eval-after-load 'org '(progn (org-dynamic-block-define "denote-links" 'denote-org-dblock-insert-links)))
+(autoload 'org-dblock-write:denote-links "denote-org" "\
+Function to update `denote-links' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block.
+
+(fn PARAMS)")
+(autoload 'denote-org-dblock-insert-missing-links "denote-org" "\
+Create Org dynamic block to insert Denote links matching REGEXP.
+
+(fn REGEXP)" '(org-mode))
+(eval-after-load 'org '(progn (org-dynamic-block-define "denote-missing-links" 'denote-org-dblock-insert-missing-links)))
+(autoload 'org-dblock-write:denote-missing-links "denote-org" "\
+Function to update `denote-links' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block.
+
+(fn PARAMS)")
+(autoload 'denote-org-dblock-insert-backlinks "denote-org" "\
+Create Org dynamic block to insert Denote backlinks to current file." '(org-mode))
+(eval-after-load 'org '(progn (org-dynamic-block-define "denote-backlinks" 'denote-org-dblock-insert-backlinks)))
+(autoload 'org-dblock-write:denote-backlinks "denote-org" "\
+Function to update `denote-backlinks' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block.
+
+(fn PARAMS)")
+(autoload 'denote-org-dblock-insert-files "denote-org" "\
+Create Org dynamic block to insert Denote files matching REGEXP.
+Sort the files according to SORT-BY-COMPONENT, which is a symbol
+among `denote-sort-components'.
+
+(fn REGEXP SORT-BY-COMPONENT)" '(org-mode))
+(eval-after-load 'org '(progn (org-dynamic-block-define "denote-files" 'denote-org-dblock-insert-files)))
+(autoload 'org-dblock-write:denote-files "denote-org" "\
+Function to update `denote-files' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block.
+
+(fn PARAMS)")
+(autoload 'denote-org-dblock-insert-files-as-headings "denote-org" "\
+Create Org dynamic block to insert Denote Org files matching REGEXP.
+
+Turn the #+title of each file into a top-level heading.  Then increment
+all original headings in the file by one, so that they become
+subheadings of what once was the #+title.
+
+Use the #+filetags of each file as tags for the top-level heading (what
+was the #+title).
+
+Sort the files according to SORT-BY-COMPONENT, which is a symbol
+among `denote-sort-components'.
+
+IMPORTANT NOTE: This dynamic block only works with Org files, because it
+has to assume the Org notation in order to insert each file's contents
+as its own heading.
+
+(fn REGEXP SORT-BY-COMPONENT)" '(org-mode))
+(eval-after-load 'org '(progn (org-dynamic-block-define "denote-files-as-headings" 'denote-org-dblock-insert-files-as-headings)))
+(autoload 'org-dblock-write:denote-files-as-headings "denote-org" "\
+Function to update `denote-files' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block.
+
+(fn PARAMS)")
+(register-definition-prefixes "denote-org" '("denote-org-"))
+
+;;; End of scraped data
+
+(provide 'denote-org-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; denote-org-autoloads.el ends here
blob - /dev/null
blob + 8e1f48d7ad74b033b24c3cbe7e83108ec334769f (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/denote-org-pkg.el
@@ -0,0 +1,2 @@
+;; Generated package description from denote-org.el  -*- mode: lisp-data; no-byte-compile: t -*-
+(define-package "denote-org" "0.1.1" "Denote extensions for Org mode" '((emacs "28.1") (denote "4.0.0")) :commit "0151c5a8ef525ce523c7f6c42f0c49f731ad2ff5" :authors '(("Protesilaos Stavrou" . "info@protesilaos.com")) :maintainer '("Protesilaos Stavrou" . "info@protesilaos.com") :url "https://github.com/protesilaos/denote-org")
blob - /dev/null
blob + 80f75f9fe5adaaa334566230c050bacb3a5655bc (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/denote-org.el
@@ -0,0 +1,853 @@
+;;; denote-org.el --- Denote extensions for Org mode -*- lexical-binding: t -*-
+
+;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
+
+;; Author: Protesilaos Stavrou <info@protesilaos.com>
+;; Maintainer: Protesilaos Stavrou <info@protesilaos.com>
+;; URL: https://github.com/protesilaos/denote-org
+;; Version: 0.1.1
+;; Package-Requires: ((emacs "28.1") (denote "4.0.0"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Optional extensions to Denote that work specifically with Org mode.
+
+;;; Code:
+
+(require 'denote)
+(require 'org)
+
+(defgroup denote-org ()
+  "Optional extensions to Denote that work specifically with Org mode."
+  :group 'denote
+  :link '(info-link "(denote) top")
+  :link '(info-link "(denote-org) top")
+  :link '(url-link :tag "Denote homepage" "https://protesilaos.com/emacs/denote")
+  :link '(url-link :tag "Denote Org homepage" "https://protesilaos.com/emacs/denote-org"))
+
+;;;; Link to file and heading
+
+(defun denote-org--get-outline (file)
+  "Return `outline-regexp' headings and line numbers of FILE."
+  (with-current-buffer (find-file-noselect file)
+    (let ((outline-regexp (format "^\\(?:%s\\)" (or (bound-and-true-p outline-regexp) "\\*+ ")))
+          candidates)
+      (save-excursion
+        (goto-char (point-min))
+        (while (if (bound-and-true-p outline-search-function)
+                   (funcall outline-search-function)
+                 (re-search-forward outline-regexp nil t))
+          (push
+           ;; NOTE 2024-01-20: The -5 (minimum width) is a
+           ;; sufficiently high number to keep the alignment
+           ;; consistent in most cases.  Larger files will simply
+           ;; shift the heading text in minibuffer, but this is not an
+           ;; issue anymore.
+           (format "%-5s %s"
+                   (line-number-at-pos (point))
+                   (buffer-substring-no-properties (line-beginning-position) (line-end-position)))
+           candidates)
+          (goto-char (1+ (line-end-position)))))
+      (if candidates
+          (nreverse candidates)
+        (user-error "No outline")))))
+
+(define-obsolete-function-alias
+  'denote-org--outline-prompt
+  'denote-org-outline-prompt
+  "3.1.0")
+
+(defun denote-org-outline-prompt (&optional file)
+  "Prompt for outline among headings retrieved by `denote-org--get-outline'.
+With optional FILE use the outline of it, otherwise use that of
+the current file."
+  (let ((current-file (or file buffer-file-name)))
+    (completing-read
+     (format "Select heading inside `%s': "
+             (propertize (file-name-nondirectory current-file) 'face 'denote-faces-prompt-current-name))
+     (denote--completion-table-no-sort 'imenu (denote-org--get-outline current-file))
+     nil :require-match)))
+
+(defun denote-org--get-heading-and-id-from-line (line file)
+  "Return heading text and CUSTOM_ID from the given LINE in FILE."
+  (with-current-buffer (find-file-noselect file)
+    (save-excursion
+      (goto-char (point-min))
+      (forward-line (1- line))
+      (cons (denote-link-ol-get-heading)
+            (if (eq denote-org-store-link-to-heading 'context)
+                (org-entry-get (point) "CUSTOM_ID")
+              (denote-link-ol-get-id))))))
+
+(defun denote-org-format-link-with-heading (file heading-id description &optional format)
+  "Prepare link to FILE with HEADING-ID using DESCRIPTION.
+Optional FORMAT is the exact link pattern to use."
+  (when (region-active-p)
+    (setq description (buffer-substring-no-properties (region-beginning) (region-end)))
+    (denote--delete-active-region-content))
+  (format
+   (or format "[[denote:%s::#%s][%s]]")
+   (denote-retrieve-filename-identifier file)
+   heading-id
+   description))
+
+(define-obsolete-function-alias
+  'denote-org-extras-link-to-heading
+  'denote-org-link-to-heading
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-link-to-heading ()
+  "Link to file and then specify a heading to extend the link to.
+
+The resulting link has the following pattern:
+
+[[denote:IDENTIFIER::#ORG-HEADING-CUSTOM-ID]][Description::Heading text]].
+
+Because only Org files can have links to individual headings,
+limit the list of possible files to those which include the .org
+file extension (remember that Denote works with many file types,
+per the user option `denote-file-type').
+
+The user option `denote-org-store-link-to-heading'
+determined whether the `org-store-link' function can save a link
+to the current heading.  Such links look the same as those of
+this command, though the functionality defined herein is
+independent of it.
+
+To only link to a file, use the `denote-link' command.
+
+Also see `denote-org-backlinks-for-heading'."
+  (declare (interactive-only t))
+  (interactive nil org-mode)
+  (unless (derived-mode-p 'org-mode)
+    (user-error "Links to headings only work between Org files"))
+  (let ((context-p (eq denote-org-store-link-to-heading 'context)))
+    (when-let* ((file (denote-file-prompt ".*\\.org"))
+                (file-text (denote-get-link-description file))
+                (heading (denote-org-outline-prompt file))
+                (line (string-to-number (car (split-string heading "\t"))))
+                (heading-data (denote-org--get-heading-and-id-from-line line file))
+                (heading-text (car heading-data))
+                (heading-id (if (and context-p (null (cdr heading-data)))
+                                heading-text
+                              (cdr heading-data)))
+                (description (denote-link-format-heading-description file-text heading-text)))
+      (insert
+       (denote-org-format-link-with-heading
+        file
+        heading-id
+        description
+        (when (equal heading-text heading-id)
+          "[[denote:%s::*%s][%s]]"))))))
+
+;;;; Heading backlinks
+
+(defun denote-org--get-file-id-and-heading-id-or-context ()
+  "Return link to current file and heading.
+If a CUSTOM_ID is present and the value of the user option
+`denote-org-store-link-to-heading' is set to `context', then return a
+regexp that matches both the CUSTOM_ID and the context of the current
+heading.  This looks like:
+
+    \\(ID::*HEADING-TEXT\\|ID::#HEADING-ID\\)
+
+If CUSTOM_ID is present but `denote-org-store-link-to-heading' is not
+set to `context', then return a patternf of the following form:
+
+    ID::#HEADING-ID"
+  (when-let* ((id (denote-retrieve-filename-identifier-with-error buffer-file-name)))
+    (let ((context-p (eq denote-org-store-link-to-heading 'context))
+          (heading-id (org-entry-get (point) "CUSTOM_ID")))
+      (cond
+       ((and context-p heading-id)
+        (format "\\(%s::%s%s\\|#%s\\)" id (shell-quote-argument "*") (denote-link-ol-get-heading) heading-id))
+       (context-p
+        (concat id "::" (shell-quote-argument "*") (denote-link-ol-get-heading)))
+       (heading-id
+        (concat id "::#" heading-id))
+       (t
+        (error "No way to get link to a heading at point in file `%s'" buffer-file-name))))))
+
+(defun denote-org--get-backlinks-buffer-name (text)
+  "Format a buffer name for `denote-org-backlinks-for-heading' with TEXT."
+  (format "*Denote HEADING backlinks for %S*" text))
+
+(defun denote-org--get-backlinks-for-heading (file-and-heading-id)
+  "Get backlinks to FILE-AND-HEADING-ID as a list of strings."
+  (when-let* ((files (denote-directory-files nil :omit-current :text-only))
+              (xref-file-name-display 'abs)
+              (matches-in-files (xref-matches-in-files file-and-heading-id files))
+              (xref-alist (xref--analyze matches-in-files)))
+    (mapcar
+     (lambda (x)
+       (denote-get-file-name-relative-to-denote-directory (car x)))
+     xref-alist)))
+
+(define-obsolete-function-alias
+  'denote-org-extras-backlinks-for-heading
+  'denote-org-backlinks-for-heading
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-backlinks-for-heading ()
+  "Produce backlinks for the current heading.
+This otherwise has the same behaviour as `denote-backlinks'---refer to
+that for the details.
+
+Also see `denote-org-link-to-heading'."
+  (interactive)
+  (when-let* ((heading-id (denote-org--get-file-id-and-heading-id-or-context))
+              (heading-text (substring-no-properties (denote-link-ol-get-heading))))
+    (denote-link--prepare-backlinks heading-id ".*\\.org" (denote-org--get-backlinks-buffer-name heading-text))))
+
+;;;; Extract subtree into its own note
+
+(defun denote-org--get-heading-date ()
+  "Try to return a timestamp for the current Org heading.
+This can be used as the value for the DATE argument of the
+`denote' command."
+  (when-let* ((pos (point))
+              (timestamp (or (org-entry-get pos "DATE")
+                             (org-entry-get pos "CREATED")
+                             (org-entry-get pos "CLOSED"))))
+    (date-to-time timestamp)))
+
+(define-obsolete-function-alias
+  'denote-org-extras-extract-org-subtree
+  'denote-org-extract-org-subtree
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-extract-org-subtree ()
+  "Create new Denote note using the current Org subtree as input.
+Remove the subtree from its current file and move its contents into a
+new Denote file (a subtree is a heading with all of its contents,
+including subheadings).
+
+Take the text of the subtree's top level heading and use it as the title
+of the new note.
+
+If the heading has any tags, use them as the keywords of the new note.
+If the Org file has any #+filetags use them as well (Org's filetags are
+inherited by the headings).  If none of these are true and the user
+option `denote-prompts' includes an entry for keywords, then prompt for
+keywords.  Else do not include any keywords.
+
+If the heading has a PROPERTIES drawer, retain it for further review.
+
+If the heading's PROPERTIES drawer includes a DATE or CREATED property,
+or there exists a CLOSED statement with a timestamp value, use that to
+derive the date (or date and time) of the new note (if there is only a
+date, the time is taken as 00:00).  If more than one of these is
+present, the order of preference is DATE, then CREATED, then CLOSED.  If
+none of these is present, use the current time.  If the `denote-prompts'
+includes an entry for a date, then prompt for a date at this stage (also
+see `denote-date-prompt-use-org-read-date').
+
+For the rest, consult the value of the user option `denote-prompts' in
+the following scenaria:
+
+- Optionally prompt for a subdirectory, otherwise produce the new note
+  in the variable `denote-directory'.
+
+- Optionally prompt for a file signature, otherwise do not use one.
+
+Make the new note an Org file regardless of the value of the user option
+`denote-file-type'."
+  (interactive nil org-mode)
+  (unless (derived-mode-p 'org-mode)
+    (user-error "Headings can only be extracted from Org files"))
+  (if-let* ((text (org-get-entry))
+            (heading (denote-link-ol-get-heading)))
+      (let ((tags (org-get-tags))
+            (date (denote-org--get-heading-date))
+            subdirectory
+            signature)
+        (dolist (prompt denote-prompts)
+          (pcase prompt
+            ('keywords (when (not tags) (setq tags (denote-keywords-prompt))))
+            ('subdirectory (setq subdirectory (denote-subdirectory-prompt)))
+            ('date (when (not date) (setq date (denote-date-prompt))))
+            ('signature (setq signature (denote-signature-prompt)))))
+        (delete-region (org-entry-beginning-position)
+                       (save-excursion (org-end-of-subtree t) (point)))
+        (denote heading tags 'org subdirectory date text signature))
+    (user-error "No subtree to extract; aborting")))
+
+;;;; Convert links from `:denote' to `:file' and vice versa
+
+(defun denote-org--get-link-type-regexp (type)
+  "Return regexp for Org link TYPE.
+TYPE is a symbol of either `file' or `denote'.
+
+The regexp consists of four groups.  Group 1 is the link type, 2
+is the target, 3 is the target's search terms, and 4 is the
+description."
+  (let ((group-1))
+    (pcase type
+      ('denote (setq group-1 "denote"))
+      ('file (setq group-1 "file"))
+      (_ (error "`%s' is an unknown link type" type)))
+    (format "\\[\\[\\(?1:%s:\\)\\(?:\\(?2:.*?\\)\\(?3:::.*\\)?\\]\\|\\]\\)\\(?4:\\[\\(?:.*?\\)\\]\\)?\\]" group-1)))
+
+(defun denote-org--get-path (id)
+  "Return file path to ID according to `org-link-file-path-type'."
+  (if (or (eq org-link-file-path-type 'adaptive)
+          (eq org-link-file-path-type 'relative))
+      (denote-get-relative-path-by-id id)
+    (denote-get-path-by-id id)))
+
+(define-obsolete-function-alias
+  'denote-org-extras-convert-links-to-file-type
+  'denote-org-convert-links-to-file-type
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-convert-links-to-file-type ()
+  "Convert denote: links to file: links in the current Org buffer.
+Ignore all other link types.  Also ignore links that do not
+resolve to a file in the variable `denote-directory'."
+  (interactive nil org-mode)
+  (if (derived-mode-p 'org-mode)
+      (save-excursion
+        (let ((count 0))
+          (goto-char (point-min))
+          (while (re-search-forward (denote-org--get-link-type-regexp 'denote) nil :no-error)
+            (let* ((id (match-string-no-properties 2))
+                   (search (or (match-string-no-properties 3) ""))
+                   (desc (or (match-string-no-properties 4) ""))
+                   (file (save-match-data (denote-org--get-path id))))
+              (when file
+                (let ((new-text (if desc
+                                    (format "[[file:%s%s]%s]" file search desc)
+                                  (format "[[file:%s%s]]" file search))))
+                  (replace-match new-text :fixed-case :literal)
+                  (setq count (1+ count))))))
+          (message "Converted %d `denote:' links to `file:' links" count)))
+    (user-error "The current file is not using Org mode")))
+
+(define-obsolete-function-alias
+  'denote-org-extras-convert-links-to-denote-type
+  'denote-org-convert-links-to-denote-type
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-convert-links-to-denote-type ()
+  "Convert file: links to denote: links in the current Org buffer.
+Ignore all other link types.  Also ignore file: links that do not
+point to a file with a Denote file name."
+  (interactive nil org-mode)
+  (if (derived-mode-p 'org-mode)
+      (save-excursion
+        (let ((count 0))
+          (goto-char (point-min))
+          (while (re-search-forward (denote-org--get-link-type-regexp 'file) nil :no-error)
+            (let* ((file (match-string-no-properties 2))
+                   (search (or (match-string-no-properties 3) ""))
+                   (desc (or (match-string-no-properties 4) ""))
+                   (id (save-match-data (denote-retrieve-filename-identifier file))))
+              (when id
+                (let ((new-text (if desc
+                                    (format "[[denote:%s%s]%s]" id search desc)
+                                  (format "[[denote:%s%s]]" id search))))
+                  (replace-match new-text :fixed-case :literal)
+                  (setq count (1+ count))))))
+          (message "Converted %d `file:' links to `denote:' links" count)))
+    (user-error "The current file is not using Org mode")))
+
+;;;; Org dynamic blocks
+
+;; NOTE 2024-01-22 12:26:13 +0200: The following is copied from the
+;; now-deleted denote-org-dblock.el.  Its original author was Elias
+;; Storms <elias.storms@gmail.com>, with substantial contributions and
+;; further developments by me (Protesilaos).
+
+;; This section defines Org dynamic blocks using the facility described
+;; in the Org manual.  Evaluate this:
+;;
+;;    (info "(org) Dynamic Blocks")
+;;
+;; The dynamic blocks defined herein are documented at length in the
+;; Denote manual.  See the following node and its subsections:
+;;
+;;    (info "(denote) Use Org dynamic blocks")
+
+;;;;; Common helper functions
+
+(defun denote-org-dblock--files (files-matching-regexp &optional sort-by-component reverse exclude-regexp)
+  "Return list of FILES-MATCHING-REGEXP in variable `denote-directory'.
+SORT-BY-COMPONENT, REVERSE, EXCLUDE-REGEXP have the same meaning as
+`denote-sort-get-directory-files'.  If both are nil, do not try to
+perform any sorting.
+
+Also see `denote-org-dblock--files-missing-only'."
+  (cond
+   ((and sort-by-component reverse)
+    (denote-sort-get-directory-files files-matching-regexp sort-by-component reverse :omit-current exclude-regexp))
+   (sort-by-component
+    (denote-sort-get-directory-files files-matching-regexp sort-by-component nil :omit-current exclude-regexp))
+   (reverse
+    (denote-sort-get-directory-files files-matching-regexp :no-component-specified reverse :omit-current exclude-regexp))
+   (t
+    (denote-directory-files files-matching-regexp :omit-current nil exclude-regexp))))
+
+(defun denote-org-dblock--get-missing-links (regexp)
+  "Return list of missing links to all notes matching REGEXP.
+Missing links are those for which REGEXP does not have a match in
+the current buffer."
+  (let ((found-files (denote-directory-files regexp :omit-current))
+        (linked-files (denote-link--expand-identifiers denote-org-link-in-context-regexp)))
+    (if-let* ((final-files (seq-difference found-files linked-files)))
+        final-files
+      (message "All links matching `%s' are present" regexp)
+      '())))
+
+(defun denote-org-dblock--files-missing-only (files-matching-regexp &optional sort-by-component reverse)
+  "Return list of missing links to FILES-MATCHING-REGEXP.
+SORT-BY-COMPONENT and REVERSE have the same meaning as
+`denote-sort-files'.  If both are nil, do not try to perform any
+sorting.
+
+Also see `denote-org-dblock--files'."
+  (denote-sort-files
+   (denote-org-dblock--get-missing-links files-matching-regexp)
+   sort-by-component
+   reverse))
+
+;;;;; Dynamic block to insert links
+
+(define-obsolete-function-alias
+  'denote-org-extras-dblock-insert-links
+  'denote-org-dblock-insert-links
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-dblock-insert-links (regexp)
+  "Create Org dynamic block to insert Denote links matching REGEXP."
+  (interactive
+   (list
+    (denote-files-matching-regexp-prompt))
+   org-mode)
+  (org-create-dblock (list :name "denote-links"
+                           :regexp regexp
+                           :not-regexp nil
+                           :excluded-dirs-regexp nil
+                           :sort-by-component nil
+                           :reverse-sort nil
+                           :id-only nil
+                           :include-date nil))
+  (org-update-dblock))
+
+;; NOTE 2024-03-30: This is how the autoload is done in org.el.
+;;;###autoload
+(eval-after-load 'org
+  '(progn
+     (org-dynamic-block-define "denote-links" 'denote-org-dblock-insert-links)))
+
+;; TODO 2024-12-04: Maybe we can do this for anything that deals with
+;; regular expressions that users provide?  I prefer not to do the
+;; work if nobody wants it, though I am mentioning this here just in
+;; case.
+(defun denote-org--parse-rx (regexp)
+  "Parse REGEXP as an `rx' argument or string and return string."
+  (cond
+   ((null regexp)
+    nil)
+   ((listp regexp)
+    (rx-to-string regexp))
+   ((stringp regexp)
+    regexp)
+   (t
+    (error "Regexp `%s' is neither a list nor a string" regexp))))
+
+;;;###autoload
+(defun org-dblock-write:denote-links (params)
+  "Function to update `denote-links' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block."
+  (let* ((rx (denote-org--parse-rx (plist-get params :regexp)))
+         (not-rx (denote-org--parse-rx (plist-get params :not-regexp)))
+         (sort (plist-get params :sort-by-component))
+         (reverse (plist-get params :reverse-sort))
+         (include-date (plist-get params :include-date))
+         (block-name (plist-get params :block-name))
+         (denote-excluded-directories-regexp (or (plist-get params :excluded-dirs-regexp)
+                                                 denote-excluded-directories-regexp))
+         (files (denote-org-dblock--files rx sort reverse not-rx)))
+    (when block-name (insert "#+name: " block-name "\n"))
+    (denote-link--insert-links files 'org (plist-get params :id-only) :no-other-sorting include-date)
+    (join-line))) ; remove trailing empty line
+
+;;;;; Dynamic block to insert missing links
+
+;; TODO 2024-12-03: Do we need the :not-regexp here?  I think yes,
+;; though I prefer to have a user of this kind of dblock send me their
+;; feedback.
+
+(define-obsolete-function-alias
+  'denote-org-extras-dblock-insert-missing-links
+  'denote-org-dblock-insert-missing-links
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-dblock-insert-missing-links (regexp)
+  "Create Org dynamic block to insert Denote links matching REGEXP."
+  (interactive
+   (list
+    (denote-files-matching-regexp-prompt))
+   org-mode)
+  (org-create-dblock (list :name "denote-missing-links"
+                           :regexp regexp
+                           :excluded-dirs-regexp nil
+                           :sort-by-component nil
+                           :reverse-sort nil
+                           :id-only nil
+                           :include-date nil))
+  (org-update-dblock))
+
+;; NOTE 2024-03-30: This is how the autoload is done in org.el.
+;;;###autoload
+(eval-after-load 'org
+  '(progn
+     (org-dynamic-block-define "denote-missing-links" 'denote-org-dblock-insert-missing-links)))
+
+;;;###autoload
+(defun org-dblock-write:denote-missing-links (params)
+  "Function to update `denote-links' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block."
+  (let* ((rx (denote-org--parse-rx (plist-get params :regexp)))
+         (sort (plist-get params :sort-by-component))
+         (reverse (plist-get params :reverse-sort))
+         (include-date (plist-get params :include-date))
+         (block-name (plist-get params :block-name))
+         (denote-excluded-directories-regexp (or (plist-get params :excluded-dirs-regexp)
+                                                 denote-excluded-directories-regexp))
+         (files (denote-org-dblock--files-missing-only rx sort reverse)))
+    (when block-name (insert "#+name: " block-name "\n"))
+    (denote-link--insert-links files 'org (plist-get params :id-only) :no-other-sorting include-date)
+    (join-line))) ; remove trailing empty line
+
+;;;;; Dynamic block to insert backlinks
+
+(defun denote-org-dblock--maybe-sort-backlinks (files sort-by-component reverse)
+  "Sort backlink FILES if SORT-BY-COMPONENT and/or REVERSE is non-nil."
+  (cond
+   ((and sort-by-component reverse)
+    (denote-sort-files files sort-by-component reverse))
+   (sort-by-component
+    (denote-sort-files files sort-by-component))
+   (reverse
+    (denote-sort-files files :no-component-specified reverse))
+   (t
+    files)))
+
+;; TODO 2024-12-03: Do we need the :not-regexp here?  I think yes,
+;; though I prefer to have a user of this kind of dblock send me their
+;; feedback.
+
+(define-obsolete-function-alias
+  'denote-org-extras-dblock-insert-backlinks
+  'denote-org-dblock-insert-backlinks
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-dblock-insert-backlinks ()
+  "Create Org dynamic block to insert Denote backlinks to current file."
+  (interactive nil org-mode)
+  (org-create-dblock (list :name "denote-backlinks"
+                           :excluded-dirs-regexp nil
+                           :sort-by-component nil
+                           :reverse-sort nil
+                           :id-only nil
+                           :this-heading-only nil
+                           :include-date nil))
+  (org-update-dblock))
+
+;; NOTE 2024-03-30: This is how the autoload is done in org.el.
+;;;###autoload
+(eval-after-load 'org
+  '(progn
+     (org-dynamic-block-define "denote-backlinks" 'denote-org-dblock-insert-backlinks)))
+
+;;;###autoload
+(defun org-dblock-write:denote-backlinks (params)
+  "Function to update `denote-backlinks' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block."
+  (when-let* ((files (if (plist-get params :this-heading-only)
+                         (denote-org--get-backlinks-for-heading (denote-org--get-file-id-and-heading-id-or-context))
+                       (denote-link-return-backlinks))))
+    (let* ((sort (plist-get params :sort-by-component))
+           (reverse (plist-get params :reverse-sort))
+           (include-date (plist-get params :include-date))
+           (denote-excluded-directories-regexp (or (plist-get params :excluded-dirs-regexp)
+                                                   denote-excluded-directories-regexp))
+           (files (denote-org-dblock--maybe-sort-backlinks files sort reverse)))
+      (denote-link--insert-links files 'org (plist-get params :id-only) :no-other-sorting include-date)
+      (join-line)))) ; remove trailing empty line
+
+;;;;; Dynamic block to insert entire file contents
+
+(defun denote-org-dblock--get-file-contents (file &optional no-front-matter add-links)
+  "Insert the contents of FILE.
+With optional NO-FRONT-MATTER as non-nil, try to remove the front
+matter from the top of the file.  If NO-FRONT-MATTER is a number,
+remove that many lines starting from the top.  If it is any other
+non-nil value, delete from the top until the first blank line.
+
+With optional ADD-LINKS as non-nil, first insert a link to the
+file and then insert its contents.  In this case, format the
+contents as a typographic list.  If ADD-LINKS is `id-only', then
+insert links as `denote-link' does when supplied with an ID-ONLY
+argument."
+  (when (denote-file-is-note-p file)
+    (with-temp-buffer
+      (when add-links
+        (insert
+         (format "- %s\n\n"
+                 (denote-format-link
+                  file
+                  (denote-get-link-description file)
+                  'org
+                  (eq add-links 'id-only)))))
+      (let ((beginning-of-contents (point)))
+        (insert-file-contents file)
+        (when no-front-matter
+          (delete-region
+           (if (natnump no-front-matter)
+               (progn (forward-line no-front-matter) (line-beginning-position))
+             (1+ (re-search-forward "^$" nil :no-error 1)))
+           beginning-of-contents))
+        (when add-links
+          (indent-region beginning-of-contents (point-max) 2)))
+      (buffer-string))))
+
+(defvar denote-org-dblock-file-contents-separator
+  (concat "\n\n" (make-string 50 ?-) "\n\n\n")
+  "Fallback separator used by `denote-org-dblock-add-files'.")
+
+(defun denote-org-dblock--separator (separator)
+  "Return appropriate value of SEPARATOR for `denote-org-dblock-add-files'."
+  (cond
+   ((null separator) "")
+   ((stringp separator) separator)
+   (t denote-org-dblock-file-contents-separator)))
+
+(defun denote-org-dblock-add-files (regexp &optional separator no-front-matter add-links sort-by-component reverse excluded-dirs-regexp exclude-regexp)
+  "Insert files matching REGEXP.
+
+Seaprate them with the optional SEPARATOR.  If SEPARATOR is nil,
+use the `denote-org-dblock-file-contents-separator'.
+
+If optional NO-FRONT-MATTER is non-nil try to remove the front
+matter from the top of the file.  Do it by finding the first
+blank line, starting from the top of the buffer.
+
+If optional ADD-LINKS is non-nil, first insert a link to the file
+and then insert its contents.  In this case, format the contents
+as a typographic list.
+
+If optional SORT-BY-COMPONENT is a symbol among `denote-sort-components',
+sort files matching REGEXP by the corresponding Denote file name
+component.  If the symbol is not among `denote-sort-components',
+fall back to the default identifier-based sorting.
+
+If optional REVERSE is non-nil reverse the sort order.
+
+Optional EXCLUDED-DIRS-REGEXP is the `let' bound value of
+`denote-excluded-directories-regexp'.  When nil, the original value of
+that user option is used.
+
+Optional EXCLUDE-REGEXP is a more general way to exclude files whose
+name matches the given regular expression."
+  (let* ((denote-excluded-directories-regexp (or excluded-dirs-regexp denote-excluded-directories-regexp))
+         (files (denote-org-dblock--files regexp sort-by-component reverse exclude-regexp))
+         (files-contents (mapcar
+                          (lambda (file) (denote-org-dblock--get-file-contents file no-front-matter add-links))
+                          files)))
+    (insert (string-join files-contents (denote-org-dblock--separator separator)))))
+
+(define-obsolete-function-alias
+  'denote-org-extras-dblock-insert-files
+  'denote-org-dblock-insert-files
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-dblock-insert-files (regexp sort-by-component)
+  "Create Org dynamic block to insert Denote files matching REGEXP.
+Sort the files according to SORT-BY-COMPONENT, which is a symbol
+among `denote-sort-components'."
+  (interactive
+   (list
+    (denote-files-matching-regexp-prompt)
+    (denote-sort-component-prompt))
+   org-mode)
+  (org-create-dblock (list :name "denote-files"
+                           :regexp regexp
+                           :not-regexp nil
+                           :excluded-dirs-regexp nil
+                           :sort-by-component sort-by-component
+                           :reverse-sort nil
+                           :no-front-matter nil
+                           :file-separator nil
+                           :add-links nil))
+  (org-update-dblock))
+
+;; NOTE 2024-03-30: This is how the autoload is done in org.el.
+;;;###autoload
+(eval-after-load 'org
+  '(progn
+     (org-dynamic-block-define "denote-files" 'denote-org-dblock-insert-files)))
+
+;;;###autoload
+(defun org-dblock-write:denote-files (params)
+  "Function to update `denote-files' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block."
+  (let* ((rx (denote-org--parse-rx (plist-get params :regexp)))
+         (not-rx (denote-org--parse-rx (plist-get params :not-regexp)))
+         (sort (plist-get params :sort-by-component))
+         (reverse (plist-get params :reverse-sort))
+         (block-name (plist-get params :block-name))
+         (separator (plist-get params :file-separator))
+         (no-f-m (plist-get params :no-front-matter))
+         (add-links (plist-get params :add-links))
+         (excluded-dirs (plist-get params :excluded-dirs-regexp)))
+    (when block-name (insert "#+name: " block-name "\n"))
+    (when rx (denote-org-dblock-add-files rx separator no-f-m add-links sort reverse excluded-dirs not-rx)))
+  (join-line)) ; remove trailing empty line
+
+;;;; Insert files as headings
+
+(defun denote-org-dblock--extract-regexp (regexp)
+  "Extract REGEXP from the buffer and trim it of surrounding spaces."
+  (string-trim
+   (save-excursion
+     (re-search-forward regexp nil :no-error)
+     (buffer-substring-no-properties (match-end 0) (line-end-position)))))
+
+(defun denote-org-dblock--get-file-contents-as-heading (file add-links)
+  "Insert the contents of Org FILE, formatting the #+title as a heading.
+With optional ADD-LINKS, make the title link to the original file."
+  (when-let* (((denote-file-is-note-p file))
+              (identifier (denote-retrieve-filename-identifier file))
+              (file-type (denote-filetype-heuristics file))
+              ((eq file-type 'org)))
+    (with-temp-buffer
+      (let ((beginning-of-contents (point))
+            title
+            tags)
+        (insert-file-contents file)
+        (setq title (denote-org-dblock--extract-regexp (denote--title-key-regexp file-type)))
+        (setq tags (denote-org-dblock--extract-regexp (denote--keywords-key-regexp file-type)))
+        (delete-region (1+ (re-search-forward "^$" nil :no-error 1)) beginning-of-contents)
+        (goto-char beginning-of-contents)
+        (when (and title tags)
+          (if add-links
+              (insert (format "* [[denote:%s][%s]] %s\n\n" identifier title tags))
+            (insert (format "* %s %s\n\n" title tags)))
+          (org-align-tags :all))
+        (while (re-search-forward "^\\(*+?\\) " nil :no-error)
+          (replace-match (format "*%s " "\\1"))))
+      (buffer-string))))
+
+(defun denote-org-dblock-add-files-as-headings (regexp &optional add-links sort-by-component reverse excluded-dirs-regexp exclude-regexp)
+  "Insert files matching REGEXP.
+
+If optional ADD-LINKS is non-nil, first insert a link to the file
+and then insert its contents.  In this case, format the contents
+as a typographic list.
+
+If optional SORT-BY-COMPONENT is a symbol among `denote-sort-components',
+sort files matching REGEXP by the corresponding Denote file name
+component.  If the symbol is not among `denote-sort-components',
+fall back to the default identifier-based sorting.
+
+If optional REVERSE is non-nil reverse the sort order.
+
+Optional EXCLUDED-DIRS-REGEXP is the `let' bound value of
+`denote-excluded-directories-regexp'.  When nil, the original value of
+that user option is used.
+
+Optional EXCLUDE-REGEXP is a more general way to exclude files whose
+name matches the given regular expression."
+  (let* ((denote-excluded-directories-regexp (or excluded-dirs-regexp denote-excluded-directories-regexp))
+         (files (denote-org-dblock--files regexp sort-by-component reverse exclude-regexp))
+         (files-contents (mapcar
+                          (lambda (file)
+                            (denote-org-dblock--get-file-contents-as-heading file add-links))
+                          files)))
+    (insert (string-join files-contents))))
+
+(define-obsolete-function-alias
+  'denote-org-extras-dblock-insert-files-as-headings
+  'denote-org-dblock-insert-files-as-headings
+  "As part of making `denote-org' a standalone package")
+
+;;;###autoload
+(defun denote-org-dblock-insert-files-as-headings (regexp sort-by-component)
+  "Create Org dynamic block to insert Denote Org files matching REGEXP.
+
+Turn the #+title of each file into a top-level heading.  Then increment
+all original headings in the file by one, so that they become
+subheadings of what once was the #+title.
+
+Use the #+filetags of each file as tags for the top-level heading (what
+was the #+title).
+
+Sort the files according to SORT-BY-COMPONENT, which is a symbol
+among `denote-sort-components'.
+
+IMPORTANT NOTE: This dynamic block only works with Org files, because it
+has to assume the Org notation in order to insert each file's contents
+as its own heading."
+  (interactive
+   (list
+    (denote-files-matching-regexp-prompt)
+    (denote-sort-component-prompt))
+   org-mode)
+  (org-create-dblock (list :name "denote-files-as-headings"
+                           :regexp regexp
+                           :not-regexp nil
+                           :excluded-dirs-regexp nil
+                           :sort-by-component sort-by-component
+                           :reverse-sort nil
+                           :add-links nil))
+  (org-update-dblock))
+
+;; NOTE 2024-03-30: This is how the autoload is done in org.el.
+;;;###autoload
+(eval-after-load 'org
+  '(progn
+     (org-dynamic-block-define "denote-files-as-headings" 'denote-org-dblock-insert-files-as-headings)))
+
+;;;###autoload
+(defun org-dblock-write:denote-files-as-headings (params)
+  "Function to update `denote-files' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block."
+  (let* ((rx (denote-org--parse-rx (plist-get params :regexp)))
+         (not-rx (denote-org--parse-rx (plist-get params :not-regexp)))
+         (sort (plist-get params :sort-by-component))
+         (reverse (plist-get params :reverse-sort))
+         (block-name (plist-get params :block-name))
+         (add-links (plist-get params :add-links))
+         (excluded-dirs (plist-get params :excluded-dirs-regexp)))
+    (when block-name (insert "#+name: " block-name "\n"))
+    (when rx (denote-org-dblock-add-files-as-headings rx add-links sort reverse excluded-dirs not-rx)))
+  (join-line)) ; remove trailing empty line
+
+(provide 'denote-org)
+;;; denote-org.el ends here
blob - /dev/null
blob + f1fba7dac575b855475a6aecc1201ae5fcd2b7f1 (mode 644)
Binary files /dev/null and elpa/denote-org-0.1.1/denote-org.info differ
blob - /dev/null
blob + cf277daac78585fb73dccd9fcd5fed9303d556cc (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1/dir
@@ -0,0 +1,18 @@
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+
+File: dir,	Node: Top	This is the top of the INFO tree
+
+  This (the Directory node) gives a menu of major topics.
+  Typing "q" exits, "H" lists all Info commands, "d" returns here,
+  "h" gives a primer for first-timers,
+  "mEmacs<Return>" visits the Emacs manual, etc.
+
+  In Emacs, you can click mouse button 2 on a menu item or cross reference
+  to select it.
+
+* Menu:
+
+Emacs misc features
+* Denote Org: (denote-org).     Extensions to better integrate Org with Denote.
blob - /dev/null
blob + 707df4f9bdce70fe9deb2cf693b05bdfe88c6e4f (mode 644)
--- /dev/null
+++ elpa/denote-org-0.1.1.signed
@@ -0,0 +1 @@
+Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2025-04-19T23:10:04+0200 using EDDSA
\ No newline at end of file
blob - 5fcafacee76da44024a76a8368c10e684803ca8b
blob + b951843615cd8df89ec49b6397307b79232e5120
--- init.el
+++ init.el
@@ -3,6 +3,10 @@
 (require 'xdg)
 (require 'cl-lib)
 
+(setq lh/dir-documents
+      (expand-file-name
+       (cond ((eq system-type 'gnu/linux) (or (xdg-user-dir "DOCUMENTS") "~/Documents"))
+             ((eq system-type 'windows-nt) "~/Documents"))))
 (setq lh/dir-data-home
       (expand-file-name
        (cond ((eq system-type 'gnu/linux) (or (xdg-data-home) "~/.local/share"))
@@ -32,8 +36,9 @@
                                      ("melpa-stable" . 1)
                                      ("melpa" . 0))
         package-pinned-packages    '((sly . "melpa"))
-        package-selected-packages  '(csv-mode elfeed magit nhexl-mode notmuch ob-restclient paredit
-                                     paredit-menu restclient restclient-jq sly))
+        package-selected-packages  '(csv-mode denote denote-org elfeed magit nhexl-mode notmuch
+                                     ob-restclient paredit paredit-menu restclient
+                                     restclient-jq sly))
 (package-initialize)
 
 ;;;; Completions
@@ -102,8 +107,17 @@
 (with-eval-after-load 'restclient
   (require 'restclient-capf))
 
+;;;; org + denote
+(let* ((org-dir (expand-file-name "org" lh/dir-documents))
+       (denote-dir (expand-file-name "notes" org-dir)))
+  (make-directory org-dir t)
+  (make-directory denote-dir t)
+  (setopt org-directory org-dir
+          denote-directory denote-dir))
+
 ;;;; Misc
 (setopt focus-follows-mouse t
+        mouse-autoselect-window 0.2
         frame-resize-pixelwise t
         scroll-conservatively 100
         pixel-scroll-precision-mode t