[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
- [elpa] externals/denote updated (b88eaf36a4 -> 95ee2d4f38), ELPA Syncer, 2022/07/31
- [elpa] externals/denote 7a8143a7c3 01/10: Rename denote-dired--rename-file to denote-dired--rename-file-prompt, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 4ce8c6701c 03/10: Fix denote--rename-file, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 3453f409a3 05/10: Rename internal functions, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 8989d98d2c 08/10: Remove 'require' for dired in denote-dired.el, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 35e2d93bfa 04/10: Move renaming commands from denote-dired.el to denote.el, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 9246831598 06/10: Merge pull request #67 from jeanphilippegg/reorganization, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 95ee2d4f38 10/10: Put require call at the top, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 1a1f3fb7cf 02/10: Use denote--rename-file in renaming functions, ELPA Syncer, 2022/07/31
- [elpa] externals/denote b78834c8fa 07/10: Remove obsoletion warnings from older versions, ELPA Syncer, 2022/07/31
- [elpa] externals/denote 79f5b62aa6 09/10: Merge all ancillary files into denote.el,
ELPA Syncer <=