branch: externals/denote commit c6c02ef2df4c423fd1de7c02a286c20b828aaceb Author: Protesilaos Stavrou <i...@protesilaos.com> Commit: Protesilaos Stavrou <i...@protesilaos.com>
Make denote-sort-dired more abstract The idea is to make it easier to write custom variations of the denote-sort-dired. --- denote.el | 97 +++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/denote.el b/denote.el index 8d2a3e5141..7c911f825e 100644 --- a/denote.el +++ b/denote.el @@ -1817,6 +1817,49 @@ Process them to return the buffer name." (if exclude-regexp (format-message "; exclude-regexp `%s'" exclude-regexp) "")) :special-buffer)) +(defun denote-sort-dired--get-sort-parameters (sort-by-component reverse) + "Return (SORT-BY-COMPONENT . REVERSE) for `denote-sort-dired'. +If SORT-BY-COMPONENT is nil, use the value of the user option +`denote-sort-dired-default-sort-component' or fall back to `identifier'. + +If REVERSE is nil, use the value of the user option +`denote-sort-dired-default-reverse-sort' or fall back to nil" + (cons + (or sort-by-component denote-sort-dired-default-sort-component 'identifier) + (or reverse denote-sort-dired-default-reverse-sort nil))) + +(defun denote-sort-dired--prepare-buffer (directory files-fn files-matching-regexp sort-by-component reverse-sort exclude-regexp) + "Prepare buffer for `denote-sort-dired'. +DIRECTORY is an absolute path to the base directory used in the Dired +listing. + +FILES-FN is a function that returns the files to be listed in the Dired +buffer. It takes FILES-MATCHING-REGEXP, SORT-BY-COMPONENT, +REVERSE-SORT, and EXCLUDE-REGEXP as arguments and must return the +results accordingly as a list of strings. + +FILES-FN must consult the value of the variable `denote-directory' to +determine if it is a list of paths or a single file path (see +`denote-has-single-denote-directory-p'). If it is a list of paths, then +the returned list of files must consist of absolute file paths. +Otherwise they can be relative to the single path of the variable +`denote-directory'." + (let* ((default-directory directory) + (files (funcall files-fn files-matching-regexp sort-by-component reverse-sort exclude-regexp)) + (dired-buffer (dired (cons directory files))) + (buffer-name (funcall denote-sort-dired-buffer-name-function files-matching-regexp sort-by-component reverse-sort exclude-regexp))) + (with-current-buffer dired-buffer + (rename-buffer buffer-name :unique) + (setq-local revert-buffer-function + (lambda (&rest _) + (if-let* ((default-directory directory) + (files (funcall files-fn files-matching-regexp sort-by-component reverse-sort exclude-regexp))) + (setq-local dired-directory (cons directory files)) + (setq-local dired-directory (cons directory nil))) + (dired-revert))) + (funcall revert-buffer-function)) + buffer-name)) + (defun denote-sort-dired--find-common-directory (directories) "Return common root directory among DIRECTORIES." (if-let* ((parts (mapcar (lambda (directory) (split-string directory "/" :omit-nulls)) directories)) @@ -1857,37 +1900,29 @@ also prompt for SORT-BY-COMPONENT, REVERSE, and EXCLUDE-REGEXP. OMIT-CURRENT have been applied. When called from Lisp, the arguments are a string, a symbol among -`denote-sort-components', a non-nil value, and a string, respectively." - (interactive - (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts))) - (let ((component (or sort-by-component - denote-sort-dired-default-sort-component - 'identifier)) - (reverse-sort (or reverse - denote-sort-dired-default-reverse-sort - nil)) - (exclude-rx (or exclude-regexp nil)) - (single-dir-p (denote-has-single-denote-directory-p))) - (if-let* (;; See comment in `denote-file-prompt'. - (default-directory (if single-dir-p - (car (denote-directories)) - (denote-sort-dired--find-common-directory (denote-directories)))) - (files (denote-sort-get-directory-files files-matching-regexp component reverse-sort nil exclude-rx))) - (let ((dired-buffer (dired (cons default-directory (if single-dir-p (mapcar #'file-relative-name files) files)))) - (buffer-name (funcall denote-sort-dired-buffer-name-function files-matching-regexp component reverse-sort exclude-rx))) - (with-current-buffer dired-buffer - (rename-buffer buffer-name :unique) - (setq-local revert-buffer-function - (lambda (&rest _) - (if-let* ((default-directory (if single-dir-p - (car (denote-directories)) - (denote-sort-dired--find-common-directory (denote-directories)))) - (all-files (denote-sort-get-directory-files files-matching-regexp component reverse-sort nil exclude-rx)) - (files (if single-dir-p (mapcar #'file-relative-name all-files) all-files))) - (setq-local dired-directory (cons default-directory files))) - (dired-revert))) - (revert-buffer)) - buffer-name) +`denote-sort-components', a non-nil value, and a string, respectively. + +When called from Lisp FILES-MATCHING-REGEXP can be a function which +accepts the remaining of `denote-sort-dired' as arguments. It should +return a list of files, sorted accordingly. The file paths may be +relative if `denote-has-single-denote-directory-p' is non-nil, otherwise +they must be absolute." + (interactive (append (list (denote-files-matching-regexp-prompt)) (denote-sort-dired--prompts))) + (pcase-let* ((`(,component . ,reverse-sort) (denote-sort-dired--get-sort-parameters sort-by-component reverse)) + (exclude-rx exclude-regexp) + (files-fn (cond + ((functionp files-matching-regexp) files-matching-regexp) + ((stringp files-matching-regexp) + (lambda (files-matching-regexp sort-by-component reverse exclude-regexp) + (let ((files (denote-sort-get-directory-files files-matching-regexp sort-by-component reverse nil exclude-regexp))) + (if (denote-has-single-denote-directory-p) + (mapcar #'file-relative-name files) + files))))))) + (if-let* ((directory (if (denote-has-single-denote-directory-p) ; see comment in `denote-file-prompt' + (car (denote-directories)) + (denote-sort-dired--find-common-directory (denote-directories)))) + (files (funcall files-fn files-matching-regexp component reverse-sort exclude-rx))) + (denote-sort-dired--prepare-buffer directory files-fn files-matching-regexp component reverse-sort exclude-rx) (message "No matching files for: %s" files-matching-regexp)))) (defalias 'denote-dired 'denote-sort-dired