From 5e7c3c81b277b466c34039ae28be12e691a9a894 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 40d9ae7d4dc..320b88ea594 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -445,9 +445,18 @@ complete again. 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 b9fe3df7f84..31e70014d2d 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -3937,6 +3937,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." @@ -4003,6 +4027,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.2