From: Spencer Baugh Date: Tue, 17 Oct 2023 13:09:55 +0000 (-0400) Subject: Add historical option to completions-sort X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=e33f560badac3fd6bd23a6ffc1244afee7dec5f3;p=emacs.git Add historical option to completions-sort Support sorting candidates in *Completions* by the order they show up in the minibuffer history. Also add minibuffer-sort-alphabetically and minibuffer-sort-by-history, which are usable for both completions-sort and display-sort-function. * lisp/minibuffer.el (completions-sort): Document 'historical option. (minibuffer-completion-help): Support 'historical option. (minibuffer-sort-alphabetically) (minibuffer-completion-base, minibuffer-sort-by-history): Add. * etc/NEWS: Announce it. --- diff --git a/etc/NEWS b/etc/NEWS index 3d26f276604..29f4e5c0b66 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -637,6 +637,11 @@ new command 'minibuffer-choose-completion-or-exit' (bound by contents instead. The deselection behavior can be controlled with the new user option 'completion-auto-deselect'. +*** New value 'historical' for user option 'completions-sort' +When 'completions-sort' is set to 'historical', completion candidates +will be sorted by their chronological order in the minibuffer history, +with more recent candidates appearing first. + ** Pcomplete --- diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 382d4458e26..03b64198bcf 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1314,14 +1314,27 @@ completion candidates than this number." (defcustom completions-sort 'alphabetical "Sort candidates in the *Completions* buffer. -The value can be nil to disable sorting, `alphabetical' for -alphabetical sorting or a custom sorting function. The sorting -function takes and returns a list of completion candidate -strings." +Completion candidates in the *Completions* buffer are sorted +depending on the value. + +If it's nil, sorting is disabled. +If it's the symbol `alphabetical', candidates are sorted by +`minibuffer-sort-alphabetically'. +If it's the symbol `historical', candidates are sorted by +`minibuffer-sort-by-history'. +If it's a function, the function is called to sort the candidates. +The sorting function takes a list of completion candidate +strings, which it may modify; it should return a sorted list, +which may be the same. + +If the completion-specific metadata provides a +`display-sort-function', that function overrides the value of +this variable." :type '(choice (const :tag "No sorting" nil) (const :tag "Alphabetical sorting" alphabetical) + (const :tag "Historical sorting" historical) (function :tag "Custom function")) - :version "29.1") + :version "30.1") (defcustom completions-group nil "Enable grouping of completion candidates in the *Completions* buffer. @@ -1647,6 +1660,44 @@ Remove completion BASE prefix string from history elements." (substring c base-size))) hist))))) +(defun minibuffer-sort-alphabetically (completions) + "Sort COMPLETIONS alphabetically. + +COMPLETIONS are sorted alphabetically by `string-lessp'. + +This is a suitable function to use for `completions-sort' or to +include as `display-sort-function' in completion metadata." + (sort completions #'string-lessp)) + +(defvar minibuffer-completion-base nil + "The base for the current completion. + +This is the part of the current minibuffer input which comes +before the current completion field, as determined by +`completion-boundaries'. This is primarily relevant for file +names, where this is the directory component of the file name.") + +(defun minibuffer-sort-by-history (completions) + "Sort COMPLETIONS by their position in `minibuffer-history-variable'. + +COMPLETIONS are sorted first by `minibuffer-sort-alphbetically', +then any elements occuring in the minibuffer history list are +moved to the front based on the chronological order they occur in +the history. If a history variable hasn't been specified for +this call of `completing-read', COMPLETIONS are sorted only by +`minibuffer-sort-alphbetically'. + +This is a suitable function to use for `completions-sort' or to +include as `display-sort-function' in completion metadata." + (let ((alphabetized (sort completions #'string-lessp))) + ;; Only use history when it's specific to these completions. + (if (eq minibuffer-history-variable + (default-value minibuffer-history-variable)) + alphabetized + (minibuffer--sort-by-position + (minibuffer--sort-preprocess-history minibuffer-completion-base) + alphabetized)))) + (defun minibuffer--group-by (group-fun sort-fun elems) "Group ELEMS by GROUP-FUN and sort groups by SORT-FUN." (let ((groups)) @@ -2440,6 +2491,7 @@ The candidate will still be chosen by `choose-completion' unless (let* ((last (last completions)) (base-size (or (cdr last) 0)) (prefix (unless (zerop base-size) (substring string 0 base-size))) + (minibuffer-completion-base (substring string 0 base-size)) (base-prefix (buffer-substring (minibuffer--completion-prompt-end) (+ start base-size))) (base-suffix @@ -2506,7 +2558,8 @@ The candidate will still be chosen by `choose-completion' unless (funcall sort-fun completions) (pcase completions-sort ('nil completions) - ('alphabetical (sort completions #'string-lessp)) + ('alphabetical (minibuffer-sort-alphabetically completions)) + ('historical (minibuffer-sort-by-history completions)) (_ (funcall completions-sort completions))))) ;; After sorting, group the candidates using the