'emacs sort files in completions buffer when opening a file
While opening a file in emacs using tab completion, emacs brings up the Completions buffer with a list of the possible completions. The list is ordered alphabetically. How would I configure emacs so that the default behavior is to sort the possible file completions based on time showing the newest or oldest file / directory at the top of the list? Could I further change the sorting criteria dynamically while looking at the completions buffer?
Solution 1:[1]
If you use Icicles then you can easily control sorting.
And you can easily change sort orders on the fly.
And for file-name completion the default sort orders include the order you are requesting. You can choose it to be your default sort order for file-name completion. Or you can choose it during file-name completion, by either cycling or completing its name.
And you can easily define your own sort orders.
If you use only vanilla Emacs then you can fiddle with completion metadata for file-name completion. See metadata categories
display-sort-functionandcycle-sort-function.For example, you can define your own completion command that acts similar to
read-file-namebut that uses a different sort function.This is what vanilla library
tmm.eldoes, for example:
(minibuffer-with-setup-hook
#'tmm-add-prompt
(completing-read
(concat gl-str " (up/down to change, PgUp to menu): ")
(tmm--completion-table tmm-km-list) nil t nil
(cons 'tmm--history (- (* 2 history-len) index-of-default))))
(defun tmm--completion-table (items)
(lambda (string pred action)
(if (eq action 'metadata)
'(metadata (display-sort-function . identity))
(complete-with-action action items string pred))))
Solution 2:[2]
An additional approach can be to define advice for completion--insert-strings. For instance, I wanted to
- Sort symbols with
--last. - Hide
*buffers, unless explicitly filtering for them.
and came up with the following solution:
(advice-add #'completion--insert-strings :around #'my-cmplt-insstr)
(defun my-cmplt-insstr (oldfun strings &rest r)
"Hook into `completion--insert-strings' that applies some postprocessing."
;; Symbols: Sort `--' after anything else.
(when (cl-every #'intern-soft strings)
(mylog "my-cmplt-insstr: -- comes last")
(setq strings
(cl-sort strings #'<
:key (lambda (it) (s-count-matches "--" it))))
(setq strings
(cl-loop with last-had-ddash = nil
for string in strings
for has-ddash = (string-match-p "--" string)
if (and has-ddash (not last-had-ddash))
collect ""
collect string
do (setq last-had-ddash has-ddash))))
;; Buffers: * hidden by default.
(when (cl-member "*Messages*" strings :test #'string=)
(unless (cl-every (lambda (it) (string-prefix-p "*" it)) strings)
(setq strings
(cl-remove-if (lambda (it) (string-prefix-p "*" it)) strings))))
(apply oldfun strings r))
This solution uses rough heuristics to guess what is being completed, but it could be used as an alternate starting point, e.g. with specific read-* functions being advised to set flags for determining which rules are applied.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Drew |
| Solution 2 | kdb |
