2022-06-07 16:21:49 +02:00
|
|
|
;;; denote-dired.el --- Integration between Denote and Dired -*- lexical-binding: t -*-
|
2022-06-07 09:39:46 +02:00
|
|
|
|
2022-06-10 15:01:46 +02:00
|
|
|
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
2022-06-07 09:39:46 +02:00
|
|
|
|
|
|
|
;; Author: Protesilaos Stavrou <info@protesilaos.com>
|
|
|
|
;; URL: https://git.sr.ht/~protesilaos/denote
|
2022-06-23 07:35:41 +02:00
|
|
|
;; Mailing list: https://lists.sr.ht/~protesilaos/denote
|
2022-06-07 09:39:46 +02:00
|
|
|
;; Version: 0.1.0
|
2022-06-16 04:42:43 +02:00
|
|
|
;; Package-Requires: ((emacs "27.2"))
|
2022-06-07 09:39:46 +02:00
|
|
|
|
|
|
|
;; 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:
|
|
|
|
;;
|
2022-06-16 11:47:52 +02:00
|
|
|
;; 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 (read manual's "The
|
|
|
|
;; file-naming scheme"). While Denote does not manage such files, it
|
|
|
|
;; already has all the mechanisms to facilitate the task of renaming
|
|
|
|
;; them.
|
|
|
|
;;
|
|
|
|
;; To this end, we provide the `denote-dired-rename-file' command. It
|
|
|
|
;; has a two-fold purpose: (i) to change the name of an existing file
|
|
|
|
;; while retaining its identifier and (ii) to write a Denote-compliant
|
|
|
|
;; file name for an item that was not created by `denote' or related
|
|
|
|
;; commands (such as an image or PDF).
|
|
|
|
;;
|
|
|
|
;; The `denote-dired-rename-file' command will target the file at point
|
|
|
|
;; if it finds one in the current Dired buffer. Otherwise it prompts
|
|
|
|
;; with minibuffer completion for a file name. It then uses the
|
|
|
|
;; familiar prompts for a `TITLE' and `KEYWORDS' the same way the
|
|
|
|
;; `denote' command does (read manual's "Points of entry). As a final
|
|
|
|
;; step, it asks for confirmation before renaming the file at point,
|
|
|
|
;; showing a message like:
|
|
|
|
;;
|
|
|
|
;; 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,
|
|
|
|
;; conduct the renaming operation outright---no questions asked.
|
|
|
|
;;
|
|
|
|
;; When operating on a file that has no identifier, such as
|
|
|
|
;; `sample.pdf', Denote reads the file properties to retrieve its last
|
|
|
|
;; modification time. If the file was from a past date like 2000-11-31
|
|
|
|
;; it will get an identifier starting with `20001131' followed by the
|
|
|
|
;; time component (per our file-naming scheme).
|
|
|
|
;;
|
|
|
|
;; 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.
|
|
|
|
;;
|
|
|
|
;; The final step of the `denote-dired-rename-file' command is to call
|
|
|
|
;; the special hook `denote-dired-post-rename-functions'. Functions
|
|
|
|
;; added to that hook must accept three arguments, as explained in its
|
|
|
|
;; doc string. For the time being, the only function we define is the
|
|
|
|
;; one which updates the underlying note's front matter to match the new
|
|
|
|
;; file name: `denote-dired-rewrite-front-matter'. The function takes
|
|
|
|
;; care to only operate on an actual note, instead of arbitrary files.
|
|
|
|
;;
|
|
|
|
;; DEVELOPMENT NOTE: the `denote-dired-rewrite-front-matter' needs to be
|
|
|
|
;; tested thoroughly. It rewrites file contents so we have to be sure
|
|
|
|
;; it does the right thing. To avoid any trouble, it always asks for
|
|
|
|
;; confirmation before performing the replacement. This confirmation
|
|
|
|
;; ignores `denote-dired-rename-expert' for the time being, though we
|
|
|
|
;; might want to lift that restriction once everything works as
|
|
|
|
;; intended.
|
|
|
|
;;
|
|
|
|
;;
|
2022-06-08 11:02:33 +02:00
|
|
|
;; 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.
|
2022-06-07 09:39:46 +02:00
|
|
|
;;
|
2022-06-08 11:02:33 +02:00
|
|
|
;; There are two ways to set the mode. Either use it for all directories,
|
|
|
|
;; which probably is not needed:
|
2022-06-07 09:39:46 +02:00
|
|
|
;;
|
2022-06-08 11:02:33 +02:00
|
|
|
;; (require 'denote-dired)
|
2022-06-07 09:39:46 +02:00
|
|
|
;; (add-hook 'dired-mode-hook #'denote-dired-mode)
|
2022-06-08 11:02:33 +02:00
|
|
|
;;
|
|
|
|
;; 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.
|
2022-06-07 09:39:46 +02:00
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
2022-06-16 07:58:25 +02:00
|
|
|
(require 'denote-retrieve)
|
2022-06-08 09:47:18 +02:00
|
|
|
(require 'dired)
|
2022-06-07 09:39:46 +02:00
|
|
|
|
|
|
|
(defgroup denote-dired ()
|
2022-06-07 16:21:49 +02:00
|
|
|
"Integration between Denote and Dired."
|
|
|
|
:group 'denote)
|
2022-06-07 09:39:46 +02:00
|
|
|
|
2022-06-08 10:50:35 +02:00
|
|
|
(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)
|
|
|
|
|
2022-06-12 16:16:31 +02:00
|
|
|
(defcustom denote-dired-rename-expert nil
|
|
|
|
"If t, `denote-dired-rename-file' doesn't ask for confirmation.
|
|
|
|
The confiration is asked via a `y-or-n-p' prompt which shows the
|
|
|
|
old name followed by the new one."
|
|
|
|
:type 'boolean
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-16 07:58:25 +02:00
|
|
|
(defcustom denote-dired-post-rename-functions
|
2022-06-17 16:52:08 +02:00
|
|
|
(list #'denote-dired-update-dired-buffers
|
|
|
|
#'denote-dired-rewrite-front-matter)
|
2022-06-16 07:58:25 +02:00
|
|
|
"List of functions called after `denote-dired-rename-file'.
|
2022-06-16 11:23:35 +02:00
|
|
|
Each function must accept three arguments: FILE, TITLE, and
|
2022-06-16 07:58:25 +02:00
|
|
|
KEYWORDS. The first is the full path to the file provided as a
|
|
|
|
string, the second is the human-readable file name (not what
|
|
|
|
Denote sluggifies) also as a string, and the third are the
|
|
|
|
keywords. If there is only one keyword, it is a string, else a
|
|
|
|
list of strings.
|
|
|
|
|
|
|
|
DEVELOPMENT NOTE: the `denote-dired-rewrite-front-matter' needs
|
|
|
|
to be tested thoroughly. It rewrites file contents so we have to
|
|
|
|
be sure it does the right thing. To avoid any trouble, it always
|
|
|
|
asks for confirmation before performing the replacement. This
|
|
|
|
confirmation ignores `denote-dired-rename-expert' for the time
|
|
|
|
being, though we might want to lift that restriction once
|
|
|
|
everything works as intended."
|
|
|
|
:type 'hook
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-16 08:01:12 +02:00
|
|
|
;;;; Commands
|
|
|
|
|
|
|
|
(defun denote-dired--file-attributes-time (file)
|
|
|
|
"Return `file-attribute-modification-time' of FILE as identifier."
|
|
|
|
(format-time-string
|
|
|
|
denote--id-format
|
|
|
|
(file-attribute-modification-time (file-attributes file))))
|
|
|
|
|
|
|
|
(defun denote-dired--file-name-id (file)
|
|
|
|
"Return FILE identifier, else generate one."
|
|
|
|
(cond
|
|
|
|
((string-match denote--id-regexp file)
|
|
|
|
(substring file (match-beginning 0) (match-end 0)))
|
|
|
|
((denote-dired--file-attributes-time file))
|
|
|
|
(t (format-time-string denote--id-format))))
|
|
|
|
|
2022-06-17 16:55:32 +02:00
|
|
|
(defun denote-dired--rename-buffer (old-name new-name)
|
|
|
|
"Rename OLD-NAME buffer to NEW-NAME, when appropriate."
|
2022-06-20 17:12:10 +02:00
|
|
|
(when-let* ((buffer (find-buffer-visiting old-name)))
|
|
|
|
(with-current-buffer buffer
|
|
|
|
(set-visited-file-name new-name nil t))))
|
2022-06-17 16:55:32 +02:00
|
|
|
|
2022-06-17 20:19:21 +02:00
|
|
|
(defun denote-dired--rename-dired-file-or-prompt ()
|
|
|
|
"Return Dired file at point, else prompt for one."
|
|
|
|
(or (dired-get-filename nil t)
|
|
|
|
(let* ((file (buffer-file-name))
|
|
|
|
(format (if file
|
|
|
|
(format "Rename file Denote-style [%s]: " file)
|
|
|
|
"Rename file Denote-style: ")))
|
|
|
|
(read-file-name format nil file t nil))))
|
|
|
|
|
|
|
|
(defun denote-dired--rename-file-is-regular (file)
|
|
|
|
"Throw error is FILE is not regular, else return FILE."
|
|
|
|
(if (or (file-directory-p file)
|
|
|
|
(not (file-regular-p file)))
|
|
|
|
(user-error "Only rename regular files")
|
|
|
|
file))
|
|
|
|
|
2022-06-08 09:47:18 +02:00
|
|
|
;;;###autoload
|
2022-06-12 04:34:33 +02:00
|
|
|
(defun denote-dired-rename-file (file title keywords)
|
|
|
|
"Rename FILE to include TITLE and KEYWORDS.
|
|
|
|
|
2022-06-12 16:16:31 +02:00
|
|
|
If in Dired, consider FILE to be the one at point, else prompt
|
|
|
|
with completion.
|
|
|
|
|
|
|
|
If FILE has a Denote-compliant identifier, retain it while
|
|
|
|
updating the TITLE and KEYWORDS fields of the file name. Else
|
|
|
|
create 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 time.
|
|
|
|
|
|
|
|
As a final step, prompt for confirmation, showing the difference
|
|
|
|
between old and new file names. If `denote-dired-rename-expert'
|
|
|
|
is non-nil, conduct the renaming operation outright---no
|
|
|
|
questions asked!
|
2022-06-12 04:34:33 +02:00
|
|
|
|
|
|
|
The file type extension (e.g. .pdf) is read from the underlying
|
2022-06-12 16:16:31 +02:00
|
|
|
file and is preserved through the renaming process. Files that
|
|
|
|
have no extension are simply left without one.
|
2022-06-12 04:34:33 +02:00
|
|
|
|
|
|
|
Renaming only occurs relative to the current directory. Files
|
2022-06-16 11:23:35 +02:00
|
|
|
are not moved between directories. As a final step, call the
|
|
|
|
`denote-dired-post-rename-functions'.
|
2022-06-12 04:34:33 +02:00
|
|
|
|
|
|
|
This command is intended to (i) rename existing Denote
|
|
|
|
notes, (ii) complement note-taking, such as by renaming
|
|
|
|
attachments that the user adds to their notes."
|
2022-06-08 09:47:18 +02:00
|
|
|
(interactive
|
|
|
|
(list
|
2022-06-17 20:19:21 +02:00
|
|
|
(denote-dired--rename-file-is-regular (denote-dired--rename-dired-file-or-prompt))
|
2022-06-08 09:47:18 +02:00
|
|
|
(denote--title-prompt)
|
|
|
|
(denote--keywords-prompt)))
|
2022-06-12 04:34:33 +02:00
|
|
|
(let* ((dir (file-name-directory file))
|
2022-06-08 09:47:18 +02:00
|
|
|
(old-name (file-name-nondirectory file))
|
|
|
|
(extension (file-name-extension file t))
|
|
|
|
(new-name (denote--format-file
|
|
|
|
dir
|
2022-06-12 04:34:33 +02:00
|
|
|
(denote-dired--file-name-id file)
|
2022-06-08 09:47:18 +02:00
|
|
|
keywords
|
|
|
|
(denote--sluggify title)
|
2022-06-17 10:26:32 +02:00
|
|
|
extension))
|
2022-06-24 05:29:52 +02:00
|
|
|
(max-mini-window-height 0.33)) ; allow minibuffer to be resized
|
2022-06-16 07:58:25 +02:00
|
|
|
(unless (string= old-name (file-name-nondirectory new-name))
|
|
|
|
(when (y-or-n-p
|
|
|
|
(format "Rename %s to %s?"
|
|
|
|
(propertize old-name 'face 'error)
|
|
|
|
(propertize (file-name-nondirectory new-name) 'face 'success)))
|
|
|
|
(rename-file old-name new-name nil)
|
2022-06-17 16:55:32 +02:00
|
|
|
(denote-dired--rename-buffer old-name new-name)
|
2022-06-16 07:58:25 +02:00
|
|
|
(run-hook-with-args 'denote-dired-post-rename-functions new-name title keywords)))))
|
|
|
|
|
2022-06-17 16:52:08 +02:00
|
|
|
(defun denote-dired-update-dired-buffers (&rest _)
|
|
|
|
"Update Dired buffers of variable `denote-directory'.
|
|
|
|
Can run after `denote-dired-post-rename-functions', though it
|
|
|
|
ignores all its arguments."
|
|
|
|
(mapc
|
|
|
|
(lambda (buf)
|
|
|
|
(with-current-buffer buf
|
|
|
|
(when (and (eq major-mode 'dired-mode)
|
2022-06-21 12:22:38 +02:00
|
|
|
(string-match-p (expand-file-name default-directory)
|
|
|
|
(expand-file-name (denote-directory))))
|
2022-06-17 16:52:08 +02:00
|
|
|
(revert-buffer))))
|
|
|
|
(buffer-list)))
|
|
|
|
|
2022-06-16 07:58:25 +02:00
|
|
|
(defun denote-dired--file-meta-header (title date keywords id filetype)
|
|
|
|
"Front matter for renamed notes.
|
|
|
|
|
|
|
|
TITLE, DATE, KEYWORDS, FILENAME, ID, and FILETYPE are all strings
|
|
|
|
which are provided by `denote-dired-rewrite-front-matter'."
|
|
|
|
(let ((kw-space (denote--file-meta-keywords keywords))
|
|
|
|
(kw-toml (denote--file-meta-keywords keywords 'toml)))
|
|
|
|
(pcase filetype
|
|
|
|
('markdown-toml (format denote-toml-front-matter title date kw-toml id))
|
|
|
|
('markdown-yaml (format denote-yaml-front-matter title date kw-space id))
|
|
|
|
('text (format denote-text-front-matter title date kw-space id denote-text-front-matter-delimiter))
|
|
|
|
(_ (format denote-org-front-matter title date kw-space id)))))
|
|
|
|
|
|
|
|
(defun denote-dired--filetype-heuristics (file)
|
|
|
|
"Return likely file type of FILE.
|
|
|
|
The return value is for `denote--file-meta-header'."
|
|
|
|
(pcase (file-name-extension file)
|
|
|
|
("md" (if (string-match-p "title\\s-*=" (denote-retrieve--value-title file 0))
|
|
|
|
'markdown-toml
|
|
|
|
'markdown-yaml))
|
|
|
|
("txt" 'text)
|
|
|
|
(_ 'org)))
|
|
|
|
|
|
|
|
(defun denote-dired--front-matter-search-delimiter (filetype)
|
|
|
|
"Return likely front matter delimiter search for FILETYPE."
|
|
|
|
(pcase filetype
|
|
|
|
('markdown-toml (re-search-forward "^\\+\\+\\+$" nil t 2))
|
|
|
|
('markdown-yaml (re-search-forward "^---$" nil t 2))
|
|
|
|
;; 2 at most, as the user might prepend it to the block as well.
|
|
|
|
;; Though this might give us false positives, it ultimately is the
|
|
|
|
;; user's fault.
|
|
|
|
('text (or (re-search-forward denote-text-front-matter-delimiter nil t 2)
|
|
|
|
(re-search-forward denote-text-front-matter-delimiter nil t 1)
|
|
|
|
(re-search-forward "^[\s\t]*$" nil t 1)))
|
|
|
|
;; Org does not have a real delimiter. This is the trickiest one.
|
|
|
|
(_ (re-search-forward "^[\s\t]*$" nil t 1))))
|
|
|
|
|
2022-06-16 08:59:30 +02:00
|
|
|
(defun denote-dired--edit-front-matter-p (file)
|
2022-06-17 16:59:50 +02:00
|
|
|
"Test if FILE should be subject to front matter rewrite.
|
|
|
|
This is relevant for `denote-dired-rewrite-front-matter': if FILE
|
|
|
|
has no front matter, then we abort early instead of trying to
|
|
|
|
replace what isn't there."
|
2022-06-16 08:59:30 +02:00
|
|
|
(when-let ((ext (file-name-extension file)))
|
|
|
|
(and (file-regular-p file)
|
|
|
|
(file-writable-p file)
|
|
|
|
(not (denote--file-empty-p file))
|
|
|
|
(string-match-p "\\(md\\|org\\|txt\\)\\'" ext)
|
|
|
|
;; Heuristic to check if this is one of our notes
|
2022-06-17 16:58:26 +02:00
|
|
|
(string= (expand-file-name default-directory) (denote-directory)))))
|
2022-06-16 08:59:30 +02:00
|
|
|
|
2022-06-16 07:58:25 +02:00
|
|
|
(defun denote-dired-rewrite-front-matter (file title keywords)
|
|
|
|
"Rewrite front matter of note after `denote-dired-rename-file'.
|
|
|
|
The FILE, TITLE, and KEYWORDS are passed from the renaming
|
2022-06-17 17:02:03 +02:00
|
|
|
command and are used to construct a new front matter block if
|
|
|
|
appropriate."
|
2022-06-17 17:02:46 +02:00
|
|
|
(when-let* ((denote-dired--edit-front-matter-p file)
|
|
|
|
(id (denote-retrieve--filename-identifier file))
|
|
|
|
(date (denote-retrieve--value-date file))
|
|
|
|
(filetype (denote-dired--filetype-heuristics file))
|
|
|
|
(new-front-matter (denote--file-meta-header title date keywords id filetype)))
|
|
|
|
(let (old-front-matter front-matter-delimiter)
|
|
|
|
(with-current-buffer (find-file-noselect file)
|
|
|
|
(save-excursion
|
|
|
|
(save-restriction
|
|
|
|
(widen)
|
2022-06-16 08:59:30 +02:00
|
|
|
(goto-char (point-min))
|
2022-06-17 17:02:46 +02:00
|
|
|
(setq front-matter-delimiter (denote-dired--front-matter-search-delimiter filetype))
|
|
|
|
(when front-matter-delimiter
|
|
|
|
(setq old-front-matter
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(point-min)
|
|
|
|
(progn front-matter-delimiter (point)))))))
|
|
|
|
(when (and old-front-matter
|
|
|
|
(y-or-n-p
|
|
|
|
(format "%s\n%s\nReplace front matter?"
|
|
|
|
(propertize old-front-matter 'face 'error)
|
|
|
|
(propertize new-front-matter 'face 'success))))
|
|
|
|
(delete-region (point-min) front-matter-delimiter)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(insert new-front-matter)
|
|
|
|
;; FIXME 2022-06-16: Instead of `delete-blank-lines', we
|
|
|
|
;; should check if we added any new lines and delete only
|
|
|
|
;; those.
|
|
|
|
(delete-blank-lines))))))
|
2022-06-08 09:47:18 +02:00
|
|
|
|
|
|
|
;;;; Extra fontification
|
|
|
|
|
2022-06-11 18:28:10 +02:00
|
|
|
(defface denote-dired-field-date
|
2022-06-07 09:39:46 +02:00
|
|
|
'((((class color) (min-colors 88) (background light))
|
|
|
|
:foreground "#00538b")
|
|
|
|
(((class color) (min-colors 88) (background dark))
|
|
|
|
:foreground "#00d3d0")
|
|
|
|
(t :inherit font-lock-variable-name-face))
|
|
|
|
"Face for file name date in `dired-mode' buffers."
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-11 18:28:10 +02:00
|
|
|
(defface denote-dired-field-time
|
|
|
|
'((t :inherit denote-dired-field-date))
|
2022-06-10 06:46:52 +02:00
|
|
|
"Face for file name time in `dired-mode' buffers."
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-11 18:28:10 +02:00
|
|
|
(defface denote-dired-field-title
|
2022-06-10 07:05:44 +02:00
|
|
|
'((t ))
|
|
|
|
"Face for file name title in `dired-mode' buffers."
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-11 18:28:10 +02:00
|
|
|
(defface denote-dired-field-extension
|
2022-06-10 07:05:44 +02:00
|
|
|
'((t :inherit shadow))
|
|
|
|
"Face for file extension type in `dired-mode' buffers."
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-11 18:28:10 +02:00
|
|
|
(defface denote-dired-field-keywords
|
2022-06-07 09:39:46 +02:00
|
|
|
'((default :inherit bold)
|
|
|
|
(((class color) (min-colors 88) (background light))
|
|
|
|
:foreground "#8f0075")
|
|
|
|
(((class color) (min-colors 88) (background dark))
|
|
|
|
:foreground "#f78fe7")
|
|
|
|
(t :inherit font-lock-builtin-face))
|
|
|
|
"Face for file name keywords in `dired-mode' buffers."
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-11 18:28:10 +02:00
|
|
|
(defface denote-dired-field-delimiter
|
2022-06-07 09:39:46 +02:00
|
|
|
'((((class color) (min-colors 88) (background light))
|
2022-06-11 17:43:52 +02:00
|
|
|
:foreground "gray70")
|
2022-06-07 09:39:46 +02:00
|
|
|
(((class color) (min-colors 88) (background dark))
|
2022-06-11 17:43:52 +02:00
|
|
|
:foreground "gray30")
|
2022-06-07 09:39:46 +02:00
|
|
|
(t :inherit shadow))
|
|
|
|
"Face for file name delimiters in `dired-mode' buffers."
|
|
|
|
:group 'denote-dired)
|
|
|
|
|
2022-06-08 10:50:35 +02:00
|
|
|
(defconst denote-dired-font-lock-keywords
|
2022-06-11 16:45:09 +02:00
|
|
|
`((,denote--file-regexp
|
2022-06-11 18:28:10 +02:00
|
|
|
(1 'denote-dired-field-date)
|
|
|
|
(2 'denote-dired-field-time)
|
|
|
|
(3 'denote-dired-field-delimiter)
|
|
|
|
(4 'denote-dired-field-title)
|
|
|
|
(5 'denote-dired-field-delimiter)
|
|
|
|
(6 'denote-dired-field-keywords)
|
|
|
|
(7 'denote-dired-field-extension))
|
2022-06-11 17:33:23 +02:00
|
|
|
("_"
|
2022-06-11 18:28:10 +02:00
|
|
|
(0 'denote-dired-field-delimiter t)))
|
2022-06-08 10:50:35 +02:00
|
|
|
"Keywords for fontification.")
|
2022-06-07 09:39:46 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(define-minor-mode denote-dired-mode
|
2022-06-08 09:38:51 +02:00
|
|
|
"Fontify all Denote-style file names in Dired."
|
2022-06-07 09:39:46 +02:00
|
|
|
:global nil
|
|
|
|
:group 'denote-dired
|
|
|
|
(if denote-dired-mode
|
2022-06-08 10:50:35 +02:00
|
|
|
(font-lock-add-keywords nil denote-dired-font-lock-keywords t)
|
|
|
|
(font-lock-remove-keywords nil denote-dired-font-lock-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)))
|
2022-06-07 09:39:46 +02:00
|
|
|
|
|
|
|
(provide 'denote-dired)
|
|
|
|
;;; denote-dired.el ends here
|