emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/denote 79f5b62aa6 09/10: Merge all ancillary files into


From: ELPA Syncer
Subject: [elpa] externals/denote 79f5b62aa6 09/10: Merge all ancillary files into denote.el
Date: Sun, 31 Jul 2022 01:57:30 -0400 (EDT)

branch: externals/denote
commit 79f5b62aa6a7cacb90f638e5ca931400be1d287f
Author: Protesilaos Stavrou <info@protesilaos.com>
Commit: Protesilaos Stavrou <info@protesilaos.com>

    Merge all ancillary files into denote.el
    
    Makes things easier to manage and document.
---
 README.org            |  10 -
 denote-dired.el       | 220 -----------------
 denote-faces.el       | 117 ---------
 denote-link.el        | 629 ------------------------------------------------
 denote-org-capture.el | 109 ---------
 denote.el             | 648 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 648 insertions(+), 1085 deletions(-)

diff --git a/README.org b/README.org
index 0a566f4bbd..d0ef8c9900 100644
--- a/README.org
+++ b/README.org
@@ -304,7 +304,6 @@ template.  Such as:
 
 #+begin_src emacs-lisp
 (with-eval-after-load 'org-capture
-  (require 'denote-org-capture)
   (add-to-list 'org-capture-templates
                '("n" "New note (with Denote)" plain
                  (file denote-last-path)
@@ -1015,7 +1014,6 @@ There are two ways to set the mode.  Either use it for 
all directories,
 which probably is not needed:
 
 #+begin_src emacs-lisp
-(require 'denote-dired)
 (add-hook 'dired-mode-hook #'denote-dired-mode)
 #+end_src
 
@@ -1025,8 +1023,6 @@ Or configure the user option ~denote-dired-directories~ 
and then set up
 the function ~denote-dired-mode-in-directories~:
 
 #+begin_src emacs-lisp
-(require 'denote-dired)
-
 ;; We use different ways to specify a path for demo purposes.
 (setq denote-dired-directories
       (list denote-directory
@@ -1459,10 +1455,6 @@ Everything is in place to set up the package.
 
 (setq denote-date-format nil) ; read doc string
 
-;; You will not need to `require' all those individually once the
-;; package is available.
-(require 'denote-link)
-
 ;; By default, we fontify backlinks in their bespoke buffer.
 (setq denote-link-fontify-backlinks t)
 
@@ -1473,7 +1465,6 @@ Everything is in place to set up the package.
 ;; right away)
 (add-hook 'find-file-hook #'denote-link-buttonize-buffer)
 
-(require 'denote-dired)
 (setq denote-dired-rename-expert nil)
 
 ;; We use different ways to specify a path for demo purposes.
@@ -1527,7 +1518,6 @@ Everything is in place to set up the package.
   (define-key map (kbd "C-c C-d C-R") 
#'denote-dired-rename-marked-files-and-add-front-matters))
 
 (with-eval-after-load 'org-capture
-  (require 'denote-org-capture)
   (setq denote-org-capture-specifiers "%l\n%i\n%?")
   (add-to-list 'org-capture-templates
                '("n" "New note (with denote.el)" plain
diff --git a/denote-dired.el b/denote-dired.el
deleted file mode 100644
index 730b37038c..0000000000
--- a/denote-dired.el
+++ /dev/null
@@ -1,220 +0,0 @@
-;;; denote-dired.el --- Integration between Denote and Dired -*- 
lexical-binding: t -*-
-
-;; Copyright (C) 2022  Free Software Foundation, Inc.
-
-;; Author: Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Denote Development <~protesilaos/denote@lists.sr.ht>
-;; URL: https://git.sr.ht/~protesilaos/denote
-;; Mailing-List: https://lists.sr.ht/~protesilaos/denote
-;; Version: 0.4.0
-;; Package-Requires: ((emacs "27.2"))
-
-;; 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's file-naming scheme is not specific to notes or text files:
-;; it is useful for all sorts of files, such as multimedia and PDFs that
-;; form part of the user's longer-term storage (see manual's "The
-;; file-naming scheme").  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.
-;;
-;; The `denote-dired-rename-file' command renames a file and updates
-;; existing front matter if appropriate.
-;;
-;; If in Dired, the `FILE' to be renamed is the one at point, else the
-;; command prompts with minibuffer completion for a target file.
-;;
-;; If `FILE' has a Denote-compliant identifier, the command retains it
-;; while updating the `TITLE' and `KEYWORDS' fields of the file name.
-;; Otherwise it creates an identifier based on the file's attribute of last
-;; modification time.  If such attribute cannot be found, the identifier
-;; falls back to the current date and time.
-;;
-;; The default `TITLE' is retrieved from a line starting with a title
-;; field in the file's contents, depending on the given file type (see
-;; manual's "Front matter").  Else, the file name is used as a default
-;; value at the minibuffer prompt.
-;;
-;; As a final step after the `FILE', `TITLE', and `KEYWORDS' prompts, ask
-;; for confirmation, showing the difference between old and new file names.
-;; For example:
-;;
-;;     Rename sample.pdf to 20220612T052900--my-sample-title__testing.pdf? (y 
or n)
-;;
-;; However, if the user option `denote-dired-rename-expert' is non-nil, the
-;; command conducts the renaming operation outright---no questions asked!
-;;
-;; The file type extension (e.g. `.pdf') is read from the underlying file
-;; and is preserved through the renaming process.  Files that have no
-;; extension are simply left without one.
-;;
-;; Renaming only occurs relative to the current directory.  Files are not
-;; moved between directories.
-;;
-;; If the FILE has Denote-style front matter for the TITLE and KEYWORDS,
-;; ask to rewrite their values in order to reflect the new input (this
-;; step always requires confirmation and the underlying buffer is not
-;; saved, so consider invoking `diff-buffer-with-file' to double-check
-;; the effect).  The rewrite of the FILE and KEYWORDS in the front
-;; matter should not affect the rest of the block.
-;;
-;; If the file doesn't have front matter, skip this step (see the
-;; command `denote-dired-rename-file-and-add-front-matter').
-;;
-;; The `denote-dired-rename-file' command is intended to (i) rename
-;; existing Denote notes while updating their title and keywords in the
-;; front matter, (ii) rename files that can benefit from Denote's
-;; file-naming scheme.  The latter is a convenience we provide, since we
-;; already have all the requisite mechanisms in place (though Denote
-;; does not---and will not---manage such files).
-;;
-;;
-;; The command `denote-dired-rename-file-and-add-front-matter' has the
-;; same modalities of interaction as the `denote-dired-rename-file'
-;; command (see manual's "Rename a single file").  The difference is
-;; that it unconditionally inserts front matter at the start of a file.
-;;
-;; This command is thus suitable for a workflow where an existing writable
-;; file needs to be converted into a Denote-style note.  Whereas the other
-;; command does not insert front matter if one doesn't already exist.
-;;
-;; Front matter is added when the file type extension is among the
-;; supported ones (per `denote-file-type').
-;;
-;;
-;; The `denote-dired-rename-marked-files' command renames marked files in
-;; Dired to conform with our file-naming scheme.  The operation does the
-;; following:
-;;
-;; - 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 recognized as a Denote note, rewrite 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).
-;;
-;; The command `denote-dired-rename-marked-files-and-add-front-matters' is
-;; like `denote-dired-rename-marked-files' but also adds front matter.  The
-;; additon of front matter takes place only if the file has the appropriate
-;; file type extension (per the user option `denote-file-type').
-;;
-;; Buffers are not saved.  The user can thus check them to confirm that the
-;; new front matter does not cause any problems (e.g. by invoking the
-;; command `diff-buffer-with-file').
-;;
-;; Multiple buffers can be saved with `save-some-buffers' (read its doc
-;; string).
-;;
-;;
-;; 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:
-;;
-;;     (require 'denote-dired)
-;;     (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':
-;;
-;;     (require 'denote-dired)
-;;
-;;     ;; 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 `denote-dired-mode' does not only fontify note files that were
-;; created by Denote: it covers every file name that follows our naming
-;; conventions (read about "The file-naming scheme" in the manual).
-;; 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).
-;;
-;; For the time being, the `diredfl' package is not compatible with this
-;; facility.
-
-;;; Code:
-
-(require 'denote)
-(require 'denote-faces)
-
-(defgroup denote-dired ()
-  "Integration between Denote and Dired."
-  :group 'denote)
-
-(defcustom denote-dired-directories
-  ;; We use different ways to specify a path for demo purposes.
-  (list denote-directory
-        ;; (thread-last denote-directory (expand-file-name "attachments"))
-        (expand-file-name "~/Documents/vlog"))
-  "List of directories where `denote-dired-mode' should apply to."
-  :type '(repeat directory)
-  :group 'denote-dired)
-
-;;;; Extra fontification
-
-;;;###autoload
-(define-minor-mode denote-dired-mode
-  "Fontify all Denote-style file names in Dired."
-  :global nil
-  :group 'denote-dired
-  (if denote-dired-mode
-      (font-lock-add-keywords nil denote-faces-file-name-keywords t)
-    (font-lock-remove-keywords nil denote-faces-file-name-keywords))
-  (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'."
-  (when (member (file-truename default-directory) 
(denote-dired--modes-dirs-as-dirs))
-    (denote-dired-mode 1)))
-
-(provide 'denote-dired)
-;;; denote-dired.el ends here
diff --git a/denote-faces.el b/denote-faces.el
deleted file mode 100644
index 60ab040a9e..0000000000
--- a/denote-faces.el
+++ /dev/null
@@ -1,117 +0,0 @@
-;;; denote-faces.el --- Faces and fontification rules for Denote -*- 
lexical-binding: t -*-
-
-;; Copyright (C) 2022  Free Software Foundation, Inc.
-
-;; Author: Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Denote Development <~protesilaos/denote@lists.sr.ht>
-;; URL: https://git.sr.ht/~protesilaos/denote
-;; Mailing-List: https://lists.sr.ht/~protesilaos/denote
-;; Version: 0.4.0
-;; Package-Requires: ((emacs "27.2"))
-
-;; 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:
-;;
-;; Used internally by Denote to fontify file names in Dired, the
-;; backlinks' buffer, and related.
-
-;;; Code:
-
-(require 'denote)
-
-(defgroup denote-faces ()
-  "Faces for Denote."
-  :group 'denote)
-
-(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)
-
-(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)
-
-(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)
-
-(defface denote-faces-title
-  '((t ))
-  "Face for file name title in Dired buffers."
-  :group 'denote-faces)
-
-(defface denote-faces-extension
-  '((t :inherit shadow))
-  "Face for file extension type in Dired buffers."
-  :group 'denote-faces)
-
-(defface denote-faces-keywords
-  '((t :inherit font-lock-builtin-face))
-  "Face for file name keywords in Dired buffers."
-  :group 'denote-faces)
-
-(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)
-
-;; For character classes, evaluate: (info "(elisp) Char Classes")
-(defvar denote-faces--file-name-regexp
-  (concat "\\(?1:[0-9]\\{8\\}\\)\\(?2:T[0-9]\\{6\\}\\)"
-          "\\(?:\\(?3:--\\)\\(?4:[[:alnum:][:nonascii:]-]*\\)\\)?"
-          "\\(?:\\(?5:__\\)\\(?6:[[:alnum:][:nonascii:]_-]*\\)\\)?"
-          "\\(?7:\\..*\\)?$")
-  "Regexp of file names for fontification.")
-
-(defconst denote-faces-file-name-keywords
-  `((,(concat " " denote-faces--file-name-regexp)
-     (1 'denote-faces-date)
-     (2 'denote-faces-time)
-     (3 'denote-faces-delimiter nil t)
-     (4 'denote-faces-title nil t)
-     (5 'denote-faces-delimiter nil t)
-     (6 'denote-faces-keywords nil t)
-     (7 'denote-faces-extension nil t )))
-  "Keywords for fontification of file names.")
-
-(defconst denote-faces-file-name-keywords-for-backlinks
-  `((,(concat "^\\(?8:.*/\\)?" denote-faces--file-name-regexp)
-     (8 'denote-faces-subdirectory nil t)
-     (1 'denote-faces-date)
-     (2 'denote-faces-time)
-     (3 'denote-faces-delimiter nil t)
-     (4 'denote-faces-title nil t)
-     (5 'denote-faces-delimiter nil t)
-     (6 'denote-faces-keywords nil t)
-     (7 'denote-faces-extension nil t )))
-  "Keywords for fontification of file names in the backlinks buffer.")
-
-(provide 'denote-faces)
-;;; denote-faces.el ends here
diff --git a/denote-link.el b/denote-link.el
deleted file mode 100644
index 99fd69955e..0000000000
--- a/denote-link.el
+++ /dev/null
@@ -1,629 +0,0 @@
-;;; denote-link.el --- Link facility for Denote -*- lexical-binding: t -*-
-
-;; Copyright (C) 2022  Free Software Foundation, Inc.
-
-;; Author: Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Denote Development <~protesilaos/denote@lists.sr.ht>
-;; URL: https://git.sr.ht/~protesilaos/denote
-;; Mailing-List: https://lists.sr.ht/~protesilaos/denote
-;; Version: 0.4.0
-;; Package-Requires: ((emacs "27.2"))
-
-;; 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:
-;;
-;; The `denote-link' command inserts a link at point to an entry specified
-;; at the minibuffer prompt.  Links are formatted depending on the file
-;; type of current note.  In Org and plain text buffers, links are
-;; formatted thus: `[[denote:IDENTIFIER][TITLE]]'.  While in Markdown they
-;; are expressed as `[TITLE](denote:IDENTIFIER)'.
-;;
-;; When `denote-link' is called with a prefix argument (`C-u' by default),
-;; it formats links like `[[denote:IDENTIFIER]]'.  The user might prefer
-;; its simplicity.
-;;
-;; Inserted links are automatically buttonized and remain active for as
-;; long as the buffer is available.  In Org this is handled by the major
-;; mode: the `denote:' hyperlink type works exactly like the standard
-;; `file:'.  In Markdown and plain text, Denote performs the buttonization
-;; of those links.  To buttonize links in existing files while visiting
-;; them, the user must add this snippet to their setup (it already excludes
-;; Org):
-;;
-;;     (add-hook 'find-file-hook #'denote-link-buttonize-buffer)
-;;
-;; 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-link-find-file' 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 (see manual's
-;; "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).
-;;
-;; The command `denote-link-backlinks' produces a bespoke buffer which
-;; displays the file name of all notes linking to the current one.  Each
-;; file name appears on its own line and is buttonized so that it performs
-;; the action of visiting the referenced file.  The backlinks' buffer looks
-;; like this:
-;;
-;;     Backlinks to "On being honest" (20220614T130812)
-;;     ------------------------------------------------
-;;
-;;     20220614T145606--let-this-glance-become-a-stare__journal.txt
-;;     20220616T182958--not-feeling-butterflies-in-your-stomach__journal.txt
-;;
-;; The backlinks' buffer is fontified by default, though the user has
-;; access to the `denote-link-fontify-backlinks' option to disable this
-;; effect by setting its value to nil.
-;;
-;; The placement of the backlinks' buffer is subject to the user option
-;; `denote-link-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.  The doc string of our user option includes a sample
-;; configuration that places the buffer in a left side window instead.
-;; Reproducing it here for the sake of convenience:
-;;
-;;     (setq denote-link-backlinks-display-buffer-action
-;;           '((display-buffer-reuse-window
-;;              display-buffer-in-side-window)
-;;             (side . left)
-;;             (slot . 99)
-;;             (window-width . 0.3)))
-;;
-;; The command `denote-link-add-links' adds links at point matching a
-;; regular expression or plain string.  The links 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-link-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.
-;;
-;; For convenience, the `denote-link' command has an alias called
-;; `denote-link-insert-link'.  The `denote-link-backlinks' can also be used
-;; as `denote-link-show-backlinks-buffer'.  While `denote-link-add-links'
-;; is aliased `denote-link-insert-links-matching-regexp'.  The purpose of
-;; these aliases is to offer alternative, more descriptive names of select
-;; commands.
-
-;;; Code:
-
-(require 'denote)
-(require 'denote-faces)
-
-(defgroup denote-link ()
-  "Link facility for Denote."
-  :group 'denote)
-
-;;;; User options
-
-(defcustom denote-link-fontify-backlinks t
-  "When non-nil, apply faces to files in the backlinks' buffer."
-  :type 'boolean
-  :group 'denote-link)
-
-(defcustom denote-link-backlinks-display-buffer-action
-  '((display-buffer-reuse-window display-buffer-below-selected)
-    (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-link-backlinks-display-buffer-action
-          (quote ((display-buffer-reuse-window
-                   display-buffer-in-side-window)
-                  (side . left)
-                  (slot . 99)
-                  (window-width . 0.3))))
-
-See Info node `(elisp) Displaying Buffers' for more details
-and/or the documentation string of `display-buffer'."
-  :type '(cons (choice (function :tag "Display Function")
-                       (repeat :tag "Display Functions" function))
-               alist)
-  :group 'denote-link)
-
-;;;; Link to note
-
-;; Arguments are: FILE-ID FILE-TITLE
-(defconst denote-link--format-org "[[denote:%s][%s]]"
-  "Format of Org link to note.")
-
-(defconst denote-link--format-markdown "[%2$s](denote:%1$s)"
-  "Format of Markdown link to note.")
-
-(defconst denote-link--format-id-only "[[denote:%s]]"
-  "Format of identifier-only link to note.")
-
-(defconst denote-link--regexp-org
-  (concat "\\[\\[" "denote:"  "\\(?1:" denote--id-regexp "\\)" "]" "\\[.*?]]"))
-
-(defconst denote-link--regexp-markdown
-  (concat "\\[.*?]" "(denote:"  "\\(?1:" denote--id-regexp "\\)" ")"))
-
-(defconst denote-link--regexp-plain
-  (concat "\\[\\[" "denote:"  "\\(?1:" denote--id-regexp "\\)" "]]"))
-
-(defun denote-link--file-type-format (current-file id-only)
-  "Return link format based on CURRENT-FILE format.
-With non-nil ID-ONLY, use the generic link format without a
-title."
-  ;; Includes backup files.  Maybe we can remove them?
-  (let ((current-file-ext (file-name-extension current-file)))
-    (cond
-     (id-only denote-link--format-id-only)
-     ((string= current-file-ext "md")
-      denote-link--format-markdown)
-     ;; Plain text also uses [[denote:ID][TITLE]]
-     (t denote-link--format-org))))
-
-(defun denote-link--file-type-regexp (file)
-  "Return link regexp based on FILE format."
-  (pcase (file-name-extension file)
-    ("md" denote-link--regexp-markdown)
-    (_ denote-link--regexp-org)))
-
-(defun denote-link--format-link (file pattern)
-  "Prepare link to FILE using PATTERN."
-  (let ((file-id (denote--retrieve-filename-identifier file))
-        (file-title (unless (string= pattern denote-link--format-id-only)
-                      (denote--retrieve-value-title file))))
-    (format pattern file-id file-title)))
-
-;;;###autoload
-(defun denote-link (target &optional id-only)
-  "Create link to TARGET note in variable `denote-directory'.
-With optional ID-ONLY, such as a universal prefix
-argument (\\[universal-argument]), insert links with just the
-identifier and no further description.  In this case, the link
-format is always [[denote:IDENTIFIER]]."
-  (interactive (list (denote--retrieve-read-file-prompt) current-prefix-arg))
-  (let ((beg (point)))
-    (insert
-     (denote-link--format-link
-      target
-      (denote-link--file-type-format (buffer-file-name) id-only)))
-    (unless (derived-mode-p 'org-mode)
-      (make-button beg (point) 'type 'denote-link-button))))
-
-(defalias 'denote-link-insert-link (symbol-function 'denote-link))
-
-(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-link--regexp-plain 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-prefix-p i (file-name-nondirectory file))
-          (push file found-files))))
-    found-files))
-
-(defvar denote-link--find-file-history nil
-  "History for `denote-link-find-file'.")
-
-(defun denote-link--find-file-prompt (files)
-  "Prompt for linked file among FILES."
-  (completing-read "Find linked file "
-                   (denote--completion-table 'file files)
-                   nil t
-                   nil 'denote-link--find-file-history))
-
-;; TODO 2022-06-14: Do we need to add any sort of extension to better
-;; integrate with Embark?  For the minibuffer interaction it is not
-;; necessary, but maybe it can be done to immediately recognise the
-;; identifiers are links to files?
-
-;;;###autoload
-(defun denote-link-find-file ()
-  "Use minibuffer completion to visit linked file."
-  (interactive)
-  (if-let* ((regexp (denote-link--file-type-regexp (buffer-file-name)))
-            (files (denote-link--expand-identifiers regexp)))
-      (find-file (denote-link--find-file-prompt files))
-    (user-error "No links found in the current buffer")))
-
-;;;; Link buttons
-
-;; Evaluate: (info "(elisp) Button Properties")
-;;
-;; Button can provide a help-echo function as well, but I think we might
-;; not need it.
-(define-button-type 'denote-link-button
-  'follow-link t
-  'action #'denote-link--find-file-at-button)
-
-(autoload 'thing-at-point-looking-at "thingatpt")
-
-(defun denote-link--link-at-point-string ()
-  "Return identifier at point."
-  (when (or (thing-at-point-looking-at denote-link--regexp-plain)
-            (thing-at-point-looking-at denote-link--regexp-markdown)
-            (thing-at-point-looking-at denote-link--regexp-org)
-            ;; Meant to handle the case where a link is broken by
-            ;; `fill-paragraph' into two lines, in which case it
-            ;; buttonizes only the "denote:ID" part.  Example:
-            ;;
-            ;; [[denote:20220619T175212][This is a
-            ;; test]]
-            ;;
-            ;; Maybe there is a better way?
-            (thing-at-point-looking-at "\\[\\(denote:.*\\)]"))
-    (match-string-no-properties 0)))
-
-(defun denote-link--id-from-string (string)
-  "Extract identifier from STRING."
-  (replace-regexp-in-string
-   (concat ".*denote:" "\\(" denote--id-regexp "\\)" ".*")
-   "\\1" string))
-
-;; NOTE 2022-06-15: I add this as a variable for advanced users who may
-;; prefer something else.  If there is demand for it, we can make it a
-;; defcustom, but I think it would be premature at this stage.
-(defvar denote-link-buton-action #'find-file-other-window
-  "Action for Denote buttons.")
-
-(defun denote-link--find-file-at-button (button)
-  "Visit file referenced by BUTTON."
-  (let* ((id (denote-link--id-from-string
-              (buffer-substring-no-properties
-               (button-start button)
-               (button-end button))))
-         (file (denote--get-note-path-by-id id)))
-    (funcall denote-link-buton-action file)))
-
-;;;###autoload
-(defun denote-link-buttonize-buffer (&optional beg end)
-  "Make denote: links actionable buttons in the current buffer.
-
-Add this to `find-file-hook'.  It will only work with Denote
-notes and will not do anything in `org-mode' buffers, as buttons
-already work there.  If you do not use Markdown or plain text,
-then you do not need this.
-
-When called from Lisp, with optional BEG and END as buffer
-positions, limit the process to the region in-between."
-  (interactive)
-  (when (and (not (derived-mode-p 'org-mode)) (denote--current-file-is-note-p))
-    (save-excursion
-      (goto-char (or beg (point-min)))
-      (while (re-search-forward denote--id-regexp end t)
-        (when-let ((string (denote-link--link-at-point-string))
-                   (beg (match-beginning 0))
-                   (end (match-end 0)))
-          (make-button beg end 'type 'denote-link-button))))))
-
-;;;; Backlinks' buffer
-
-(define-button-type 'denote-link-backlink-button
-  'follow-link t
-  'action #'denote-link--backlink-find-file
-  'face nil)            ; we use this face though we style it later
-
-(defun denote-link--backlink-find-file (button)
-  "Action for BUTTON to `find-file'."
-  (funcall denote-link-buton-action (buffer-substring (button-start button) 
(button-end button))))
-
-(defun denote-link--display-buffer (buf)
-  "Run `display-buffer' on BUF.
-Expand `denote-link-backlinks-display-buffer-action'."
-  (display-buffer
-   buf
-   `(,@denote-link-backlinks-display-buffer-action)))
-
-(defun denote-link--prepare-backlinks (id files &optional title)
-  "Create backlinks' buffer for ID including FILES.
-Use optional TITLE for a prettier heading."
-  (let ((inhibit-read-only t)
-        (buf (format "*denote-backlinks to %s*" id)))
-    (with-current-buffer (get-buffer-create buf)
-      (erase-buffer)
-      (special-mode)
-      (goto-char (point-min))
-      (when-let* ((title)
-                  (heading (format "Backlinks to %S (%s)" title id))
-                  (l (length heading)))
-        (insert (format "%s\n%s\n\n" heading (make-string l ?-))))
-      (mapc (lambda (f)
-              (insert f)
-              (make-button (point-at-bol) (point-at-eol) :type 
'denote-link-backlink-button)
-              (newline))
-            files)
-      (goto-char (point-min))
-      (when denote-link-fontify-backlinks
-        (font-lock-add-keywords nil 
denote-faces-file-name-keywords-for-backlinks t)))
-    (denote-link--display-buffer buf)))
-
-;;;###autoload
-(defun denote-link-backlinks ()
-  "Produce a buffer with files linking to current note.
-Each file is a clickable/actionable button that visits the
-referenced entry.  Files are fontified if the user option
-`denote-link-fontify-backlinks' is non-nil.
-
-The placement of the backlinks' buffer is controlled by the user
-option `denote-link-backlinks-display-buffer-action'.  By
-default, it will show up below the current window."
-  (interactive)
-  (let* ((default-directory (denote-directory))
-         (file (buffer-file-name))
-         (id (denote--retrieve-filename-identifier file))
-         (title (denote--retrieve-value-title file)))
-    (if-let ((files (denote--retrieve-proces-grep id)))
-        (denote-link--prepare-backlinks id files title)
-      (user-error "No links to the current note"))))
-
-(defalias 'denote-link-show-backlinks-buffer (symbol-function 
'denote-link-backlinks))
-
-;;;; Add links matching regexp
-
-(defvar denote-link--links-to-files nil
-  "String of `denote-link-add-links-matching-keyword'.")
-
-(defvar denote-link--prepare-links-format "- %s\n"
-  "Format specifiers for `denote-link-add-links'.")
-
-;; NOTE 2022-06-16: There is no need to overwhelm the user with options,
-;; though I expect someone to want to change the sort order.
-(defvar denote-link-add-links-sort nil
-  "Add REVERSE to `sort-lines' of `denote-link-add-links' when t.")
-
-(defun denote-link--prepare-links (files current-file id-only)
-  "Prepare links to FILES from CURRENT-FILE.
-When ID-ONLY is non-nil, use a generic link format.  See
-`denote-link--file-type-format'."
-  (setq denote-link--links-to-files
-        (with-temp-buffer
-          (mapc (lambda (file)
-                  (insert
-                   (format
-                    denote-link--prepare-links-format
-                    (denote-link--format-link
-                     file
-                     (denote-link--file-type-format current-file id-only)))))
-                files)
-          (sort-lines denote-link-add-links-sort (point-min) (point-max))
-          (buffer-string))))
-
-(defvar denote-link--add-links-history nil
-  "Minibuffer history for `denote-link-add-links'.")
-
-;;;###autoload
-(defun denote-link-add-links (regexp &optional id-only)
-  "Insert links to all notes matching 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
-    (read-regexp "Insert links matching REGEX: " nil 
'denote-link--add-links-history)
-    current-prefix-arg))
-  (let* ((default-directory (denote-directory))
-         (current-file (buffer-file-name)))
-    (if-let ((files (denote--directory-files-matching-regexp regexp)))
-        (let ((beg (point)))
-          (insert (denote-link--prepare-links files current-file id-only))
-          (unless (derived-mode-p 'org-mode)
-            (denote-link-buttonize-buffer beg (point))))
-      (user-error "No links matching `%s'" regexp))))
-
-(defalias 'denote-link-insert-links-matching-regexp (symbol-function 
'denote-link-add-links))
-
-;;;; Links from Dired marks
-
-;; NOTE 2022-07-21: I don't think we need a history for this one.
-(defun denote-link--buffer-prompt (buffers)
-  "Select buffer from BUFFERS visiting Denote notes."
-  (completing-read
-   "Select note buffer: "
-   (denote--completion-table 'buffer buffers)
-   nil t))
-
-(declare-function dired-get-marked-files "dired" (&optional localp arg filter 
distinguish-one-marked error))
-
-(defun denote-link--map-over-notes ()
-  "Return list of `denote--only-note-p' from Dired marked items."
-  (delq nil
-        (mapcar
-            (lambda (f)
-           (when (and (denote--only-note-p f)
-                      (denote--dir-in-denote-directory-p default-directory))
-             f))
-         (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 are Denote notes, meaning that they have our file-naming
-scheme, are writable/regular files, and use the appropriate file
-type extension (per `denote-file-type').  Furthermore, the marked
-files need to be inside the variable `denote-directory' or one of
-its subdirectories.  No other file is recognised (the list of
-marked files ignores whatever does not count as a note for our
-purposes).
-
-The BUFFER is one which visits a Denote note file.  If there are
-multiple buffers, prompt with completion for one among them.  If
-there isn't one, 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
-   (list
-    (denote-link--map-over-notes)
-    (let ((buffers (denote--buffer-file-names)))
-      (get-buffer
-       (cond
-        ((null buffers)
-         (user-error "No buffers visiting Denote notes"))
-        ((eq (length buffers) 1)
-         (car buffers))
-        (t
-         (denote-link--buffer-prompt buffers)))))
-    current-prefix-arg)
-   dired-mode)
-  (if (null files)
-      (user-error "No note files to link to")
-    (when (y-or-n-p (format "Create links at point in %s?" buffer))
-      (with-current-buffer buffer
-        (insert (denote-link--prepare-links files (buffer-file-name) id-only))
-        (denote-link-buttonize-buffer)))))
-
-;;;; 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 path-id)
-  "Resolve LINK into the appropriate target.
-With optional PATH-ID return a cons cell consisting of the path
-and the identifier."
-  (let* ((search (and (string-match "::\\(.*\\)\\'" link)
-                      (match-string 1 link)))
-         (id (if (and (stringp search) (not (string-empty-p search)))
-                 (substring link 0 (match-beginning 0))
-               link))
-         (path (denote--get-note-path-by-id id)))
-    (cond
-     (path-id
-      (cons (format "%s" path) (format "%s" id)))
-     ((and (stringp search) (not (string-empty-p search)))
-      (concat path "::" search))
-     (path))))
-
-(defun denote-link-ol-follow (link)
-  "Find file of type `denote:' matching LINK.
-LINK is the identifier of the note, optionally followed by a
-search option akin to that of standard Org `file:' link types.
-Read Info node `(org) Search Options'.
-
-Uses the function `denote-directory' to establish the path to the
-file."
-  (org-link-open-as-file
-   (denote-link--ol-resolve-link-to-target link)
-   nil))
-
-(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."
-  (concat
-   "denote:"
-   (denote--retrieve-filename-identifier (denote--retrieve-read-file-prompt))))
-
-(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."
-  (let* ((path-id (denote-link--ol-resolve-link-to-target link :path-id))
-         (path (file-name-nondirectory (car path-id)))
-         (p (file-name-sans-extension path))
-         (id (cdr path-id))
-         (desc (or description (concat "denote:" id))))
-    (cond
-     ((eq format 'html) (format "<a target=\"_blank\" href=\"%s.html\">%s</a>" 
p desc))
-     ((eq format 'latex) (format "\\href{%s}{%s}" (replace-regexp-in-string 
"[\\{}$%&_#~^]" "\\\\\\&" path) desc))
-     ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
-     ((eq format 'ascii) (format "[%s] <denote:%s>" desc path)) ; NOTE 
2022-06-16: May be tweaked further
-     ((eq format 'md) (format "[%s](%s.md)" desc p))
-     (t 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
-           :complete #'denote-link-ol-complete
-           :export #'denote-link-ol-export)))))
-
-(provide 'denote-link)
-;;; denote-link.el ends here
diff --git a/denote-org-capture.el b/denote-org-capture.el
deleted file mode 100644
index b802ba087d..0000000000
--- a/denote-org-capture.el
+++ /dev/null
@@ -1,109 +0,0 @@
-;;; denote-org-capture.el --- Integration between Denote and org-capture -*- 
lexical-binding: t -*-
-
-;; Copyright (C) 2022  Free Software Foundation, Inc.
-
-;; Author: Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Denote Development <~protesilaos/denote@lists.sr.ht>
-;; URL: https://git.sr.ht/~protesilaos/denote
-;; Mailing-List: https://lists.sr.ht/~protesilaos/denote
-;; Version: 0.4.0
-;; Package-Requires: ((emacs "27.2"))
-
-;; 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 integration with org-capture.
-;;
-;; Samples of an `org-capture-templates' entry:
-;;
-;;     (setq org-capture-templates
-;;           '(("n" "New note (with denote.el)" plain
-;;              (file denote-last-path)
-;;              #'denote-org-capture
-;;              :no-save t
-;;              :immediate-finish nil
-;;              :kill-buffer t
-;;              :jump-to-captured t)))
-;;
-;;     (with-eval-after-load 'org-capture
-;;       (add-to-list 'org-capture-templates
-;;                    '("n" "New note (with denote.el)" plain
-;;                      (file denote-last-path)
-;;                      #'denote-org-capture
-;;                      :no-save t
-;;                      :immediate-finish nil
-;;                      :kill-buffer t
-;;                      :jump-to-captured t)))
-;;
-;; 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'.
-
-;;; Code:
-
-(require 'denote)
-
-(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
-  :group 'denote-org-capture)
-
-;;;###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.
-
-Note that this function 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' (which can include
-arbitrary text).
-
-Consult the manual for template samples."
-  (let ((title (denote--title-prompt))
-        (keywords (denote--keywords-prompt))
-        (denote-file-type nil)) ; we enforce the .org extension for 
`org-capture'
-    (denote--path title keywords)
-    (setq denote-last-front-matter (denote--file-meta-header
-                                    title (denote--date nil) keywords
-                                    (format-time-string denote--id-format 
nil)))
-    (denote--keywords-add-to-history denote-last-keywords)
-    (concat denote-last-front-matter denote-org-capture-specifiers)))
-
-(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)
-
-(provide 'denote-org-capture)
-;;; denote-org-capture.el ends here
diff --git a/denote.el b/denote.el
index 5d16360344..663088e798 100644
--- a/denote.el
+++ b/denote.el
@@ -1414,5 +1414,653 @@ doc string)."
         (revert-buffer))
     (user-error "No marked files; aborting")))
 
+;;;; The Denote faces
+
+(defgroup denote-faces ()
+  "Faces for Denote."
+  :group 'denote)
+
+(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)
+
+(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)
+
+(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)
+
+(defface denote-faces-title
+  '((t ))
+  "Face for file name title in Dired buffers."
+  :group 'denote-faces)
+
+(defface denote-faces-extension
+  '((t :inherit shadow))
+  "Face for file extension type in Dired buffers."
+  :group 'denote-faces)
+
+(defface denote-faces-keywords
+  '((t :inherit font-lock-builtin-face))
+  "Face for file name keywords in Dired buffers."
+  :group 'denote-faces)
+
+(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)
+
+;; For character classes, evaluate: (info "(elisp) Char Classes")
+(defvar denote-faces--file-name-regexp
+  (concat "\\(?1:[0-9]\\{8\\}\\)\\(?2:T[0-9]\\{6\\}\\)"
+          "\\(?:\\(?3:--\\)\\(?4:[[:alnum:][:nonascii:]-]*\\)\\)?"
+          "\\(?:\\(?5:__\\)\\(?6:[[:alnum:][:nonascii:]_-]*\\)\\)?"
+          "\\(?7:\\..*\\)?$")
+  "Regexp of file names for fontification.")
+
+(defconst denote-faces-file-name-keywords
+  `((,(concat " " denote-faces--file-name-regexp)
+     (1 'denote-faces-date)
+     (2 'denote-faces-time)
+     (3 'denote-faces-delimiter nil t)
+     (4 'denote-faces-title nil t)
+     (5 'denote-faces-delimiter nil t)
+     (6 'denote-faces-keywords nil t)
+     (7 'denote-faces-extension nil t )))
+  "Keywords for fontification of file names.")
+
+(defconst denote-faces-file-name-keywords-for-backlinks
+  `((,(concat "^\\(?8:.*/\\)?" denote-faces--file-name-regexp)
+     (8 'denote-faces-subdirectory nil t)
+     (1 'denote-faces-date)
+     (2 'denote-faces-time)
+     (3 'denote-faces-delimiter nil t)
+     (4 'denote-faces-title nil t)
+     (5 'denote-faces-delimiter nil t)
+     (6 'denote-faces-keywords nil t)
+     (7 'denote-faces-extension nil t )))
+  "Keywords for fontification of file names in the backlinks buffer.")
+
+;;;; Fontification in Dired
+
+(defgroup denote-dired ()
+  "Integration between Denote and Dired."
+  :group 'denote)
+
+(defcustom denote-dired-directories
+  ;; We use different ways to specify a path for demo purposes.
+  (list denote-directory
+        ;; (thread-last denote-directory (expand-file-name "attachments"))
+        (expand-file-name "~/Documents/vlog"))
+  "List of directories where `denote-dired-mode' should apply to."
+  :type '(repeat directory)
+  :group 'denote-dired)
+
+;;;###autoload
+(define-minor-mode denote-dired-mode
+  "Fontify all Denote-style file names in Dired."
+  :global nil
+  :group 'denote-dired
+  (if denote-dired-mode
+      (font-lock-add-keywords nil denote-faces-file-name-keywords t)
+    (font-lock-remove-keywords nil denote-faces-file-name-keywords))
+  (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'."
+  (when (member (file-truename default-directory) 
(denote-dired--modes-dirs-as-dirs))
+    (denote-dired-mode 1)))
+
+;;;; The linking facility
+
+(defgroup denote-link ()
+  "Link facility for Denote."
+  :group 'denote)
+
+;;;;; User options
+
+(defcustom denote-link-fontify-backlinks t
+  "When non-nil, apply faces to files in the backlinks' buffer."
+  :type 'boolean
+  :group 'denote-link)
+
+(defcustom denote-link-backlinks-display-buffer-action
+  '((display-buffer-reuse-window display-buffer-below-selected)
+    (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-link-backlinks-display-buffer-action
+          (quote ((display-buffer-reuse-window
+                   display-buffer-in-side-window)
+                  (side . left)
+                  (slot . 99)
+                  (window-width . 0.3))))
+
+See Info node `(elisp) Displaying Buffers' for more details
+and/or the documentation string of `display-buffer'."
+  :type '(cons (choice (function :tag "Display Function")
+                       (repeat :tag "Display Functions" function))
+               alist)
+  :group 'denote-link)
+
+;;;;; Link to note
+
+;; Arguments are: FILE-ID FILE-TITLE
+(defconst denote-link--format-org "[[denote:%s][%s]]"
+  "Format of Org link to note.")
+
+(defconst denote-link--format-markdown "[%2$s](denote:%1$s)"
+  "Format of Markdown link to note.")
+
+(defconst denote-link--format-id-only "[[denote:%s]]"
+  "Format of identifier-only link to note.")
+
+(defconst denote-link--regexp-org
+  (concat "\\[\\[" "denote:"  "\\(?1:" denote--id-regexp "\\)" "]" "\\[.*?]]"))
+
+(defconst denote-link--regexp-markdown
+  (concat "\\[.*?]" "(denote:"  "\\(?1:" denote--id-regexp "\\)" ")"))
+
+(defconst denote-link--regexp-plain
+  (concat "\\[\\[" "denote:"  "\\(?1:" denote--id-regexp "\\)" "]]"))
+
+(defun denote-link--file-type-format (current-file id-only)
+  "Return link format based on CURRENT-FILE format.
+With non-nil ID-ONLY, use the generic link format without a
+title."
+  ;; Includes backup files.  Maybe we can remove them?
+  (let ((current-file-ext (file-name-extension current-file)))
+    (cond
+     (id-only denote-link--format-id-only)
+     ((string= current-file-ext "md")
+      denote-link--format-markdown)
+     ;; Plain text also uses [[denote:ID][TITLE]]
+     (t denote-link--format-org))))
+
+(defun denote-link--file-type-regexp (file)
+  "Return link regexp based on FILE format."
+  (pcase (file-name-extension file)
+    ("md" denote-link--regexp-markdown)
+    (_ denote-link--regexp-org)))
+
+(defun denote-link--format-link (file pattern)
+  "Prepare link to FILE using PATTERN."
+  (let ((file-id (denote--retrieve-filename-identifier file))
+        (file-title (unless (string= pattern denote-link--format-id-only)
+                      (denote--retrieve-value-title file))))
+    (format pattern file-id file-title)))
+
+;;;###autoload
+(defun denote-link (target &optional id-only)
+  "Create link to TARGET note in variable `denote-directory'.
+With optional ID-ONLY, such as a universal prefix
+argument (\\[universal-argument]), insert links with just the
+identifier and no further description.  In this case, the link
+format is always [[denote:IDENTIFIER]]."
+  (interactive (list (denote--retrieve-read-file-prompt) current-prefix-arg))
+  (let ((beg (point)))
+    (insert
+     (denote-link--format-link
+      target
+      (denote-link--file-type-format (buffer-file-name) id-only)))
+    (unless (derived-mode-p 'org-mode)
+      (make-button beg (point) 'type 'denote-link-button))))
+
+(defalias 'denote-link-insert-link (symbol-function 'denote-link))
+
+(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-link--regexp-plain 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-prefix-p i (file-name-nondirectory file))
+          (push file found-files))))
+    found-files))
+
+(defvar denote-link--find-file-history nil
+  "History for `denote-link-find-file'.")
+
+(defun denote-link--find-file-prompt (files)
+  "Prompt for linked file among FILES."
+  (completing-read "Find linked file "
+                   (denote--completion-table 'file files)
+                   nil t
+                   nil 'denote-link--find-file-history))
+
+;; TODO 2022-06-14: Do we need to add any sort of extension to better
+;; integrate with Embark?  For the minibuffer interaction it is not
+;; necessary, but maybe it can be done to immediately recognise the
+;; identifiers are links to files?
+
+;;;###autoload
+(defun denote-link-find-file ()
+  "Use minibuffer completion to visit linked file."
+  (interactive)
+  (if-let* ((regexp (denote-link--file-type-regexp (buffer-file-name)))
+            (files (denote-link--expand-identifiers regexp)))
+      (find-file (denote-link--find-file-prompt files))
+    (user-error "No links found in the current buffer")))
+
+;;;;; Link buttons
+
+;; Evaluate: (info "(elisp) Button Properties")
+;;
+;; Button can provide a help-echo function as well, but I think we might
+;; not need it.
+(define-button-type 'denote-link-button
+  'follow-link t
+  'action #'denote-link--find-file-at-button)
+
+(autoload 'thing-at-point-looking-at "thingatpt")
+
+(defun denote-link--link-at-point-string ()
+  "Return identifier at point."
+  (when (or (thing-at-point-looking-at denote-link--regexp-plain)
+            (thing-at-point-looking-at denote-link--regexp-markdown)
+            (thing-at-point-looking-at denote-link--regexp-org)
+            ;; Meant to handle the case where a link is broken by
+            ;; `fill-paragraph' into two lines, in which case it
+            ;; buttonizes only the "denote:ID" part.  Example:
+            ;;
+            ;; [[denote:20220619T175212][This is a
+            ;; test]]
+            ;;
+            ;; Maybe there is a better way?
+            (thing-at-point-looking-at "\\[\\(denote:.*\\)]"))
+    (match-string-no-properties 0)))
+
+(defun denote-link--id-from-string (string)
+  "Extract identifier from STRING."
+  (replace-regexp-in-string
+   (concat ".*denote:" "\\(" denote--id-regexp "\\)" ".*")
+   "\\1" string))
+
+;; NOTE 2022-06-15: I add this as a variable for advanced users who may
+;; prefer something else.  If there is demand for it, we can make it a
+;; defcustom, but I think it would be premature at this stage.
+(defvar denote-link-buton-action #'find-file-other-window
+  "Action for Denote buttons.")
+
+(defun denote-link--find-file-at-button (button)
+  "Visit file referenced by BUTTON."
+  (let* ((id (denote-link--id-from-string
+              (buffer-substring-no-properties
+               (button-start button)
+               (button-end button))))
+         (file (denote--get-note-path-by-id id)))
+    (funcall denote-link-buton-action file)))
+
+;;;###autoload
+(defun denote-link-buttonize-buffer (&optional beg end)
+  "Make denote: links actionable buttons in the current buffer.
+
+Add this to `find-file-hook'.  It will only work with Denote
+notes and will not do anything in `org-mode' buffers, as buttons
+already work there.  If you do not use Markdown or plain text,
+then you do not need this.
+
+When called from Lisp, with optional BEG and END as buffer
+positions, limit the process to the region in-between."
+  (interactive)
+  (when (and (not (derived-mode-p 'org-mode)) (denote--current-file-is-note-p))
+    (save-excursion
+      (goto-char (or beg (point-min)))
+      (while (re-search-forward denote--id-regexp end t)
+        (when-let ((string (denote-link--link-at-point-string))
+                   (beg (match-beginning 0))
+                   (end (match-end 0)))
+          (make-button beg end 'type 'denote-link-button))))))
+
+;;;;; Backlinks' buffer
+
+(define-button-type 'denote-link-backlink-button
+  'follow-link t
+  'action #'denote-link--backlink-find-file
+  'face nil)            ; we use this face though we style it later
+
+(defun denote-link--backlink-find-file (button)
+  "Action for BUTTON to `find-file'."
+  (funcall denote-link-buton-action (buffer-substring (button-start button) 
(button-end button))))
+
+(defun denote-link--display-buffer (buf)
+  "Run `display-buffer' on BUF.
+Expand `denote-link-backlinks-display-buffer-action'."
+  (display-buffer
+   buf
+   `(,@denote-link-backlinks-display-buffer-action)))
+
+(defun denote-link--prepare-backlinks (id files &optional title)
+  "Create backlinks' buffer for ID including FILES.
+Use optional TITLE for a prettier heading."
+  (let ((inhibit-read-only t)
+        (buf (format "*denote-backlinks to %s*" id)))
+    (with-current-buffer (get-buffer-create buf)
+      (erase-buffer)
+      (special-mode)
+      (goto-char (point-min))
+      (when-let* ((title)
+                  (heading (format "Backlinks to %S (%s)" title id))
+                  (l (length heading)))
+        (insert (format "%s\n%s\n\n" heading (make-string l ?-))))
+      (mapc (lambda (f)
+              (insert f)
+              (make-button (point-at-bol) (point-at-eol) :type 
'denote-link-backlink-button)
+              (newline))
+            files)
+      (goto-char (point-min))
+      (when denote-link-fontify-backlinks
+        (font-lock-add-keywords nil 
denote-faces-file-name-keywords-for-backlinks t)))
+    (denote-link--display-buffer buf)))
+
+;;;###autoload
+(defun denote-link-backlinks ()
+  "Produce a buffer with files linking to current note.
+Each file is a clickable/actionable button that visits the
+referenced entry.  Files are fontified if the user option
+`denote-link-fontify-backlinks' is non-nil.
+
+The placement of the backlinks' buffer is controlled by the user
+option `denote-link-backlinks-display-buffer-action'.  By
+default, it will show up below the current window."
+  (interactive)
+  (let* ((default-directory (denote-directory))
+         (file (buffer-file-name))
+         (id (denote--retrieve-filename-identifier file))
+         (title (denote--retrieve-value-title file)))
+    (if-let ((files (denote--retrieve-proces-grep id)))
+        (denote-link--prepare-backlinks id files title)
+      (user-error "No links to the current note"))))
+
+(defalias 'denote-link-show-backlinks-buffer (symbol-function 
'denote-link-backlinks))
+
+;;;;; Add links matching regexp
+
+(defvar denote-link--links-to-files nil
+  "String of `denote-link-add-links-matching-keyword'.")
+
+(defvar denote-link--prepare-links-format "- %s\n"
+  "Format specifiers for `denote-link-add-links'.")
+
+;; NOTE 2022-06-16: There is no need to overwhelm the user with options,
+;; though I expect someone to want to change the sort order.
+(defvar denote-link-add-links-sort nil
+  "Add REVERSE to `sort-lines' of `denote-link-add-links' when t.")
+
+(defun denote-link--prepare-links (files current-file id-only)
+  "Prepare links to FILES from CURRENT-FILE.
+When ID-ONLY is non-nil, use a generic link format.  See
+`denote-link--file-type-format'."
+  (setq denote-link--links-to-files
+        (with-temp-buffer
+          (mapc (lambda (file)
+                  (insert
+                   (format
+                    denote-link--prepare-links-format
+                    (denote-link--format-link
+                     file
+                     (denote-link--file-type-format current-file id-only)))))
+                files)
+          (sort-lines denote-link-add-links-sort (point-min) (point-max))
+          (buffer-string))))
+
+(defvar denote-link--add-links-history nil
+  "Minibuffer history for `denote-link-add-links'.")
+
+;;;###autoload
+(defun denote-link-add-links (regexp &optional id-only)
+  "Insert links to all notes matching 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
+    (read-regexp "Insert links matching REGEX: " nil 
'denote-link--add-links-history)
+    current-prefix-arg))
+  (let* ((default-directory (denote-directory))
+         (current-file (buffer-file-name)))
+    (if-let ((files (denote--directory-files-matching-regexp regexp)))
+        (let ((beg (point)))
+          (insert (denote-link--prepare-links files current-file id-only))
+          (unless (derived-mode-p 'org-mode)
+            (denote-link-buttonize-buffer beg (point))))
+      (user-error "No links matching `%s'" regexp))))
+
+(defalias 'denote-link-insert-links-matching-regexp (symbol-function 
'denote-link-add-links))
+
+;;;;; Links from Dired marks
+
+;; NOTE 2022-07-21: I don't think we need a history for this one.
+(defun denote-link--buffer-prompt (buffers)
+  "Select buffer from BUFFERS visiting Denote notes."
+  (completing-read
+   "Select note buffer: "
+   (denote--completion-table 'buffer buffers)
+   nil t))
+
+(declare-function dired-get-marked-files "dired" (&optional localp arg filter 
distinguish-one-marked error))
+
+(defun denote-link--map-over-notes ()
+  "Return list of `denote--only-note-p' from Dired marked items."
+  (delq nil
+        (mapcar
+            (lambda (f)
+           (when (and (denote--only-note-p f)
+                      (denote--dir-in-denote-directory-p default-directory))
+             f))
+         (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 are Denote notes, meaning that they have our file-naming
+scheme, are writable/regular files, and use the appropriate file
+type extension (per `denote-file-type').  Furthermore, the marked
+files need to be inside the variable `denote-directory' or one of
+its subdirectories.  No other file is recognised (the list of
+marked files ignores whatever does not count as a note for our
+purposes).
+
+The BUFFER is one which visits a Denote note file.  If there are
+multiple buffers, prompt with completion for one among them.  If
+there isn't one, 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
+   (list
+    (denote-link--map-over-notes)
+    (let ((buffers (denote--buffer-file-names)))
+      (get-buffer
+       (cond
+        ((null buffers)
+         (user-error "No buffers visiting Denote notes"))
+        ((eq (length buffers) 1)
+         (car buffers))
+        (t
+         (denote-link--buffer-prompt buffers)))))
+    current-prefix-arg)
+   dired-mode)
+  (if (null files)
+      (user-error "No note files to link to")
+    (when (y-or-n-p (format "Create links at point in %s?" buffer))
+      (with-current-buffer buffer
+        (insert (denote-link--prepare-links files (buffer-file-name) id-only))
+        (denote-link-buttonize-buffer)))))
+
+;;;;; 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 path-id)
+  "Resolve LINK into the appropriate target.
+With optional PATH-ID return a cons cell consisting of the path
+and the identifier."
+  (let* ((search (and (string-match "::\\(.*\\)\\'" link)
+                      (match-string 1 link)))
+         (id (if (and (stringp search) (not (string-empty-p search)))
+                 (substring link 0 (match-beginning 0))
+               link))
+         (path (denote--get-note-path-by-id id)))
+    (cond
+     (path-id
+      (cons (format "%s" path) (format "%s" id)))
+     ((and (stringp search) (not (string-empty-p search)))
+      (concat path "::" search))
+     (path))))
+
+(defun denote-link-ol-follow (link)
+  "Find file of type `denote:' matching LINK.
+LINK is the identifier of the note, optionally followed by a
+search option akin to that of standard Org `file:' link types.
+Read Info node `(org) Search Options'.
+
+Uses the function `denote-directory' to establish the path to the
+file."
+  (org-link-open-as-file
+   (denote-link--ol-resolve-link-to-target link)
+   nil))
+
+(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."
+  (concat
+   "denote:"
+   (denote--retrieve-filename-identifier (denote--retrieve-read-file-prompt))))
+
+(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."
+  (let* ((path-id (denote-link--ol-resolve-link-to-target link :path-id))
+         (path (file-name-nondirectory (car path-id)))
+         (p (file-name-sans-extension path))
+         (id (cdr path-id))
+         (desc (or description (concat "denote:" id))))
+    (cond
+     ((eq format 'html) (format "<a target=\"_blank\" href=\"%s.html\">%s</a>" 
p desc))
+     ((eq format 'latex) (format "\\href{%s}{%s}" (replace-regexp-in-string 
"[\\{}$%&_#~^]" "\\\\\\&" path) desc))
+     ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
+     ((eq format 'ascii) (format "[%s] <denote:%s>" desc path)) ; NOTE 
2022-06-16: May be tweaked further
+     ((eq format 'md) (format "[%s](%s.md)" desc p))
+     (t 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
+           :complete #'denote-link-ol-complete
+           :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
+  :group 'denote-org-capture)
+
+;;;###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.
+
+Note that this function 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' (which can include
+arbitrary text).
+
+Consult the manual for template samples."
+  (let ((title (denote--title-prompt))
+        (keywords (denote--keywords-prompt))
+        (denote-file-type nil)) ; we enforce the .org extension for 
`org-capture'
+    (denote--path title keywords)
+    (setq denote-last-front-matter (denote--file-meta-header
+                                    title (denote--date nil) keywords
+                                    (format-time-string denote--id-format 
nil)))
+    (denote--keywords-add-to-history denote-last-keywords)
+    (concat denote-last-front-matter denote-org-capture-specifiers)))
+
+(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)
+
 (provide 'denote)
 ;;; denote.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]