From cb033b5921fe4eba2b17795c1d3a803256d620cd Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sat, 6 Jan 2024 13:31:23 +0100 Subject: [PATCH] Support sorting file name completions list by last modified time (minibuffer--sort-file-names-by-last-modified-time): New function. (read-file-name-default): Add it to 'minibuffer-completions-sort-orders' buffer-locally. * doc/emacs/mini.texi (Completion Commands): Elaborate about 'minibuffer-sort-completions'. --- doc/emacs/mini.texi | 15 ++++++++++++--- lisp/minibuffer.el | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi index 1d2dfa8fc4f..072b707ace3 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -399,9 +399,18 @@ the minibuffer, or completes it and then submits it, depending on the of the completions list. By default, Emacs sorts the list of possible completion candidates in the order that you specify in user option @code{completions-sort} (@pxref{Completion Options}). This command -lets you change the order of the current completions list interactively. -You can invoke it with a negative prefix argument (@kbd{C-- C-x C-v}) to -reverse the current order. +lets you change the order of the current completions list +interactively. You can invoke it with a negative prefix argument +(@kbd{C-- C-x C-v}) to reverse the current order. The user option +@code{minibuffer-completions-sort-orders} determines which orders this +command suggests for sorting the completions list. By default, this +includes alphabetical sorting, sorting by candidate position in the +minibuffer history, and no sorting at all. Some commands that use +minibuffer completion also provide additional sorting options that are +specifically useful with their completion candidates. For example, +during file name completion, as in @kbd{C-x C-f} (@pxref{Visiting}), +you can use @key{C-x C-v} to sort candidate file names chronologically +by their last modified time. @kindex C-x n n @r{(completion)} @findex minibuffer-narrow-completions-to-current diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 5f517b3f54b..65db5606e94 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -3666,6 +3666,30 @@ and `read-file-name-function'." ;; instead, but for now, let's keep this non-obsolete. ;;(make-obsolete-variable 'minibuffer-completing-file-name nil "future" 'get) +(defun minibuffer--sort-file-names-by-last-modified-time (files) + "Sort file name completion candidates FILES by last modified time." + (let ((file-time-alist + (mapcar (lambda (file) + (cons file + (file-attribute-modification-time + (ignore-errors + (file-attributes + (substitute-in-file-name + (concat minibuffer-completion-base file))))))) + files))) + (sort files (lambda (a b) + (let ((atime (alist-get a file-time-alist + nil nil #'string=)) + (btime (alist-get b file-time-alist + nil nil #'string=))) + (if atime + (or (not btime) + ;; Put more recently modified files first. + (time-less-p btime atime) + (and (time-equal-p atime btime) + (string-lessp a b))) + (and (not btime) (string-lessp a b)))))))) + (defun read-file-name-default (prompt &optional dir default-filename mustmatch initial predicate) "Default method for reading file names. See `read-file-name' for the meaning of the arguments." @@ -3732,6 +3756,12 @@ See `read-file-name' for the meaning of the arguments." (with-current-buffer (window-buffer (minibuffer-selected-window)) (read-file-name--defaults dir initial)))) + (setq-local + minibuffer-completions-sort-orders + (cons '(?m "modified" "Sort by last modified time" + minibuffer--sort-file-names-by-last-modified-time + "latest modified first") + minibuffer-completions-sort-orders)) (set-syntax-table minibuffer-local-filename-syntax)) (completing-read prompt 'read-file-name-internal pred mustmatch insdef -- 2.39.5