* Updating *Completions* as you type
@ 2023-10-12 23:53 sbaugh
2023-10-13 6:31 ` Eli Zaretskii
` (3 more replies)
0 siblings, 4 replies; 107+ messages in thread
From: sbaugh @ 2023-10-12 23:53 UTC (permalink / raw)
To: emacs-devel
It would be nice if there was a built-in customization which caused
*Completions* to update as you type, as long as that buffer is visible.
I imagine such a request has been made before, so what is the obstacle
to adding it?
I would like to figure out a solution which everyone is happy with, and
then I would be happy to implement it. It seems to me that it's just a
matter of, after each keystroke, triggering (for minibuffer completion)
minibuffer-completion-help or (for buffer completion) some new function
to populate *Completions* with all-completions output. This could (I
guess) be done with after-change-functions, although maybe others have a
better idea.
(Btw, if we had this behavior, it also seems like it would help with
another long-time request: asynchronous completion support. A
programmed completion table could internally do something asynchronous
and stateful, and accumulate results over time, and return more and more
results each time Emacs calls all-completions/try-completion. If Emacs
automatically called all-completions with such a programmed completion
table, the resulting behavior would be an acceptable approximation of
asynchronous completion, without having to complicate the programmed
completion API.)
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-12 23:53 Updating *Completions* as you type sbaugh
@ 2023-10-13 6:31 ` Eli Zaretskii
2023-10-13 18:01 ` Spencer Baugh
2023-10-13 6:34 ` Juri Linkov
` (2 subsequent siblings)
3 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-10-13 6:31 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> From: sbaugh@catern.com
> Date: Thu, 12 Oct 2023 19:53:53 -0400
>
>
> It would be nice if there was a built-in customization which caused
> *Completions* to update as you type, as long as that buffer is visible.
> I imagine such a request has been made before, so what is the obstacle
> to adding it?
I think we have alternative completion schemes, like ido.el and
others, which update the list of the completion candidates as you
type, albeit not in the *Completions* buffer. Why would we need yet
another knob in the default completion scheme?
> (Btw, if we had this behavior, it also seems like it would help with
> another long-time request: asynchronous completion support. A
> programmed completion table could internally do something asynchronous
> and stateful, and accumulate results over time, and return more and more
> results each time Emacs calls all-completions/try-completion. If Emacs
> automatically called all-completions with such a programmed completion
> table, the resulting behavior would be an acceptable approximation of
> asynchronous completion, without having to complicate the programmed
> completion API.)
IIUC what you mean by "asynchronous completion", it is a terrible
idea. How can anyone type text without getting immediate feedback for
what he/she typed? When I sometimes see this (due to network delays
or system load or whatever), it is a terrible UX.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-12 23:53 Updating *Completions* as you type sbaugh
2023-10-13 6:31 ` Eli Zaretskii
@ 2023-10-13 6:34 ` Juri Linkov
2023-10-13 19:04 ` Spencer Baugh
` (2 more replies)
2023-10-13 18:11 ` Updating *Completions* as you type Daniel Semyonov
2023-10-17 0:44 ` Michael Heerdegen
3 siblings, 3 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-13 6:34 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1389 bytes --]
> It would be nice if there was a built-in customization which caused
> *Completions* to update as you type, as long as that buffer is visible.
> I imagine such a request has been made before, so what is the obstacle
> to adding it?
I don't remember what was the obstacle, but here is the previous patch
that implements the behavior of zsh and is based on icomplete-mode.
> I would like to figure out a solution which everyone is happy with, and
> then I would be happy to implement it. It seems to me that it's just a
> matter of, after each keystroke, triggering (for minibuffer completion)
> minibuffer-completion-help or (for buffer completion) some new function
> to populate *Completions* with all-completions output.
There is one difference between icomplete-mode and zcomplete-mode:
the former uses completion-all-sorted-completions where the
recently used items are at the top of the completion list.
Whereas the latter uses the same alphabetical sorting as TAB
shows in the *Completions* buffer. Maybe a new function
should allow any sorting order?
You are welcome to implement such a new function
to populate *Completions* with all-completions output.
Currently I have no idea how to do this.
> This could (I guess) be done with after-change-functions, although
> maybe others have a better idea.
icomplete-mode uses post-command-hook, so zcomplete-mode does the same.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: zcomplete.patch --]
[-- Type: text/x-diff, Size: 13430 bytes --]
diff --git a/lisp/zcomplete.el b/lisp/zcomplete.el
new file mode 100644
index 00000000000..75a40c0afd3
--- /dev/null
+++ b/lisp/zcomplete.el
@@ -0,0 +1,317 @@
+;;; zcomplete.el --- zsh-like minibuffer completion based on icomplete -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author: Juri Linkov <juri@linkov.net>
+;; Keywords: completion
+;; Maintainer: emacs-devel@gnu.org
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Like `icomplete' but provides feedback in the *Completions* window
+;; instead of the minibuffer.
+
+;;; Code:
+
+(defgroup zcomplete nil
+ "Show completions dynamically in *Completions* window from minibuffer."
+ :prefix "zcomplete-"
+ :link '(info-link "(emacs)Zcomplete")
+ :group 'minibuffer)
+
+(defcustom zcomplete-show-matches-on-no-input nil
+ "When non-nil, show completions when first prompting for input.
+This means to show completions even when the current minibuffer contents
+is the same as was the initial input after minibuffer activation.
+This also means that if you traverse the list of completions with
+commands and just hit RET without typing any characters,
+the match under point will be chosen instead of the default."
+ :type 'boolean)
+
+(defcustom zcomplete-with-completion-tables t
+ "Specialized completion tables with which zcomplete should operate.
+If this is t, zcomplete operates on all tables.
+Otherwise this should be a list of the completion tables (e.g.,
+`internal-complete-buffer') on which zcomplete should operate."
+ :type '(choice (const :tag "All" t)
+ (repeat function)))
+
+(defcustom zcomplete-compute-delay .15
+ "Completions-computation stall, used only with large-number completions.
+See `zcomplete-delay-completions-threshold'."
+ :type 'number)
+
+(defcustom zcomplete-delay-completions-threshold 400
+ "Pending-completions number over which to apply `zcomplete-compute-delay'."
+ :type 'integer)
+
+(defcustom zcomplete-max-delay-chars 2
+ "Maximum number of initial chars to apply `zcomplete-compute-delay'."
+ :type 'integer)
+
+(defcustom zcomplete-minibuffer-setup-hook nil
+ "Zcomplete-specific customization of minibuffer setup.
+This hook is run during minibuffer setup if Zcomplete is active."
+ :type 'hook)
+
+\f
+(defvar zcomplete--initial-input nil
+ "Initial input in the minibuffer when `zcomplete-mode' was activated.
+Used to implement the option `zcomplete-show-matches-on-no-input'.")
+
+(defvar zcomplete--previous-input nil
+ "Previous input in the minibuffer before editing it.
+Used to optimize `zcomplete-exhibit' to not be fired while
+moving point in the minibuffer.")
+
+(defun zcomplete-post-command-hook ()
+ (let ((non-essential t)) ;E.g. don't prompt for password!
+ (unless (memq this-command '( previous-history-element next-history-element
+ previous-line-or-history-element
+ next-line-or-history-element))
+ (zcomplete-exhibit))))
+
+(defcustom zcomplete-auto-exhibit 'visible
+ "Non-nil means to use pop up completions on minibuffer edit."
+ :type '(choice (const :tag "Don't auto pop up completions" nil)
+ (const :tag "Pop up completions window" t)
+ (const :tag "Update completions window only when visible"
+ visible)))
+
+(defcustom zcomplete-arrows 'visible
+ "Non-nil means to use arrows to browse completions from the minibuffer."
+ :type '(choice (const :tag "Don't use arrows" nil)
+ (const :tag "Use arrows" t)
+ (const :tag "Use arrows when completions window is visible"
+ visible)))
+
+(defun zcomplete-visible ()
+ (get-buffer-window "*Completions*" 0))
+
+(defun zcomplete-bind-arrows (binding &optional horizontal)
+ `(menu-item
+ "" ,binding
+ :filter ,(lambda (cmd)
+ (when (or (eq zcomplete-arrows t)
+ (and (eq zcomplete-arrows 'visible)
+ (zcomplete-visible)
+ (or (not horizontal)
+ (eq completions-format 'one-column))))
+ cmd))))
+
+(defun zcomplete-bind-visible (binding)
+ `(menu-item
+ "" ,binding
+ :filter ,(lambda (cmd)
+ (when (zcomplete-visible)
+ cmd))))
+
+(defvar-keymap zcomplete-minibuffer-mode-map ;; zcomplete-minibuffer-map
+ :doc "Keymap used by `zcomplete-mode' in the minibuffer."
+
+ "<remap> <minibuffer-complete-and-exit>" (zcomplete-bind-visible #'zcomplete-ret)
+ "<remap> <minibuffer-keyboard-quit>" (zcomplete-bind-visible #'zcomplete-quit)
+ "<remap> <abort-minibuffers>" (zcomplete-bind-visible #'zcomplete-quit)
+
+ "<left>" (zcomplete-bind-arrows #'zcomplete-previous-completion t)
+ "<right>" (zcomplete-bind-arrows #'zcomplete-next-completion t)
+ "<up>" (zcomplete-bind-arrows #'zcomplete-previous-line-completion)
+ "<down>" (zcomplete-bind-arrows #'zcomplete-next-line-completion)
+ "<home>" (zcomplete-bind-arrows #'zcomplete-first-completion)
+ "<end>" (zcomplete-bind-arrows #'zcomplete-last-completion)
+ "<next>" (zcomplete-bind-arrows #'scroll-other-window)
+ "<prior>" (zcomplete-bind-arrows #'scroll-other-window-down))
+
+(defun zcomplete-ret (&optional no-exit no-quit)
+ "Choose the completion from the minibuffer in its completions window."
+ (interactive "P")
+ (condition-case nil
+ (minibuffer-choose-completion no-exit no-quit)
+ (error (minibuffer-complete-and-exit))))
+
+(defun zcomplete-quit ()
+ "Exit minibuffer for zcomplete."
+ (interactive)
+ (minibuffer-hide-completions))
+
+(defcustom zcomplete-auto-choose nil
+ "Non-nil means to automatically insert completions to the minibuffer.
+It affects the variable `minibuffer-completion-auto-choose'.
+This variable is usable only when `zcomplete-auto-exhibit' is nil."
+ :type 'boolean)
+
+(defun zcomplete-next-completion (&optional n)
+ "Run `minibuffer-next-completion' without auto choosing."
+ (interactive "p")
+ (let ((minibuffer-completion-auto-choose zcomplete-auto-choose))
+ (minibuffer-next-completion n)))
+
+(defun zcomplete-previous-completion (&optional n)
+ "Run `minibuffer-previous-completion' without auto choosing."
+ (interactive "p")
+ (let ((minibuffer-completion-auto-choose zcomplete-auto-choose))
+ (minibuffer-previous-completion n)))
+
+(defun zcomplete-next-line-completion (&optional n)
+ "Run `minibuffer-next-line-completion' without auto choosing."
+ (interactive "p")
+ (let ((minibuffer-completion-auto-choose zcomplete-auto-choose))
+ (minibuffer-next-line-completion n)))
+
+(defun zcomplete-previous-line-completion (&optional n)
+ "Run `minibuffer-previous-line-completion' without auto choosing."
+ (interactive "p")
+ (let ((minibuffer-completion-auto-choose zcomplete-auto-choose))
+ (minibuffer-previous-line-completion n)))
+
+(defun zcomplete-first-completion ()
+ "Run `first-completion' from the minibuffer in its completions window."
+ (interactive)
+ (with-minibuffer-completions-window
+ (when completions-highlight-face
+ (setq-local cursor-face-highlight-nonselected-window t))
+ (let ((minibuffer-completion-auto-choose zcomplete-auto-choose))
+ (first-completion))))
+
+(defun zcomplete-last-completion ()
+ "Run `last-completion' from the minibuffer in its completions window."
+ (interactive)
+ (with-minibuffer-completions-window
+ (when completions-highlight-face
+ (setq-local cursor-face-highlight-nonselected-window t))
+ (let ((minibuffer-completion-auto-choose zcomplete-auto-choose))
+ (last-completion))))
+
+\f
+;;;###autoload
+(define-minor-mode zcomplete-mode
+ "Toggle incremental minibuffer completion (Zcomplete mode).
+
+When this global minor mode is enabled, typing in the minibuffer
+continuously displays a list of possible completions that match
+the string you have typed. The list of completions is displayed
+in the *Completions* window.
+
+For more information, see Info node `(emacs)Zcomplete'.
+For options you can set, `\\[customize-group] zcomplete'.
+
+You can use the following key bindings to navigate and select
+completions:
+
+\\{zcomplete-minibuffer-map}"
+ :global t :group 'zcomplete
+ (remove-hook 'minibuffer-setup-hook #'zcomplete-minibuffer-setup)
+ (when zcomplete-mode
+ (add-hook 'minibuffer-setup-hook #'zcomplete-minibuffer-setup)
+ ;; (setq-default completion-show-help nil
+ ;; completions-header-format nil)
+ ))
+
+(define-minor-mode zcomplete-minibuffer-mode
+ "Enable arrows in the minibuffer.
+The only purpose of this mode is to activate
+`zcomplete-minibuffer-mode-map' in the minibuffer."
+ :global nil)
+
+(defun zcomplete--completion-table ()
+ (if (window-minibuffer-p) minibuffer-completion-table
+ (or (nth 2 completion-in-region--data)
+ (message "In %S (w=%S): %S"
+ (current-buffer) (selected-window) (window-minibuffer-p)))))
+(defun zcomplete--field-string ()
+ (if (window-minibuffer-p)
+ (minibuffer-contents)
+ (buffer-substring-no-properties
+ (nth 0 completion-in-region--data)
+ (nth 1 completion-in-region--data))))
+(defun zcomplete--field-beg ()
+ (if (window-minibuffer-p) (minibuffer-prompt-end)
+ (nth 0 completion-in-region--data)))
+(defun zcomplete--field-end ()
+ (if (window-minibuffer-p) (point-max)
+ (nth 1 completion-in-region--data)))
+
+(defun zcomplete-simple-completing-p ()
+ "Non-nil if current window is a minibuffer that's doing simple completion."
+ (unless executing-kbd-macro
+ (let ((table (zcomplete--completion-table)))
+ (and table
+ (or (not (functionp table))
+ (eq zcomplete-with-completion-tables t)
+ (member table zcomplete-with-completion-tables))))))
+
+(defun zcomplete-minibuffer-setup ()
+ "Run in minibuffer on activation to establish incremental completion.
+Usually run by inclusion in `minibuffer-setup-hook'."
+ (when zcomplete-mode
+ (setq-local zcomplete--initial-input (zcomplete--field-string))
+ (setq-local zcomplete--previous-input nil)
+ (zcomplete-minibuffer-mode 1)
+ (add-hook 'post-command-hook #'zcomplete-post-command-hook nil t)
+ (zcomplete-exhibit)
+ (run-hooks 'zcomplete-minibuffer-setup-hook)))
+
+(defun zcomplete-exhibit ()
+ "Update zcomplete completions display.
+Should be run via minibuffer `post-command-hook'.
+See `zcomplete-mode' and `minibuffer-setup-hook'."
+ (when (and zcomplete-mode
+ (zcomplete-simple-completing-p)) ;Shouldn't be necessary.
+ (when (and (or zcomplete-show-matches-on-no-input
+ (not (equal (zcomplete--field-string)
+ zcomplete--initial-input)))
+ (not (equal (zcomplete--field-string)
+ zcomplete--previous-input))
+ (or (eq zcomplete-auto-exhibit t)
+ (and (eq zcomplete-auto-exhibit 'visible)
+ (zcomplete-visible)))
+ (or
+ ;; Don't bother with delay after certain number of chars:
+ (> (- (point) (zcomplete--field-beg))
+ zcomplete-max-delay-chars)
+ ;; Don't delay if the completions are known.
+ completion-all-sorted-completions
+ ;; Don't delay if alternatives number is small enough:
+ (and (sequencep (zcomplete--completion-table))
+ (< (length (zcomplete--completion-table))
+ zcomplete-delay-completions-threshold))
+ ;; Delay - give some grace time for next keystroke, before
+ ;; embarking on computing completions:
+ (sit-for zcomplete-compute-delay)))
+ (save-excursion
+ (goto-char (point-max))
+ (setq-local zcomplete--previous-input (zcomplete--field-string))
+ (minibuffer-completion-help)
+ (unless zcomplete-auto-exhibit
+ (zcomplete-first-completion))))))
+
+(let ((keymap completion-in-region-mode-map))
+ (keymap-set keymap "<left>" #'zcomplete-previous-completion)
+ (keymap-set keymap "<right>" #'zcomplete-next-completion)
+ (keymap-set keymap "<up>" #'zcomplete-previous-line-completion)
+ (keymap-set keymap "<down>" #'zcomplete-next-line-completion)
+ (keymap-set keymap "<home>" #'zcomplete-first-completion)
+ (keymap-set keymap "<end>" #'zcomplete-last-completion)
+ (keymap-set keymap "<next>" #'scroll-other-window)
+ (keymap-set keymap "<prior>" #'scroll-other-window-down)
+ (keymap-set keymap "RET" #'zcomplete-ret))
+
+\f
+(provide 'zcomplete)
+
+;;; zcomplete.el ends here
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-13 6:31 ` Eli Zaretskii
@ 2023-10-13 18:01 ` Spencer Baugh
2023-10-14 7:09 ` Eli Zaretskii
2023-10-14 16:51 ` Juri Linkov
0 siblings, 2 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-10-13 18:01 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: sbaugh@catern.com
>> Date: Thu, 12 Oct 2023 19:53:53 -0400
>>
>>
>> It would be nice if there was a built-in customization which caused
>> *Completions* to update as you type, as long as that buffer is visible.
>> I imagine such a request has been made before, so what is the obstacle
>> to adding it?
>
> I think we have alternative completion schemes, like ido.el and
> others, which update the list of the completion candidates as you
> type, albeit not in the *Completions* buffer. Why would we need yet
> another knob in the default completion scheme?
ido-mode only works for files and buffers, not all minibuffer
completion, and is also unmaintained and sometimes buggy besides that.
icomplete-mode (and its derivatives) doesn't work for in-buffer
completion. Also, it is buggier than the default completion scheme.
>> (Btw, if we had this behavior, it also seems like it would help with
>> another long-time request: asynchronous completion support. A
>> programmed completion table could internally do something asynchronous
>> and stateful, and accumulate results over time, and return more and more
>> results each time Emacs calls all-completions/try-completion. If Emacs
>> automatically called all-completions with such a programmed completion
>> table, the resulting behavior would be an acceptable approximation of
>> asynchronous completion, without having to complicate the programmed
>> completion API.)
>
> IIUC what you mean by "asynchronous completion", it is a terrible
> idea. How can anyone type text without getting immediate feedback for
> what he/she typed? When I sometimes see this (due to network delays
> or system load or whatever), it is a terrible UX.
By asynchronous completion, I just mean being able to type, and trigger
completion, and have completions appear incrementally as they are
computed, without interfering with you continuing to type. I don't
think that stops immediate feedback for typing.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-12 23:53 Updating *Completions* as you type sbaugh
2023-10-13 6:31 ` Eli Zaretskii
2023-10-13 6:34 ` Juri Linkov
@ 2023-10-13 18:11 ` Daniel Semyonov
2023-10-13 18:48 ` Spencer Baugh
2023-10-17 0:44 ` Michael Heerdegen
3 siblings, 1 reply; 107+ messages in thread
From: Daniel Semyonov @ 2023-10-13 18:11 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 2403 bytes --]
My package Vcomplete implements this functionality, however I stopped developing it since I reached the conclusion that this isn’t a very useful feature (to me) and all other features of the package were implemented in some form in Emacs. It still works though, and will use the base Emacs implementation for those other features if they’re available.
Some notes:
- Using after-change-functions to implement this can cause weird issues in packages like Tramp and embark which modify the minibuffer during completion.
- If there are a lot of completions, the completions buffer can take a while to update, and you need to make sure this process blocks user input as little as possible.
- I recall having issues with the completion buffer popping up randomly when typing after completing in a buffer, but I don’t remember why it happened and how I solved it.
- There is also the package aggressive-completion which does something similar.
Daniel
(Sent from a phone, sorry for any weird formatting)
> On 13 Oct 2023, at 8:31, sbaugh@catern.com wrote:
>
>
> It would be nice if there was a built-in customization which caused
> *Completions* to update as you type, as long as that buffer is visible.
> I imagine such a request has been made before, so what is the obstacle
> to adding it?
>
> I would like to figure out a solution which everyone is happy with, and
> then I would be happy to implement it. It seems to me that it's just a
> matter of, after each keystroke, triggering (for minibuffer completion)
> minibuffer-completion-help or (for buffer completion) some new function
> to populate *Completions* with all-completions output. This could (I
> guess) be done with after-change-functions, although maybe others have a
> better idea.
>
> (Btw, if we had this behavior, it also seems like it would help with
> another long-time request: asynchronous completion support. A
> programmed completion table could internally do something asynchronous
> and stateful, and accumulate results over time, and return more and more
> results each time Emacs calls all-completions/try-completion. If Emacs
> automatically called all-completions with such a programmed completion
> table, the resulting behavior would be an acceptable approximation of
> asynchronous completion, without having to complicate the programmed
> completion API.)
>
>
[-- Attachment #2: Type: text/html, Size: 3419 bytes --]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-13 18:11 ` Updating *Completions* as you type Daniel Semyonov
@ 2023-10-13 18:48 ` Spencer Baugh
2023-10-16 3:16 ` [External] : " Drew Adams
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-10-13 18:48 UTC (permalink / raw)
To: emacs-devel
Daniel Semyonov <daniel@dsemy.com> writes:
> My package Vcomplete implements this functionality, however I stopped
> developing it since I reached the conclusion that this isn’t a very
> useful feature (to me) and all other features of the package were
> implemented in some form in Emacs. It still works though, and will
> use the base Emacs implementation for those other features if they’re
> available.
Oh yes, I did see your package. One different is that I don't want to
automatically open the *Completions* buffer, just auto-update after it's
open. Deciding when to open *Completions* is the responsibility of
completion-auto-help and other such options.
> Some notes:
> - Using after-change-functions to implement this can cause weird
> issues in packages like Tramp and embark which modify the minibuffer
> during completion.
Good to know.
> - If there are a lot of completions, the completions buffer can take a
> while to update, and you need to make sure this process blocks user
> input as little as possible.
Hm, perhaps I can optimize the updating of *Completions*, then. That
would be generally useful. Maybe we can find a way to allow user input
to continue while minibuffer-completion-help is running.
> - I recall having issues with the completion buffer popping up
> randomly when typing after completing in a buffer, but I don’t
> remember why it happened and how I solved it.
Plausibly this won't be an issue since I don't plan to open
*Completions* if it's not already open.
> - There is also the package aggressive-completion which does something
> similar.
True! Seems very similar to vcomplete. Again it has more features than
I want to implement, though.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-13 6:34 ` Juri Linkov
@ 2023-10-13 19:04 ` Spencer Baugh
2023-10-14 16:58 ` Juri Linkov
2023-10-16 3:19 ` [External] : " Drew Adams
2023-10-20 9:35 ` zcomplete Philip Kaludercic
2 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-10-13 19:04 UTC (permalink / raw)
To: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> It would be nice if there was a built-in customization which caused
>> *Completions* to update as you type, as long as that buffer is visible.
>> I imagine such a request has been made before, so what is the obstacle
>> to adding it?
>
> I don't remember what was the obstacle, but here is the previous patch
> that implements the behavior of zsh and is based on icomplete-mode.
Nice! Although again this is more features than I want - I just want
*Completions* to automatically update after it opens.
>> I would like to figure out a solution which everyone is happy with, and
>> then I would be happy to implement it. It seems to me that it's just a
>> matter of, after each keystroke, triggering (for minibuffer completion)
>> minibuffer-completion-help or (for buffer completion) some new function
>> to populate *Completions* with all-completions output.
>
> There is one difference between icomplete-mode and zcomplete-mode:
> the former uses completion-all-sorted-completions where the
> recently used items are at the top of the completion list.
> Whereas the latter uses the same alphabetical sorting as TAB
> shows in the *Completions* buffer. Maybe a new function
> should allow any sorting order?
This is orthogonal to my original topic, which is just updating
*Completions* as I type, without changing how it gets populated.
That being said, yes this may be nice. But minibuffer-completion-help
already does sort the completions using display-sort-function, just like
completion-all-sorted-completions, so what's causing the difference in
behavior?
Honestly the main place I find myself wanting different sorting of
completions is for buffer completion - I'd prefer buffers to be sorted
by most-recently-used. Maybe we can just add such an option?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-13 18:01 ` Spencer Baugh
@ 2023-10-14 7:09 ` Eli Zaretskii
2023-10-14 19:26 ` Björn Bidar
[not found] ` <874jit2ef7.fsf@>
2023-10-14 16:51 ` Juri Linkov
1 sibling, 2 replies; 107+ messages in thread
From: Eli Zaretskii @ 2023-10-14 7:09 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Fri, 13 Oct 2023 14:01:38 -0400
>
> Eli Zaretskii <eliz@gnu.org> writes:
> >> From: sbaugh@catern.com
> >> Date: Thu, 12 Oct 2023 19:53:53 -0400
> >>
> >>
> >> It would be nice if there was a built-in customization which caused
> >> *Completions* to update as you type, as long as that buffer is visible.
> >> I imagine such a request has been made before, so what is the obstacle
> >> to adding it?
> >
> > I think we have alternative completion schemes, like ido.el and
> > others, which update the list of the completion candidates as you
> > type, albeit not in the *Completions* buffer. Why would we need yet
> > another knob in the default completion scheme?
>
> ido-mode only works for files and buffers, not all minibuffer
> completion, and is also unmaintained and sometimes buggy besides that.
>
> icomplete-mode (and its derivatives) doesn't work for in-buffer
> completion.
What do you mean by "in-buffer completion"?
> Also, it is buggier than the default completion scheme.
Then let's fix those bugs before we consider adding yet another
completion scheme (with its own bugs).
Does anyone else here thinks we need yet in core another completion
feature in addition to what we have already (which, btw, includes
fido-mode as well)?
> >> (Btw, if we had this behavior, it also seems like it would help with
> >> another long-time request: asynchronous completion support. A
> >> programmed completion table could internally do something asynchronous
> >> and stateful, and accumulate results over time, and return more and more
> >> results each time Emacs calls all-completions/try-completion. If Emacs
> >> automatically called all-completions with such a programmed completion
> >> table, the resulting behavior would be an acceptable approximation of
> >> asynchronous completion, without having to complicate the programmed
> >> completion API.)
> >
> > IIUC what you mean by "asynchronous completion", it is a terrible
> > idea. How can anyone type text without getting immediate feedback for
> > what he/she typed? When I sometimes see this (due to network delays
> > or system load or whatever), it is a terrible UX.
>
> By asynchronous completion, I just mean being able to type, and trigger
> completion, and have completions appear incrementally as they are
> computed, without interfering with you continuing to type. I don't
> think that stops immediate feedback for typing.
If it's asynchronous, then how can we make sure the feedback is
immediate?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-13 18:01 ` Spencer Baugh
2023-10-14 7:09 ` Eli Zaretskii
@ 2023-10-14 16:51 ` Juri Linkov
2023-10-14 17:56 ` sbaugh
2023-10-14 19:51 ` Dmitry Gutov
1 sibling, 2 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-14 16:51 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> icomplete-mode (and its derivatives) doesn't work for in-buffer
> completion. Also, it is buggier than the default completion scheme.
Actually, now icomplete-mode supports in-buffer completion quite well.
> By asynchronous completion, I just mean being able to type, and trigger
> completion, and have completions appear incrementally as they are
> computed, without interfering with you continuing to type. I don't
> think that stops immediate feedback for typing.
I believe this is achievable by just wrapping code with while-no-input.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-13 19:04 ` Spencer Baugh
@ 2023-10-14 16:58 ` Juri Linkov
2023-10-14 20:05 ` sbaugh
2023-10-17 15:01 ` sbaugh
0 siblings, 2 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-14 16:58 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
>>> It would be nice if there was a built-in customization which caused
>>> *Completions* to update as you type, as long as that buffer is visible.
>>> I imagine such a request has been made before, so what is the obstacle
>>> to adding it?
>>
>> I don't remember what was the obstacle, but here is the previous patch
>> that implements the behavior of zsh and is based on icomplete-mode.
>
> Nice! Although again this is more features than I want - I just want
> *Completions* to automatically update after it opens.
Probably it's possible to pare it down to less code with less features
that could basically do the same after toggling a new option.
> That being said, yes this may be nice. But minibuffer-completion-help
> already does sort the completions using display-sort-function, just like
> completion-all-sorted-completions, so what's causing the difference in
> behavior?
It seems this is implementable in minibuffer-completion-help
by copying this code from completion-all-sorted-completions:
(setq all (minibuffer--sort-by-position
(minibuffer--sort-preprocess-history
(substring string 0 base-size))
all))
> Honestly the main place I find myself wanting different sorting of
> completions is for buffer completion - I'd prefer buffers to be sorted
> by most-recently-used. Maybe we can just add such an option?
Such an option would be nice. Maybe the right way to support it
is to add a new sort function with the code above. Then the caller
could provide such a function in the completion metadata.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 16:51 ` Juri Linkov
@ 2023-10-14 17:56 ` sbaugh
2023-10-14 19:51 ` Dmitry Gutov
1 sibling, 0 replies; 107+ messages in thread
From: sbaugh @ 2023-10-14 17:56 UTC (permalink / raw)
To: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> icomplete-mode (and its derivatives) doesn't work for in-buffer
>> completion. Also, it is buggier than the default completion scheme.
>
> Actually, now icomplete-mode supports in-buffer completion quite well.
Oh, neat! I knew there was icomplete-in-buffer but I see that it's been
much improved recently.
>> By asynchronous completion, I just mean being able to type, and trigger
>> completion, and have completions appear incrementally as they are
>> computed, without interfering with you continuing to type. I don't
>> think that stops immediate feedback for typing.
>
> I believe this is achievable by just wrapping code with while-no-input.
Indeed.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 7:09 ` Eli Zaretskii
@ 2023-10-14 19:26 ` Björn Bidar
[not found] ` <874jit2ef7.fsf@>
1 sibling, 0 replies; 107+ messages in thread
From: Björn Bidar @ 2023-10-14 19:26 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Spencer Baugh, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> > IIUC what you mean by "asynchronous completion", it is a terrible
>> > idea. How can anyone type text without getting immediate feedback for
>> > what he/she typed? When I sometimes see this (due to network delays
>> > or system load or whatever), it is a terrible UX.
>>
>> By asynchronous completion, I just mean being able to type, and trigger
>> completion, and have completions appear incrementally as they are
>> computed, without interfering with you continuing to type. I don't
>> think that stops immediate feedback for typing.
>
> If it's asynchronous, then how can we make sure the feedback is
> immediate?
The feedback updates while typing but doesn't show until the delay set
by the user has passed to show the suggestions again.
If the feedback hasn't updated by the time the user stops typing then
the old state is shown similar to how the feedback is when the
completion is synchronous.
I most cases I think the feedback updates as fast as the major mode can
update the buffer to pass it e.g. to an internal function or language
server/or alike.
In cases of external programs parsing the just updated buffer the
completion can be nearly asynchronous already.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
[not found] ` <874jit2ef7.fsf@>
@ 2023-10-14 19:38 ` Eli Zaretskii
0 siblings, 0 replies; 107+ messages in thread
From: Eli Zaretskii @ 2023-10-14 19:38 UTC (permalink / raw)
To: Björn Bidar; +Cc: sbaugh, emacs-devel
> From: Björn Bidar <bjorn.bidar@thaodan.de>
> Cc: Spencer Baugh <sbaugh@janestreet.com>, emacs-devel@gnu.org
> Date: Sat, 14 Oct 2023 22:26:52 +0300
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> >> > IIUC what you mean by "asynchronous completion", it is a terrible
> >> > idea. How can anyone type text without getting immediate feedback for
> >> > what he/she typed? When I sometimes see this (due to network delays
> >> > or system load or whatever), it is a terrible UX.
> >>
> >> By asynchronous completion, I just mean being able to type, and trigger
> >> completion, and have completions appear incrementally as they are
> >> computed, without interfering with you continuing to type. I don't
> >> think that stops immediate feedback for typing.
> >
> > If it's asynchronous, then how can we make sure the feedback is
> > immediate?
>
> The feedback updates while typing but doesn't show until the delay set
> by the user has passed to show the suggestions again.
This sentence seems to contradict itself: what is the meaning of
"feedback updates" if the feedback "doesn't show"?
> If the feedback hasn't updated by the time the user stops typing then
> the old state is shown similar to how the feedback is when the
> completion is synchronous.
I don't understand this, either. Please elaborate, or maybe show an
example.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 16:51 ` Juri Linkov
2023-10-14 17:56 ` sbaugh
@ 2023-10-14 19:51 ` Dmitry Gutov
1 sibling, 0 replies; 107+ messages in thread
From: Dmitry Gutov @ 2023-10-14 19:51 UTC (permalink / raw)
To: Juri Linkov, Spencer Baugh; +Cc: emacs-devel
On 14/10/2023 19:51, Juri Linkov wrote:
>> icomplete-mode (and its derivatives) doesn't work for in-buffer
>> completion. Also, it is buggier than the default completion scheme.
> Actually, now icomplete-mode supports in-buffer completion quite well.
>
>> By asynchronous completion, I just mean being able to type, and trigger
>> completion, and have completions appear incrementally as they are
>> computed, without interfering with you continuing to type. I don't
>> think that stops immediate feedback for typing.
> I believe this is achievable by just wrapping code with while-no-input.
>
icomplete-exhibit uses while-no-input, FWIW.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 16:58 ` Juri Linkov
@ 2023-10-14 20:05 ` sbaugh
2023-10-15 6:06 ` Eli Zaretskii
` (4 more replies)
2023-10-17 15:01 ` sbaugh
1 sibling, 5 replies; 107+ messages in thread
From: sbaugh @ 2023-10-14 20:05 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 816 bytes --]
Juri Linkov <juri@linkov.net> writes:
>>>> It would be nice if there was a built-in customization which caused
>>>> *Completions* to update as you type, as long as that buffer is visible.
>>>> I imagine such a request has been made before, so what is the obstacle
>>>> to adding it?
>>>
>>> I don't remember what was the obstacle, but here is the previous patch
>>> that implements the behavior of zsh and is based on icomplete-mode.
>>
>> Nice! Although again this is more features than I want - I just want
>> *Completions* to automatically update after it opens.
>
> Probably it's possible to pare it down to less code with less features
> that could basically do the same after toggling a new option.
Yes, agreed. Taking inspiration from zcomplete, I wrote this patch to
provide just this feature, thoughts?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-completions-auto-update.patch --]
[-- Type: text/x-patch, Size: 3402 bytes --]
From fef547ece1d5cd3eebbc2fb7f51e51f15cfc2b4a Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Sat, 14 Oct 2023 14:27:23 -0400
Subject: [PATCH] Add completions-auto-update
It can be useful for the *Completions* buffer to automatically update
as you type. That way you can see immediately what the next
completion operation will do, even if you've changed text in the
buffer since triggering completion.
* lisp/minibuffer.el (completions-auto-update): Add.
(completions-no-auto-update-commands): Add.
(completions--post-command): Add.
(minibuffer-completion-help): Add completions--post-command to
post-command-hook.
---
lisp/minibuffer.el | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 3e30b68d5e9..9995da9e4b7 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2376,6 +2376,40 @@ completions--fit-window-to-buffer
(resize-temp-buffer-window win))
(fit-window-to-buffer win completions-max-height)))
+(defcustom completions-auto-update t
+ "If non-nil, update the *Completions* buffer as you type.
+
+This only affects the *Completions* buffer if it is already
+displayed."
+ :type '(choice (const :tag "*Completions* doesn't change as you type" nil)
+ (const :tag "*Completions* updates as you type" t))
+ :version "30.1")
+
+(defconst completions-no-auto-update-commands
+ '(previous-history-element
+ next-history-element
+ previous-line-or-history-element
+ next-line-or-history-element
+ completion-at-point
+ minibuffer-complete-and-exit
+ minibuffer-force-complete-and-exit
+ minibuffer-next-completion
+ minibuffer-previous-completion
+ minibuffer-choose-completion)
+ "Commands to skip updating *Completions*")
+
+(defun completions--post-command ()
+ "Update a displayed *Completions* buffer after a change"
+ (when completions-auto-update
+ (while-no-input
+ (let ((non-essential t))
+ (when (and (get-buffer-window "*Completions*" 0)
+ (not (memq this-command completions-no-auto-update-commands)))
+ (redisplay)
+ (if completion-in-region-mode
+ (completion-help-at-point)
+ (minibuffer-completion-help)))))))
+
(defun minibuffer-completion-help (&optional start end)
"Display a list of possible completions of the current minibuffer contents."
(interactive)
@@ -2398,6 +2432,7 @@ minibuffer-completion-help
;; If there are no completions, or if the current input is already
;; the sole completion, then hide (previous&stale) completions.
(minibuffer-hide-completions)
+ (remove-hook 'post-command-hook #'completions--post-command t)
(if completions
(completion--message "Sole completion")
(unless completion-fail-discreetly
@@ -2449,6 +2484,9 @@ minibuffer-completion-help
(body-function
. ,#'(lambda (_window)
(with-current-buffer mainbuf
+ (when completions-auto-update
+ (add-hook 'post-command-hook #'completions--post-command nil t))
+
;; Remove the base-size tail because `sort' requires a properly
;; nil-terminated list.
(when last (setcdr last nil))
--
2.41.0
[-- Attachment #3: Type: text/plain, Size: 2714 bytes --]
>> That being said, yes this may be nice. But minibuffer-completion-help
>> already does sort the completions using display-sort-function, just like
>> completion-all-sorted-completions, so what's causing the difference in
>> behavior?
>
> It seems this is implementable in minibuffer-completion-help
> by copying this code from completion-all-sorted-completions:
>
> (setq all (minibuffer--sort-by-position
> (minibuffer--sort-preprocess-history
> (substring string 0 base-size))
> all))
Oh, very interesting! Maybe completions-sort should accept a new symbol
'history to behave this way?
I already think this would be very nice for project-switch-project, for
example, since I'm often switching between a few related projects.
Perhaps 'history should break ties by alphabetizing, otherwise
e.g. filenames you haven't visited before would be unsorted randomly.
Hmm, actually the case of filenames is a bit complex. Because for
filenames, the strings we're completing over don't appear verbatim in
the history. So perhaps read-file-name would need its own specialized
sorting function, which whenever you're completing in some directory,
sorts to the front any files in that directory whose full path appears
in file-name-history.
>> Honestly the main place I find myself wanting different sorting of
>> completions is for buffer completion - I'd prefer buffers to be sorted
>> by most-recently-used. Maybe we can just add such an option?
>
> Such an option would be nice. Maybe the right way to support it
> is to add a new sort function with the code above. Then the caller
> could provide such a function in the completion metadata.
Oh, that's also interesting. So there would be a function that the
completion metadata could specify as display-sort-function, which would
have the behavior of sorting based on history?
That also makes a lot of sense, and would allow commands like
project-switch-project and read-buffer to opt in on a command-by-command
basis, which might be more sensible.
So maybe adding 'history as a new option for completions-sort isn't a
good idea. Instead we should just add user options for enabling history
sorting for files and buffers. (And perhaps we could just enable
history sorting by default for project-switch-project.)
Also: it might be nice to switch between history-sorting and
alphabetized-sorting during the course of completion, both for files and
buffers. Maybe we could do that by making a command which puts
completion into a mode where it just ignores the display-sort-function
specified by the completion metadata, and just always uses
completions-sort.
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 20:05 ` sbaugh
@ 2023-10-15 6:06 ` Eli Zaretskii
2023-10-15 15:55 ` sbaugh
2023-10-15 7:32 ` Juri Linkov
` (3 subsequent siblings)
4 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-10-15 6:06 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> From: sbaugh@catern.com
> Date: Sat, 14 Oct 2023 16:05:11 -0400
>
> Yes, agreed. Taking inspiration from zcomplete, I wrote this patch to
> provide just this feature, thoughts?
I tried this. The update is slow (most probably because it works off
the post-command-hook), and the UX is therefore extremely unpleasant
if you type fast enough.
> +(defcustom completions-auto-update t
> + "If non-nil, update the *Completions* buffer as you type.
Thus _must_ be nil by default.
> +(defconst completions-no-auto-update-commands
> + '(previous-history-element
> + next-history-element
> + previous-line-or-history-element
> + next-line-or-history-element
> + completion-at-point
> + minibuffer-complete-and-exit
> + minibuffer-force-complete-and-exit
> + minibuffer-next-completion
> + minibuffer-previous-completion
> + minibuffer-choose-completion)
> + "Commands to skip updating *Completions*")
Why are those excluded? And why is this a defconst, not a defvar or
defcustom?
> + (while-no-input
> + (let ((non-essential t))
^^^^^^^^^^^^^^^
Why?
> + (when (and (get-buffer-window "*Completions*" 0)
> + (not (memq this-command completions-no-auto-update-commands)))
> + (redisplay)
^^^^^^^^^^^
Why do you need this?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 20:05 ` sbaugh
2023-10-15 6:06 ` Eli Zaretskii
@ 2023-10-15 7:32 ` Juri Linkov
2023-10-16 19:28 ` Rudolf Adamkovič
2023-10-15 20:31 ` Eshel Yaron
` (2 subsequent siblings)
4 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-15 7:32 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
>>> Nice! Although again this is more features than I want - I just want
>>> *Completions* to automatically update after it opens.
>>
>> Probably it's possible to pare it down to less code with less features
>> that could basically do the same after toggling a new option.
>
> Yes, agreed. Taking inspiration from zcomplete, I wrote this patch to
> provide just this feature, thoughts?
Thank you very much for finally bringing this useful feature to the core
while keeping it sufficiently short. I briefly tried your patch, and
it works exactly as expected by experience of using such common completions
as in the address bar of web browsers, etc. I'll continue testing it more
for a while.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-15 6:06 ` Eli Zaretskii
@ 2023-10-15 15:55 ` sbaugh
2023-10-16 11:38 ` Eli Zaretskii
2023-10-16 12:16 ` sbaugh
0 siblings, 2 replies; 107+ messages in thread
From: sbaugh @ 2023-10-15 15:55 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: sbaugh@catern.com
>> Date: Sat, 14 Oct 2023 16:05:11 -0400
>>
>> Yes, agreed. Taking inspiration from zcomplete, I wrote this patch to
>> provide just this feature, thoughts?
>
> I tried this. The update is slow (most probably because it works off
> the post-command-hook), and the UX is therefore extremely unpleasant
> if you type fast enough.
Interesting. Can you say more about what completion you're doing for
which the update is slow? I would have expected the while-no-input to
cause the update to not block you if you type fast.
Of course, if there are optimizations that need to be done for
completion-generation, I'm happy to do them.
>> +(defcustom completions-auto-update t
>> + "If non-nil, update the *Completions* buffer as you type.
>
> Thus _must_ be nil by default.
Of course, just defaulted to t to make testing the patch easier.
>> +(defconst completions-no-auto-update-commands
>> + '(previous-history-element
>> + next-history-element
>> + previous-line-or-history-element
>> + next-line-or-history-element
>> + completion-at-point
>> + minibuffer-complete-and-exit
>> + minibuffer-force-complete-and-exit
>> + minibuffer-next-completion
>> + minibuffer-previous-completion
>> + minibuffer-choose-completion)
>> + "Commands to skip updating *Completions*")
>
> Why are those excluded? And why is this a defconst, not a defvar or
> defcustom?
These are basically just commands where it would be annoying or
pointless to do an auto-update.
There are three classes here:
1. completion-at-point
minibuffer-complete-and-exit
minibuffer-force-complete-and-exit
These commands themselves update *Completions*, so it's not necessary
to update *Completions* immediately after they run, since it will
already be up to date for the buffer text.
This is just a performance thing and isn't strictly necessary. I'll
drop them from the next version.
(The performance optimization could be implemented separately from
completions-auto-update and apply even if it was nil. We could have
a general mechanism to skip regeneration of completions if the
completion input hasn't changed. That could be nice, although it's a
complex topic.)
2. previous-history-element
next-history-element
previous-line-or-history-element
next-line-or-history-element
minibuffer-choose-completion
These insert some text in the minibuffer which usually (but not
always) will only have one completion.
I'll drop these from the next version of my patch, since actually I
now realize there's no reason to special-case skipping these.
3. minibuffer-next-completion
minibuffer-previous-completion
These call next-completion, which changes the location of point in
*Completions*. And if we auto-update *Completions*, we lose the
location of point.
But actually, even without completions-auto-update, it would be
generally useful to not lose the location of point in *Completions*.
So I'll just implement that as a separate patch. And then I can also
drop these two special cases.
So, in the next version of my patch, this variable will be dropped
entirely.
>> + (while-no-input
>> + (let ((non-essential t))
> ^^^^^^^^^^^^^^^
> Why?
This I borrowed from zcomplete. It seems sensible, since
non-essential's docstring says:
E.g., it can be used to prevent Tramp from prompting the user for a
password when we are [...] displaying possible completions before the
user even asked for it.
>> + (when (and (get-buffer-window "*Completions*" 0)
>> + (not (memq this-command completions-no-auto-update-commands)))
>> + (redisplay)
> ^^^^^^^^^^^
> Why do you need this?
post-command-hook's docstring says:
It is a bad idea to use this hook for expensive processing. If
unavoidable, wrap your code in ‘(while-no-input (redisplay) CODE)’ to
avoid making Emacs unresponsive while the user types.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 20:05 ` sbaugh
2023-10-15 6:06 ` Eli Zaretskii
2023-10-15 7:32 ` Juri Linkov
@ 2023-10-15 20:31 ` Eshel Yaron
2023-10-16 3:18 ` [External] : " Drew Adams
2023-10-16 16:54 ` Juri Linkov
2023-10-17 13:48 ` sbaugh
2023-10-20 6:49 ` Juri Linkov
4 siblings, 2 replies; 107+ messages in thread
From: Eshel Yaron @ 2023-10-15 20:31 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
Hi,
sbaugh@catern.com writes:
> Taking inspiration from zcomplete, I wrote this patch to
> provide just this feature, thoughts?
>
> From fef547ece1d5cd3eebbc2fb7f51e51f15cfc2b4a Mon Sep 17 00:00:00 2001
> From: Spencer Baugh <sbaugh@catern.com>
> Date: Sat, 14 Oct 2023 14:27:23 -0400
> Subject: [PATCH] Add completions-auto-update
>
> It can be useful for the *Completions* buffer to automatically update
> as you type. That way you can see immediately what the next
> completion operation will do, even if you've changed text in the
> buffer since triggering completion.
>
> * lisp/minibuffer.el (completions-auto-update): Add.
> (completions-no-auto-update-commands): Add.
> (completions--post-command): Add.
> (minibuffer-completion-help): Add completions--post-command to
> post-command-hook.
I tried this out, and I came across a certain issue: say you do
`C-h o foo TAB`, and then looking at the completion candidates
you realize you actually wanted something with `bar`, so you
type `M-DEL` to delete `foo` from the minibuffer to make room
for `bar`. But now `post-command-hook` runs with an empty
minibuffer before you start typing `bar`, so it updates the
completions buffer with a very large list of symbols, causing
Emacs to briefly stall. I think that the completions buffer
possibly shouldn't be updated when the minibuffer is empty.
Perhaps there could be a minimum minibuffer contents size for
updating the completions buffer, or some other heuristic to
avoid auto-displaying excessively large sets of candidates.
Another option is to update the completions buffer on
`post-self-insert-hook` instead of `post-command-hook`, that
way you only update the completions buffer when the user
actually inserts input in the minibuffer, and you don't need to
keep a `completions-no-auto-update-commands` list.
Best,
Eshel
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-13 18:48 ` Spencer Baugh
@ 2023-10-16 3:16 ` Drew Adams
2023-10-16 9:25 ` Philip Kaludercic
0 siblings, 1 reply; 107+ messages in thread
From: Drew Adams @ 2023-10-16 3:16 UTC (permalink / raw)
To: Spencer Baugh, emacs-devel@gnu.org
FWIW:
I'll mention some similar features in Icicles. They
were introduced together from the outset (in 2005!),
and have proven useful.
Such features really should be flexible - in no way
hard-coded. Flexible for use interactively and with
Lisp. Don't just look for a good compromise
behavior - do that for the default behavior, sure.
But let users easily switch behaviors on the fly.
And let Lisp code easily choose different default
(i.e., initial) behaviors for different
contexts/commands.
> I don't want to automatically open the *Completions*
> buffer, just auto-update after it's open. Deciding
> when to open *Completions* is the responsibility of
> completion-auto-help and other such options.
Icicles introduced incremental *Completions*-display
updating, providing these options to let users and code
easily control the behavior:
1. `icicle-incremental-completion':
* `t' : Update *Completions* incrementally only if
it's already displayed. (Default.)
* `nil': Don't update *Completions* incrementally.
* other: Show *Completions* if not shown (+ update).
`C-#' in the minibuffer cycles the values, so you
can change the behavior on the fly.
Some commands, such as those for navigation/search
choices or those effectively providing multiple-choice
menus, may want to bind the var to `always', to show
you what's available at the outset, i.e., the full
completion domain.
A command that has many potential candidates (domain)
might want to bind `icicle-incremental-completion' to
`nil' at the outset if their display is too costly.
(You can always use `C-#' to
change.)
2. `icicle-show-Completions-initially-flag':
Non-nil: Show `*Completions*' even without user input.
> > - If there are a lot of completions, the completions
> > buffer can take a while to update...
These options help with that:
3. `icicle-incremental-completion-threshold':
When there are more than this many completions then
wait (see next) before updating *Completions*.
4. `icicle-incremental-completion-delay':
Seconds to wait before updating *Completions*, if
there are currently more matching candidates than
`icicle-incremental-completion-threshold'.
5. `icicle-max-candidates':
Non-nil means show at most this many candidates
in *Completions*.
___
https://www.emacswiki.org/emacs/Icicles_-_Icompletion#IncrementalCompletion
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-15 20:31 ` Eshel Yaron
@ 2023-10-16 3:18 ` Drew Adams
2023-10-16 16:54 ` Juri Linkov
1 sibling, 0 replies; 107+ messages in thread
From: Drew Adams @ 2023-10-16 3:18 UTC (permalink / raw)
To: Eshel Yaron, sbaugh@catern.com; +Cc: emacs-devel@gnu.org
> I think that the completions buffer possibly
> shouldn't be updated when the minibuffer is empty.
> Perhaps there could be a minimum minibuffer
> contents size for updating the completions buffer,
> or some other heuristic to avoid auto-displaying
> excessively large sets of candidates.
FWIW:
In addition to the Icicles variables I mentioned
previously, there's this one:
4. `icicle-Completions-display-min-chars':
`*Completions*' window is removed if fewer chars
than this are input (i.e., in the minibuffer).
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-13 6:34 ` Juri Linkov
2023-10-13 19:04 ` Spencer Baugh
@ 2023-10-16 3:19 ` Drew Adams
2023-10-20 9:35 ` zcomplete Philip Kaludercic
2 siblings, 0 replies; 107+ messages in thread
From: Drew Adams @ 2023-10-16 3:19 UTC (permalink / raw)
To: Juri Linkov, sbaugh@catern.com; +Cc: emacs-devel@gnu.org
> Maybe a new function should allow any sorting order?
FWIW:
Icicles lets a caller of a function such as
`completing-read' specify a set of sort functions
and the initial one to use.
And users can change among those sort functions
on the fly - by cycling them or inputting the name
(with completion of course). Reverse the current
sort order with a numeric prefix arg.
User switching of sort order is _very_ useful, IMO.
(And yes, incremental updating of *Completions"
needs to automatically re-sort.)
___
https://www.emacswiki.org/emacs/Icicles_-_Sorting_Candidates
______________________________________________
FWIW2:
In library `sortie.el' I implemented the same thing,
without Icicles, using only vanilla Emacs completion
metadata entries `display-sort-function' and
`cycle-sort-function'.
[I don't know of another library (besides Icicles)
that provides interactive changing of sort order -
but maybe there is one now.]
___
https://www.emacswiki.org/emacs/Sortie
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: [External] : Re: Updating *Completions* as you type
2023-10-16 3:16 ` [External] : " Drew Adams
@ 2023-10-16 9:25 ` Philip Kaludercic
2023-10-16 16:03 ` Drew Adams
2023-10-16 22:55 ` Emanuel Berg
0 siblings, 2 replies; 107+ messages in thread
From: Philip Kaludercic @ 2023-10-16 9:25 UTC (permalink / raw)
To: Drew Adams; +Cc: Spencer Baugh, emacs-devel@gnu.org
Drew Adams <drew.adams@oracle.com> writes:
> FWIW:
>
> I'll mention some similar features in Icicles. They
> were introduced together from the outset (in 2005!),
> and have proven useful.
You have mentioned Icicles a number of times, and one of the main
reasons I have never tried it out is that it is not available on ELPA or
any kind of official repository. I believe wrote about this a while
back, but according to [0], the main issue remains that your libraries
overwrite Emacs primitives, as you mention in the main file:
--8<---------------cut here---------------start------------->8---
;; ***** NOTE: These EMACS PRIMITIVES have been REDEFINED in Icicles:
;;
;; `completing-read' - (See below and doc string.)
;; `display-completion-list' - (See below and doc string.)
;; `exit-minibuffer' - Remove *Completion* window.
;; `minibuffer-complete-and-exit' - Remove *Completion* window.
;; `read-file-name' - (See below and doc string.)
;; `read-from-minibuffer' - (See below and doc string.)
;; `read-string' - (See below and doc string.)
;;
;;
;; ***** NOTE: The following functions defined in `dabbrev.el' have
;; been REDEFINED in Icicles:
;;
;; `dabbrev-completion' - Use Icicles completion when you repeat
;; (`C-M-/').
;;
;;
;; ***** NOTE: The following functions defined in `lisp.el' have
;; been REDEFINED in Icicles:
;;
;; `lisp-complete-symbol' - Selects `*Completions*' window even if on
;; another frame.
;;
;;
;; ***** NOTE: The following functions defined in `mouse.el' have
;; been REDEFINED in Icicles:
;;
;; `mouse-choose-completion' - Return the number of the completion.
;;
;;
;; ***** NOTE: The following functions defined in `simple.el' have
;; been REDEFINED in Icicles:
;;
;; `choose-completion-string' -
;; Don't exit minibuffer after `lisp-complete-symbol' completion.
;; `completion-setup-function' - 1. Put faces on inserted string(s).
;; 2. Help on help.
;; `switch-to-completions' - Always selects `*Completions*' window.
;;
;; `next-history-element' (advised only) -
;; Depending on `icicle-default-value', select minibuffer
;; contents.
;;
;; `repeat-complex-command' - Use `completing-read' to read command.
;;
;; For descriptions of changes to this file, see `icicles-chg.el'.
--8<---------------cut here---------------end--------------->8---
Is this really necessary? Somehow all the other completion systems
appear to get by without these kinds of invasive changes, and it would
be a pity the barriers for trying out your package continue to be
unnecessarily high, if the functionality is so advanced. At the very
least it would be nice if you could have your own ELPA, perhaps hosted
on Emacs Wiki to distribute these packages in a more standardised way.
[0] https://www.emacswiki.org/emacs/icicles.el
--
Philip Kaludercic
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-15 15:55 ` sbaugh
@ 2023-10-16 11:38 ` Eli Zaretskii
2023-10-16 14:50 ` Michael Albinus
2023-10-16 12:16 ` sbaugh
1 sibling, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-10-16 11:38 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> From: sbaugh@catern.com
> Date: Sun, 15 Oct 2023 11:55:47 -0400
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> >> From: sbaugh@catern.com
> >> Date: Sat, 14 Oct 2023 16:05:11 -0400
> >>
> >> Yes, agreed. Taking inspiration from zcomplete, I wrote this patch to
> >> provide just this feature, thoughts?
> >
> > I tried this. The update is slow (most probably because it works off
> > the post-command-hook), and the UX is therefore extremely unpleasant
> > if you type fast enough.
>
> Interesting. Can you say more about what completion you're doing for
> which the update is slow?
I started by typing "C-x C-f TAB".
> I would have expected the while-no-input to cause the update to not
> block you if you type fast.
while-no-input lets me type, but does nothing to speed up the updates
of the *Completions* buffer; quite the contrary: it leaves it
outdated.
> >> + (while-no-input
> >> + (let ((non-essential t))
> > ^^^^^^^^^^^^^^^
> > Why?
>
> This I borrowed from zcomplete. It seems sensible, since
> non-essential's docstring says:
>
> E.g., it can be used to prevent Tramp from prompting the user for a
> password when we are [...] displaying possible completions before the
> user even asked for it.
So completion on remote files will not be able to benefit from this?
> >> + (when (and (get-buffer-window "*Completions*" 0)
> >> + (not (memq this-command completions-no-auto-update-commands)))
> >> + (redisplay)
> > ^^^^^^^^^^^
> > Why do you need this?
>
> post-command-hook's docstring says:
>
> It is a bad idea to use this hook for expensive processing. If
> unavoidable, wrap your code in ‘(while-no-input (redisplay) CODE)’ to
> avoid making Emacs unresponsive while the user types.
Did you try this without the 'redisplay' call?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-15 15:55 ` sbaugh
2023-10-16 11:38 ` Eli Zaretskii
@ 2023-10-16 12:16 ` sbaugh
2023-10-17 18:23 ` Juri Linkov
1 sibling, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-10-16 12:16 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 354 bytes --]
sbaugh@catern.com writes:
> But actually, even without completions-auto-update, it would be
> generally useful to not lose the location of point in *Completions*.
> So I'll just implement that as a separate patch.
Here's this; it's independently useful and independently installable.
Should be a nice, if a bit niche, improvement to behavior.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Keep-point-on-the-same-completion-in-the-completions.patch --]
[-- Type: text/x-patch, Size: 12752 bytes --]
From 64c08696755c29d2d9125734865ef93af6833fef Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Sun, 15 Oct 2023 16:47:16 -0400
Subject: [PATCH] Keep point on the same completion in the completions buffer
Currently if the user re-runs minibuffer-completion-help, point is
reset to the beginning of the buffer. This throws away information
unnecessarily; let's keep point on the same completion the user
previously selected.
We move setting cursor-face-highlight-nonselected-window to
completion-setup-function so that the selected completion continues to
be highlighted after minibuffer-completion-help, which creates a new
*Completions* buffer.
* lisp/minibuffer.el (completion--insert-strings)
(completion--selected-posn, completion--insert-horizontal)
(completion--insert-vertical, completion--insert-one-column)
(completion--insert, display-completion-list): Add SELECTED argument.
(minibuffer-next-completion): Don't set
cursor-face-highlight-nonselected-window.
(minibuffer-completion-help): Calculate current-completion and pass it
to display-completion-list.
* lisp/simple.el (completions--get-posn): Add.
(choose-completion): Call completions--get-posn.
(completion-setup-function): Set
cursor-face-highlight-nonselected-window.
---
lisp/minibuffer.el | 64 +++++++++++++++++++++++++++++++---------------
lisp/simple.el | 41 ++++++++++++++++-------------
2 files changed, 66 insertions(+), 39 deletions(-)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 2120e31775e..998ef9f05a9 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2034,12 +2034,17 @@ completions-header-format
(string :tag "Format string for heading line"))
:version "29.1")
-(defun completion--insert-strings (strings &optional group-fun)
+(defvar completion--selected-posn)
+
+(defun completion--insert-strings (strings &optional group-fun selected)
"Insert a list of STRINGS into the current buffer.
The candidate strings are inserted into the buffer depending on the
completions format as specified by the variable `completions-format'.
Runs of equal candidate strings are eliminated. GROUP-FUN is a
-`group-function' used for grouping the completion candidates."
+`group-function' used for grouping the completion candidates.
+
+If SELECTED exists in STRINGS, point is set to its first
+instance; otherwise, it's set to `point-min'."
(when (consp strings)
(let* ((length (apply #'max
(mapcar (lambda (s)
@@ -2055,18 +2060,20 @@ completion--insert-strings
;; Don't allocate more columns than we can fill.
;; Windows can't show less than 3 lines anyway.
(max 1 (/ (length strings) 2))))
- (colwidth (/ wwidth columns)))
+ (colwidth (/ wwidth columns))
+ completion--selected-posn)
(unless (or tab-stop-list (null completion-tab-width)
(zerop (mod colwidth completion-tab-width)))
;; Align to tab positions for the case
;; when the caller uses tabs inside prefix.
(setq colwidth (- colwidth (mod colwidth completion-tab-width))))
(funcall (intern (format "completion--insert-%s" completions-format))
- strings group-fun length wwidth colwidth columns))))
+ strings group-fun length wwidth colwidth columns selected)
+ (goto-char (or completion--selected-posn (point-min))))))
(defun completion--insert-horizontal (strings group-fun
length wwidth
- colwidth _columns)
+ colwidth _columns selected)
(let ((column 0)
(first t)
(last-title nil)
@@ -2103,7 +2110,7 @@ completion--insert-horizontal
`(display (space :align-to ,column)))
nil))
(setq first nil)
- (completion--insert str group-fun)
+ (completion--insert str group-fun selected)
;; Next column to align to.
(setq column (+ column
;; Round up to a whole number of columns.
@@ -2111,7 +2118,7 @@ completion--insert-horizontal
(defun completion--insert-vertical (strings group-fun
_length _wwidth
- colwidth columns)
+ colwidth columns selected)
(while strings
(let ((group nil)
(column 0)
@@ -2155,13 +2162,15 @@ completion--insert-vertical
(insert " \t")
(set-text-properties (1- (point)) (point)
`(display (space :align-to ,column))))
- (completion--insert str group-fun)
+ (completion--insert str group-fun selected)
(if (> column 0)
(forward-line)
(insert "\n"))
(setq row (1+ row)))))))
-(defun completion--insert-one-column (strings group-fun &rest _)
+(defun completion--insert-one-column (strings group-fun
+ _length _wwidth
+ _colwidth _columns selected)
(let ((last-title nil) (last-string nil))
(dolist (str strings)
(unless (equal last-string str) ; Remove (consecutive) duplicates.
@@ -2172,11 +2181,14 @@ completion--insert-one-column
(setq last-title title)
(when title
(insert (format completions-group-format title) "\n")))))
- (completion--insert str group-fun)
+ (completion--insert str group-fun selected)
(insert "\n")))
(delete-char -1)))
-(defun completion--insert (str group-fun)
+(defun completion--insert (str group-fun selected)
+ (when (and (not completion--selected-posn)
+ (equal (or (car-safe str) str) selected))
+ (setq completion--selected-posn (point)))
(if (not (consp str))
(add-text-properties
(point)
@@ -2197,7 +2209,7 @@ completion--insert
(let ((beg (point))
(end (progn (insert prefix) (point))))
(add-text-properties beg end `(mouse-face nil completion--string ,(car str)))))
- (completion--insert (car str) group-fun)
+ (completion--insert (car str) group-fun selected)
(let ((beg (point))
(end (progn (insert suffix) (point))))
(add-text-properties beg end `(mouse-face nil completion--string ,(car str)))
@@ -2267,7 +2279,7 @@ completion-hilit-commonality
completions)
base-size))))
-(defun display-completion-list (completions &optional common-substring group-fun)
+(defun display-completion-list (completions &optional common-substring group-fun selected)
"Display the list of completions, COMPLETIONS, using `standard-output'.
Each element may be just a symbol or string
or may be a list of two strings to be printed as if concatenated.
@@ -2276,6 +2288,8 @@ display-completion-list
`standard-output' must be a buffer.
The actual completion alternatives, as inserted, are given `mouse-face'
properties of `highlight'.
+If SELECTED exists in COMPLETIONS, point is set to its first
+instance; otherwise, it's set to `point-min'.
At the end, this runs the normal hook `completion-setup-hook'.
It can find the completion buffer in `standard-output'.
GROUP-FUN is a `group-function' used for grouping the completion
@@ -2299,9 +2313,15 @@ display-completion-list
(goto-char (point-max))
(when completions-header-format
(insert (format completions-header-format (length completions))))
- (completion--insert-strings completions group-fun)))
-
- (run-hooks 'completion-setup-hook)
+ (completion--insert-strings completions group-fun selected)))
+
+ ;; Make sure point stays at SELECTED.
+ (let ((marker
+ (when (bufferp standard-output)
+ (with-current-buffer standard-output (point-marker)))))
+ (run-hooks 'completion-setup-hook)
+ (when marker
+ (with-current-buffer standard-output (goto-char marker))))
nil)
(defvar completion-extra-properties nil
@@ -2421,7 +2441,10 @@ minibuffer-completion-help
;; window, mark it as softly-dedicated, so bury-buffer in
;; minibuffer-hide-completions will know whether to
;; delete the window or not.
- (display-buffer-mark-dedicated 'soft))
+ (display-buffer-mark-dedicated 'soft)
+ (current-completion
+ (when-let ((buf (get-buffer "*Completions*")))
+ (with-current-buffer buf (completions--get-posn (point))))))
(with-current-buffer-window
"*Completions*"
;; This is a copy of `display-buffer-fallback-action'
@@ -2440,7 +2463,7 @@ minibuffer-completion-help
,(when temp-buffer-resize-mode
'(preserve-size . (nil . t)))
(body-function
- . ,#'(lambda (_window)
+ . ,#'(lambda (window)
(with-current-buffer mainbuf
;; Remove the base-size tail because `sort' requires a properly
;; nil-terminated list.
@@ -2527,7 +2550,8 @@ minibuffer-completion-help
(if (eq (car bounds) (length result))
'exact 'finished)))))))
- (display-completion-list completions nil group-fun)))))
+ (display-completion-list completions nil group-fun current-completion)
+ (set-window-point window (with-current-buffer standard-output (point)))))))
nil)))
nil))
@@ -4496,8 +4520,6 @@ minibuffer-next-completion
(interactive "p")
(let ((auto-choose minibuffer-completion-auto-choose))
(with-minibuffer-completions-window
- (when completions-highlight-face
- (setq-local cursor-face-highlight-nonselected-window t))
(next-completion (or n 1))
(when auto-choose
(let ((completion-use-base-affixes t))
diff --git a/lisp/simple.el b/lisp/simple.el
index ec14bec9e07..3ab8b783659 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -10000,6 +10000,25 @@ next-completion
(when (/= 0 n)
(switch-to-minibuffer))))
+(defun completions--get-posn (position)
+ "Return the completion at POSITION as a string."
+ (save-excursion
+ (goto-char position)
+ (let (beg)
+ (cond
+ ((and (not (eobp))
+ (get-text-property (point) 'completion--string))
+ (setq beg (1+ (point))))
+ ((and (not (bobp))
+ (get-text-property (1- (point)) 'completion--string))
+ (setq beg (point))))
+ (when beg
+ (setq beg (or (previous-single-property-change
+ beg 'completion--string)
+ beg))
+ (substring-no-properties
+ (get-text-property beg 'completion--string))))))
+
(defun choose-completion (&optional event no-exit no-quit)
"Choose the completion at point.
If EVENT, use EVENT's position to determine the starting position.
@@ -10019,24 +10038,8 @@ choose-completion
(base-affixes completion-base-affixes)
(insert-function completion-list-insert-choice-function)
(completion-no-auto-exit (if no-exit t completion-no-auto-exit))
- (choice
- (save-excursion
- (goto-char (posn-point (event-start event)))
- (let (beg)
- (cond
- ((and (not (eobp))
- (get-text-property (point) 'completion--string))
- (setq beg (1+ (point))))
- ((and (not (bobp))
- (get-text-property (1- (point)) 'completion--string))
- (setq beg (point)))
- (t (error "No completion here")))
- (setq beg (or (previous-single-property-change
- beg 'completion--string)
- beg))
- (substring-no-properties
- (get-text-property beg 'completion--string))))))
-
+ (choice (or (completions--get-posn (posn-point (event-start event)))
+ (error "No completion here"))))
(unless (buffer-live-p buffer)
(error "Destination buffer is dead"))
(unless no-quit
@@ -10208,6 +10211,8 @@ completion-setup-function
(base-affixes completion-base-affixes)
(insert-fun completion-list-insert-choice-function))
(completion-list-mode)
+ (when completions-highlight-face
+ (setq-local cursor-face-highlight-nonselected-window t))
(setq-local completion-base-position base-position)
(setq-local completion-base-affixes base-affixes)
(setq-local completion-list-insert-choice-function insert-fun))
--
2.41.0
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-16 11:38 ` Eli Zaretskii
@ 2023-10-16 14:50 ` Michael Albinus
2023-10-16 15:58 ` [External] : " Drew Adams
0 siblings, 1 reply; 107+ messages in thread
From: Michael Albinus @ 2023-10-16 14:50 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: sbaugh, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
Hi Eli,
>> >> + (while-no-input
>> >> + (let ((non-essential t))
>> > ^^^^^^^^^^^^^^^
>> > Why?
>>
>> This I borrowed from zcomplete. It seems sensible, since
>> non-essential's docstring says:
>>
>> E.g., it can be used to prevent Tramp from prompting the user for a
>> password when we are [...] displaying possible completions before the
>> user even asked for it.
>
> So completion on remote files will not be able to benefit from this?
No, remote files are not kicked out by this. non-essential just prevents
to open a *new* connection during the completion phase, when there
doesn't exist one already. If the connection exists already,
non-essential isn't relevant.
However, I believe it isn't needed here. Updating *Completions* will
happen only if a completion package is active. And they bind
non-essential already.
Best regards, Michael.
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-16 14:50 ` Michael Albinus
@ 2023-10-16 15:58 ` Drew Adams
0 siblings, 0 replies; 107+ messages in thread
From: Drew Adams @ 2023-10-16 15:58 UTC (permalink / raw)
To: Michael Albinus, Eli Zaretskii; +Cc: sbaugh@catern.com, emacs-devel@gnu.org
> > So completion on remote files will not be able
> > to benefit from this?
>
> No, remote files are not kicked out by this.
> non-essential just prevents to open a *new*
> connection during the completion phase
FWIW:
Icicles incremental completion is effectively turned
off whenever a remote file name is read, that is,
whenever your file-name input matches a remote-file
syntax. (You can turn it back on using `C-#'.)
Option `icicle-test-for-remote-files-flag' controls this.
By default it's non-nil.
Non-nil means Icicles tests for remote file names.
A value of nil turns off all handling of remote file
names by Tramp, including file-name completion.
The testing due to a non-nil value takes a little time,
but the test result saves time with Tramp handling, and
it is used to avoid some other costly operations when a
file is determined to be remote. These operations are
(a) incremental completion and (b) highlighting of the
part of your current input that does not complete.
Use a nil value only when you are sure that the file
names you are completing are local. The effect will be
a slight speed increase for operations (a) and (b) for
local files. You can toggle this option from the
minibuffer using `C-^'.
IOW, if you know that you won't be using remote file
names for a while, you can let Icicles and Tramp know
this by using `C-^' in the minibuffer to turn off the
option.
The "remote" test used is essentially `file-remote-p',
except that on MS Windows non-nil option
`icicle-network-drive-means-remote-flag' means consider
also files on a mapped network drive to be remote.
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-16 9:25 ` Philip Kaludercic
@ 2023-10-16 16:03 ` Drew Adams
2023-10-20 7:45 ` Philip Kaludercic
2023-10-16 22:55 ` Emanuel Berg
1 sibling, 1 reply; 107+ messages in thread
From: Drew Adams @ 2023-10-16 16:03 UTC (permalink / raw)
To: Philip Kaludercic; +Cc: Spencer Baugh, emacs-devel@gnu.org
I'm not asking you, or anyone, to use Icicles.
Unfortunately, talking about its features can
perhaps give the opposite impression.
As I tried to make clear in my posts, their aim
was to mention various Icicles features I think
are relevant to this thread - not to advertise
Icicles or suggest its use.
The point was to encourage consideration of such
or similar features as useful and perhaps worth
adding to vanilla Emacs. Nothing more.
Icicles is just a reference point here. Its doc
about such features might hopefully provide some
food for thought. _What users can do_ is the
point, not how such features can be implemented.
It's good to see others coming around to similar
feature ideas now. Knowledge that such features
work _in combination_, and they have done so for
quite a while, should be helpful, I hope.
___
Wrt la petite histoire -
To my knowledge, the first appearance of any
incremental completion was in icomplete-mode.
But that wasn't a completion whose result you
could _use_; it was only completion you could
_see_ (and only a few completions). You could
use it only as a guide/preview of what you could
then type. (Much later, completion of input was
finally added to icomplete-mode.)
Next was IswitchB, which later became the model
for Ido. Completion candidates were shown only
in the minibuffer (and again, only a few) - no
use of *Completions* to show candidates.
Icicles came after icomplete-mode and IswitchB,
and before Ido. It introduced incremental
completion showing candidates in *Completions*;
cycling among candidates (notion of "current"
candidate); on-the-fly sorting of them; etc.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-15 20:31 ` Eshel Yaron
2023-10-16 3:18 ` [External] : " Drew Adams
@ 2023-10-16 16:54 ` Juri Linkov
1 sibling, 0 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-16 16:54 UTC (permalink / raw)
To: Eshel Yaron; +Cc: sbaugh, emacs-devel
> I tried this out, and I came across a certain issue: say you do
> `C-h o foo TAB`, and then looking at the completion candidates
> you realize you actually wanted something with `bar`, so you
> type `M-DEL` to delete `foo` from the minibuffer to make room
> for `bar`. But now `post-command-hook` runs with an empty
> minibuffer before you start typing `bar`, so it updates the
> completions buffer with a very large list of symbols, causing
> Emacs to briefly stall. I think that the completions buffer
> possibly shouldn't be updated when the minibuffer is empty.
This looks like icomplete-show-matches-on-no-input.
> Perhaps there could be a minimum minibuffer contents size for
> updating the completions buffer, or some other heuristic to
> avoid auto-displaying excessively large sets of candidates.
And this is like icomplete-max-delay-chars.
> Another option is to update the completions buffer on
> `post-self-insert-hook` instead of `post-command-hook`, that
> way you only update the completions buffer when the user
> actually inserts input in the minibuffer, and you don't need to
> keep a `completions-no-auto-update-commands` list.
Is `post-self-insert-hook` called for pasting a string?
Maybe better to replace blocklist with allowlist that contains
a list '(self-insert-command yank)' by default as discussed in
https://yhetil.org/emacs-devel/87eefp18q2.fsf@gnu.org/
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-15 7:32 ` Juri Linkov
@ 2023-10-16 19:28 ` Rudolf Adamkovič
2023-10-17 18:38 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Rudolf Adamkovič @ 2023-10-16 19:28 UTC (permalink / raw)
To: emacs-devel; +Cc: Juri Linkov, sbaugh
Juri Linkov <juri@linkov.net> writes:
> Thank you very much for finally bringing this useful feature to the core
> while keeping it sufficiently short.
I, too, would like to see both automatic updates and MRU sorting in the
default minibuffer completion UI. I hacked together both for myself,
only to return to Vertico for its incredible performance. So, I think
that automatic updates must be fast, ideally as fast as Vertico.
It is also worth noting that the recent "restart" of MCT development
indicates that there is wider interest in this functionality:
https://git.sr.ht/~protesilaos/mct/commit/2cbf74edb4f4553d7075b34e06adcf59e96efda2
Rudy
--
"Be especially critical of any statement following the word
'obviously.'"
-- Anna Pell Wheeler, 1883-1966
Rudolf Adamkovič <salutis@me.com> [he/him]
Studenohorská 25
84103 Bratislava
Slovakia
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: [External] : Re: Updating *Completions* as you type
2023-10-16 9:25 ` Philip Kaludercic
2023-10-16 16:03 ` Drew Adams
@ 2023-10-16 22:55 ` Emanuel Berg
2023-10-17 6:09 ` Emanuel Berg
1 sibling, 1 reply; 107+ messages in thread
From: Emanuel Berg @ 2023-10-16 22:55 UTC (permalink / raw)
To: emacs-devel
Philip Kaludercic wrote:
> You have mentioned Icicles a number of times, and one of the
> main reasons I have never tried it out is that it is not
> available on ELPA or any kind of official repository.
> I believe wrote about this a while back, but according to
> [...], the main issue remains that your libraries overwrite
> Emacs primitives, as you mention in the main file:
>
> ;; ***** NOTE: These EMACS PRIMITIVES have been REDEFINED in Icicles:
> ;;
> ;; `completing-read' - (See below and doc string.)
> ;; `display-completion-list' - (See below and doc string.)
> ;; `exit-minibuffer' - Remove *Completion* window.
> ;; `minibuffer-complete-and-exit' - Remove *Completion* window.
> ;; `read-file-name' - (See below and doc string.)
> ;; `read-from-minibuffer' - (See below and doc string.)
> ;; `read-string' - (See below and doc string.)
Meta-Note: If "Emacs primitive" equals a "built-in" function
equals a function written in C, then
`display-completion-list', `exit-minibuffer',
`minibuffer-complete-and-exit', and `read-file-name' are
actually ordinary Lisp functions, written in Lisp.
Is the reason Icicles is not a package in GNU ELPA that it
redefines functions? If so, see if one can reduce the number
of such cases one by one.
I say this because I have some experience from similar
situations where you feel there is a whole bunch of things to
do, and it feels impossible, almost. After removing one such
case, it still feels that way. But after removing two, it
already feels much better and after removing three, in terms
of how you mentally experience the task, it is done, almost.
--
underground experts united
https://dataswamp.org/~incal
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-12 23:53 Updating *Completions* as you type sbaugh
` (2 preceding siblings ...)
2023-10-13 18:11 ` Updating *Completions* as you type Daniel Semyonov
@ 2023-10-17 0:44 ` Michael Heerdegen
3 siblings, 0 replies; 107+ messages in thread
From: Michael Heerdegen @ 2023-10-17 0:44 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
sbaugh@catern.com writes:
> It would be nice if there was a built-in customization which caused
> *Completions* to update as you type, as long as that buffer is visible.
AFAIU this sounds very much like "aggressive-completion" in Gnu Elpa.
Michael.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: [External] : Re: Updating *Completions* as you type
2023-10-16 22:55 ` Emanuel Berg
@ 2023-10-17 6:09 ` Emanuel Berg
0 siblings, 0 replies; 107+ messages in thread
From: Emanuel Berg @ 2023-10-17 6:09 UTC (permalink / raw)
To: emacs-devel
>> ;; ***** NOTE: These EMACS PRIMITIVES have been REDEFINED in Icicles:
>> ;;
>> ;; `completing-read' - (See below and doc string.)
>> ;; `display-completion-list' - (See below and doc string.)
>> ;; `exit-minibuffer' - Remove *Completion* window.
>> ;; `minibuffer-complete-and-exit' - Remove *Completion* window.
>> ;; `read-file-name' - (See below and doc string.)
>> ;; `read-from-minibuffer' - (See below and doc string.)
>> ;; `read-string' - (See below and doc string.)
>
> Meta-Note: If "Emacs primitive" equals a "built-in" function
> equals a function written in C, then
> `display-completion-list', `exit-minibuffer',
> `minibuffer-complete-and-exit', and `read-file-name' are
> actually ordinary Lisp functions, written in Lisp.
And all those are in minibuffer.el.
--
underground experts united
https://dataswamp.org/~incal
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 20:05 ` sbaugh
` (2 preceding siblings ...)
2023-10-15 20:31 ` Eshel Yaron
@ 2023-10-17 13:48 ` sbaugh
2023-10-17 18:35 ` Juri Linkov
2023-10-20 6:49 ` Juri Linkov
4 siblings, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-10-17 13:48 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 3751 bytes --]
sbaugh@catern.com writes:
>>> That being said, yes this may be nice. But minibuffer-completion-help
>>> already does sort the completions using display-sort-function, just like
>>> completion-all-sorted-completions, so what's causing the difference in
>>> behavior?
>>
>> It seems this is implementable in minibuffer-completion-help
>> by copying this code from completion-all-sorted-completions:
>>
>> (setq all (minibuffer--sort-by-position
>> (minibuffer--sort-preprocess-history
>> (substring string 0 base-size))
>> all))
>
>Oh, very interesting! Maybe completions-sort should accept a new symbol
>'history to behave this way?
>
>I already think this would be very nice for project-switch-project, for
>example, since I'm often switching between a few related projects.
>
>Perhaps 'history should break ties by alphabetizing, otherwise
>e.g. filenames you haven't visited before would be unsorted randomly.
>
>Hmm, actually the case of filenames is a bit complex. Because for
>filenames, the strings we're completing over don't appear verbatim in
>the history. So perhaps read-file-name would need its own specialized
>sorting function, which whenever you're completing in some directory,
>sorts to the front any files in that directory whose full path appears
>in file-name-history.
>
>>> Honestly the main place I find myself wanting different sorting of
>>> completions is for buffer completion - I'd prefer buffers to be sorted
>>> by most-recently-used. Maybe we can just add such an option?
>>
>> Such an option would be nice. Maybe the right way to support it
>> is to add a new sort function with the code above. Then the caller
>> could provide such a function in the completion metadata.
>
>Oh, that's also interesting. So there would be a function that the
>completion metadata could specify as display-sort-function, which would
>have the behavior of sorting based on history?
>
>That also makes a lot of sense, and would allow commands like
>project-switch-project and read-buffer to opt in on a command-by-command
>basis, which might be more sensible.
>
>So maybe adding 'history as a new option for completions-sort isn't a
>good idea. Instead we should just add user options for enabling history
>sorting for files and buffers. (And perhaps we could just enable
>history sorting by default for project-switch-project.)
>
>Also: it might be nice to switch between history-sorting and
>alphabetized-sorting during the course of completion, both for files and
>buffers. Maybe we could do that by making a command which puts
>completion into a mode where it just ignores the display-sort-function
>specified by the completion metadata, and just always uses
>completions-sort.
On reflection, I think adding a new option for completions-sort is
indeed what we should do. Otherwise, we won't get historical sorting
for non-programmed completing-read, which is a pretty common kind of
completing-read. Here's a patch to do that.
We can always add display-sort-functions later for buffers and files, if
that ends up being desirable.
Also, tangentially, I think probably we should rework
minibuffer-complete-history and minibuffer-complete-defaults to be
persistent - as in, regular TAB afterwards continues to complete history
or defaults. And there should be some way to reset back to normal.
That would be a good complement to this completions-sort change, by
maybe giving a way to switch on-demand to alphabetical sorting. (I've
long thought this would be good and useful, but in particular it's
relevant for completions-auto-update since that will otherwise nearly
immediately reset the displayed completions back to normal.)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-a-historical-option-to-completions-sort.patch --]
[-- Type: text/x-patch, Size: 3851 bytes --]
From b97e311ee42f7f9021b3c0e017636e258dd6d5d9 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Tue, 17 Oct 2023 09:09:55 -0400
Subject: [PATCH] Add a historical option to completions-sort
This causes completion to sort based on history. This is useful for
getting, e.g., most-recently-used order from C-x b.
We only do historical sorting when there's a completion-specific
history variable. Otherwise, candidate would be spuriously brought to
the front if they just happened to match a string that the user has
entered before.
Also, the presence of a completion-specific history variable is a
decent proxy for "does history matter for this command?"; if there
isn't a specific history variable, sorting based on history would
probably be undesirable. (Note also that the user can always choose
to do historical sorting mid-completion by running
minibuffer-complete-history.)
* lisp/minibuffer.el (completions-sort): Document 'historical option.
(minibuffer-completion-help): Support 'historical option.
---
lisp/minibuffer.el | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index f53cd739e2f..782efff80f9 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1313,14 +1313,26 @@ completion-cycle-threshold
(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."
+Candidate completions in the *Completions* are sorted depending
+on the value.
+
+If nil, sorting is disabled.
+If `alphabetical', candidates are sorted alphabetically.
+If `historical', candidates are first sorted alphabetically, then
+candidates occurring in `minibuffer-history-variable' are moved
+to the front based on the order they occur in the history.
+If a function, the function is called to sort the candidates.
+The sorting function takes and returns a list of completion
+candidate strings.
+
+If the completion-specific metadata provides a
+`display-sort-function', that is used instead and this value is
+ignored."
: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.
@@ -2510,6 +2522,15 @@ minibuffer-completion-help
(pcase completions-sort
('nil completions)
('alphabetical (sort completions #'string-lessp))
+ ('historical
+ (let ((alphabetized (sort completions #'string-lessp)))
+ ;; Only use history when it's specific to these completions.
+ (if (eq minibuffer-history-variable 'minibuffer-history)
+ alphabetized
+ (minibuffer--sort-by-position
+ (minibuffer--sort-preprocess-history
+ (substring string 0 base-size))
+ alphabetized))))
(_ (funcall completions-sort completions)))))
;; After sorting, group the candidates using the
--
2.41.0
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 16:58 ` Juri Linkov
2023-10-14 20:05 ` sbaugh
@ 2023-10-17 15:01 ` sbaugh
2023-10-17 18:20 ` Juri Linkov
1 sibling, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-10-17 15:01 UTC (permalink / raw)
To: emacs-devel
Tangentially, Juri, I have a thought about a redesign of
minibuffer-next-completion and minibuffer-choose-completion.
What if the concept of "current selected completion" was unified with
"the default completion"? This could be a nice, general UI.
Specifically, with switch-to-buffer and a default of init.el:
- If init.el is present in *Completions*, start out with point on it.
This would be purely a display nicety, it wouldn't actually affect
anything yet. (This would be easy with my patch which I posted
elsewhere in this thread to preserve the location of point in
*Completions*)
- If and when the user invokes minibuffer-next-completion:
- The default changes to whatever the new selected completion is
- The prompt text "(default init.el)" changes permanently to literally
"(default selected completion)"
- RET, as always, chooses the default if the minibuffer is empty; if the
user has done minibuffer-next-completion, the default is the selected
completion, so RET will choose that.
- M-RET (minibuffer-choose-completion) is replaced with a new command
which immediately chooses the default, whatever it is, ignoring the
current contents of the minibuffer
- C-u M-RET inserts the default in the the minibuffer, without exiting
(matching the behavior of C-u minibuffer-choose-completion)
I think this has some nice benefits in reducing the number of concepts
people need to track. If the minibuffer is empty, they can just use
minibuffer-next-completion a few times followed by RET to select a
completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
would be useful even to users who don't use minibuffer-next-completion.
I also think this would make it less painful to set
minibuffer-completion-auto-choose to nil, which matches
completion-in-region better and also works much better with
completions-auto-update.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 15:01 ` sbaugh
@ 2023-10-17 18:20 ` Juri Linkov
2023-10-17 23:37 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-17 18:20 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> What if the concept of "current selected completion" was unified with
> "the default completion"? This could be a nice, general UI.
>
> Specifically, with switch-to-buffer and a default of init.el:
>
> - If init.el is present in *Completions*, start out with point on it.
> This would be purely a display nicety, it wouldn't actually affect
> anything yet. (This would be easy with my patch which I posted
> elsewhere in this thread to preserve the location of point in
> *Completions*)
I think preselecting the default value in the middle of completions
would make sense only when completions were sorted by the order of the
list of default values (from M-n M-n ...). Then the first default value
would be at the top of completions, and it would easier for users
to navigate completions top-down.
> - If and when the user invokes minibuffer-next-completion:
> - The default changes to whatever the new selected completion is
> - The prompt text "(default init.el)" changes permanently to literally
> "(default selected completion)"
Changing the prompt might interfere with such packages as minibuf-eldef.el
and other cases of customized minibuffer-default-prompt-format.
Also this might break commands that manually handle the default value
for empty input.
> - RET, as always, chooses the default if the minibuffer is empty; if the
> user has done minibuffer-next-completion, the default is the selected
> completion, so RET will choose that.
> - M-RET (minibuffer-choose-completion) is replaced with a new command
> which immediately chooses the default, whatever it is, ignoring the
> current contents of the minibuffer
What should RET do after the user navigated in *Completions* and
switched back to the minibuffer. A different candidate is highlighted
in *Completions*, while the default value remains unchanged.
BTW, while looking at this case I found a problem with your first patch:
after navigating in *Completions* and switching back to the minibuffer
point is reset to the beginning of the *Completions* buffer.
> - C-u M-RET inserts the default in the the minibuffer, without exiting
> (matching the behavior of C-u minibuffer-choose-completion)
Usually the default is inserted by M-n.
> I think this has some nice benefits in reducing the number of concepts
> people need to track. If the minibuffer is empty, they can just use
> minibuffer-next-completion a few times followed by RET to select a
> completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
> would be useful even to users who don't use minibuffer-next-completion.
It seems this is intended to solve the problem of a mismatch between
the highlighted candidate and the contents of the minibuffer?
Such problem exists, for example, in icomplete-mode where
RET returns the contents of the minibuffer, so a special key 'C-j'
is dedicated to select the highlighted candidate. For selecting
a highlighted candidate from *Completions* such key is 'M-RET'.
> I also think this would make it less painful to set
> minibuffer-completion-auto-choose to nil, which matches
> completion-in-region better and also works much better with
> completions-auto-update.
Sorry, I don't understand how this would make
minibuffer-completion-auto-choose=nil less painful.
Since there is no concept of the default value for completion-in-region,
'M-RET' is the only way to choose the highlighted candidate.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-16 12:16 ` sbaugh
@ 2023-10-17 18:23 ` Juri Linkov
2023-10-18 23:27 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-17 18:23 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> Currently if the user re-runs minibuffer-completion-help, point is
> reset to the beginning of the buffer. This throws away information
> unnecessarily; let's keep point on the same completion the user
> previously selected.
Are you sure everyone would want to always preselect the previous
candidate in the middle of completions in every new completion?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 13:48 ` sbaugh
@ 2023-10-17 18:35 ` Juri Linkov
2023-10-17 22:57 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-17 18:35 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> On reflection, I think adding a new option for completions-sort is
> indeed what we should do. Otherwise, we won't get historical sorting
> for non-programmed completing-read, which is a pretty common kind of
> completing-read. Here's a patch to do that.
> We can always add display-sort-functions later for buffers and files, if
> that ends up being desirable.
Thanks, this is a nice first step that paves the way to later
additions of display-sort-functions and keys for toggling
sorting in *Completions*.
> Also, tangentially, I think probably we should rework
> minibuffer-complete-history and minibuffer-complete-defaults to be
> persistent - as in, regular TAB afterwards continues to complete history
> or defaults. And there should be some way to reset back to normal.
> That would be a good complement to this completions-sort change, by
> maybe giving a way to switch on-demand to alphabetical sorting. (I've
> long thought this would be good and useful, but in particular it's
> relevant for completions-auto-update since that will otherwise nearly
> immediately reset the displayed completions back to normal.)
I think we should choose a key to toggle completion type between
history/default/regular completion.
> Subject: [PATCH] Add a historical option to completions-sort
>
> This causes completion to sort based on history. This is useful for
> getting, e.g., most-recently-used order from C-x b.
Actually for 'C-x b' I'd prefer to sort buffers by the order of (buffer-list),
not by the order buffers occur in the minibuffer history (that I'd like
to use for everything else).
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-16 19:28 ` Rudolf Adamkovič
@ 2023-10-17 18:38 ` Juri Linkov
0 siblings, 0 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-17 18:38 UTC (permalink / raw)
To: Rudolf Adamkovič; +Cc: emacs-devel, sbaugh
> I, too, would like to see both automatic updates and MRU sorting in the
> default minibuffer completion UI. I hacked together both for myself,
> only to return to Vertico for its incredible performance. So, I think
> that automatic updates must be fast, ideally as fast as Vertico.
>
> It is also worth noting that the recent "restart" of MCT development
> indicates that there is wider interest in this functionality:
>
> https://git.sr.ht/~protesilaos/mct/commit/2cbf74edb4f4553d7075b34e06adcf59e96efda2
Thanks for the link, cross-pollination of ideas would benefit everyone.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 18:35 ` Juri Linkov
@ 2023-10-17 22:57 ` Spencer Baugh
2023-10-18 3:04 ` [External] : " Drew Adams
2023-10-18 6:56 ` Juri Linkov
0 siblings, 2 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-10-17 22:57 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> On reflection, I think adding a new option for completions-sort is
>> indeed what we should do. Otherwise, we won't get historical sorting
>> for non-programmed completing-read, which is a pretty common kind of
>> completing-read. Here's a patch to do that.
>
>> We can always add display-sort-functions later for buffers and files, if
>> that ends up being desirable.
>
> Thanks, this is a nice first step that paves the way to later
> additions of display-sort-functions and keys for toggling
> sorting in *Completions*.
>
>> Also, tangentially, I think probably we should rework
>> minibuffer-complete-history and minibuffer-complete-defaults to be
>> persistent - as in, regular TAB afterwards continues to complete history
>> or defaults. And there should be some way to reset back to normal.
>> That would be a good complement to this completions-sort change, by
>> maybe giving a way to switch on-demand to alphabetical sorting. (I've
>> long thought this would be good and useful, but in particular it's
>> relevant for completions-auto-update since that will otherwise nearly
>> immediately reset the displayed completions back to normal.)
>
> I think we should choose a key to toggle completion type between
> history/default/regular completion.
That works too of course, although it causes some more proliferation of
keys.
I'm curious, what is the intended usage of
minibuffer-complete-{history,defaults}? The fact that they only do a
single completion has made them not very usable for me.
>> Subject: [PATCH] Add a historical option to completions-sort
>>
>> This causes completion to sort based on history. This is useful for
>> getting, e.g., most-recently-used order from C-x b.
>
> Actually for 'C-x b' I'd prefer to sort buffers by the order of (buffer-list),
> not by the order buffers occur in the minibuffer history (that I'd like
> to use for everything else).
Reasonable. I suggest that this should be achieved by adding a
display-sort-function, though. (And... actually, that
display-sort-function could maybe just be identity, since the
completions are generated from buffer-list so they are in that order
anyway?)
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 18:20 ` Juri Linkov
@ 2023-10-17 23:37 ` Spencer Baugh
2023-10-17 23:44 ` Spencer Baugh
2023-10-18 6:51 ` Juri Linkov
0 siblings, 2 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-10-17 23:37 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> What if the concept of "current selected completion" was unified with
>> "the default completion"? This could be a nice, general UI.
>>
>> Specifically, with switch-to-buffer and a default of init.el:
>>
>> - If init.el is present in *Completions*, start out with point on it.
>> This would be purely a display nicety, it wouldn't actually affect
>> anything yet. (This would be easy with my patch which I posted
>> elsewhere in this thread to preserve the location of point in
>> *Completions*)
>
> I think preselecting the default value in the middle of completions
> would make sense only when completions were sorted by the order of the
> list of default values (from M-n M-n ...). Then the first default value
> would be at the top of completions, and it would easier for users
> to navigate completions top-down.
Yes, that was the case that inspired this specific idea: the case where
completions are sorted by the list of defaults, and so the default value
is the first completion.
But it occured to me that there's no reason to limit to just the case
where the default value is the first completion. We can just always
move point to the default wherever it occurs in the completions, as long
as it occurs somewhere. Seems like a nice improvement.
Although I guess it does cause M-<down> to no longer go to the first
completion, and M-<up> to no longer go to the last one. Which is a bit
annoying.
Maybe we should have bindings to move to the first and last completions.
Whatever they are, they should also work in completion-in-region-mode,
though, so M-< and M-> definitely won't work... Maybe M-0 M-<down> to go
to the first, and M-0 M-<up> to go to the last? (Or vice versa?)
>> - If and when the user invokes minibuffer-next-completion:
>> - The default changes to whatever the new selected completion is
>> - The prompt text "(default init.el)" changes permanently to literally
>> "(default selected completion)"
>
> Changing the prompt might interfere with such packages as minibuf-eldef.el
> and other cases of customized minibuffer-default-prompt-format.
I think as long as we use format-prompt, minibuf-eldef.el and customized
values of minibuffer-default-prompt-format will still work. Something
to be careful about though. Changing the prompt text isn't essential,
anyway - it may just be a bit confusing if it's not changed.
> Also this might break commands that manually handle the default value
> for empty input.
As long as the default value is present in the completions, the user can
always select it again. Or the user can always just do M-n to select
the original default value - I don't expect this would change that.
>> - RET, as always, chooses the default if the minibuffer is empty; if the
>> user has done minibuffer-next-completion, the default is the selected
>> completion, so RET will choose that.
>> - M-RET (minibuffer-choose-completion) is replaced with a new command
>> which immediately chooses the default, whatever it is, ignoring the
>> current contents of the minibuffer
>
> What should RET do after the user navigated in *Completions* and
> switched back to the minibuffer. A different candidate is highlighted
> in *Completions*, while the default value remains unchanged.
RET should probably choose the highlighted candidate in *Completions* in
that case.
BTW to be clear I don't mean that we would actually change
minibuffer-default; just that RET with an empty minibuffer would provide
the current selected completion rather than minibuffer-default.
> BTW, while looking at this case I found a problem with your first patch:
> after navigating in *Completions* and switching back to the minibuffer
> point is reset to the beginning of the *Completions* buffer.
Good catch! If you see my other patch which I posted in this thread,
"Keep point on the same completion in the completions buffer", that is a
nice orthogonal improvement which incidentally also fixes that bug in
completions-auto-update.
>> - C-u M-RET inserts the default in the the minibuffer, without exiting
>> (matching the behavior of C-u minibuffer-choose-completion)
>
> Usually the default is inserted by M-n.
True, and I don't expect to change that. I guess that's probably
sufficient.
OK, so maybe the thing I want to propose is not "we'll change the
default to whatever the current selected completion is" but instead "RET
with an empty minibuffer will submit the current selected completion".
That's equivalent, if I drop the ideas of changing the prompt and
changing M-RET.
>> I think this has some nice benefits in reducing the number of concepts
>> people need to track. If the minibuffer is empty, they can just use
>> minibuffer-next-completion a few times followed by RET to select a
>> completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
>> would be useful even to users who don't use minibuffer-next-completion.
>
> It seems this is intended to solve the problem of a mismatch between
> the highlighted candidate and the contents of the minibuffer?
> Such problem exists, for example, in icomplete-mode where
> RET returns the contents of the minibuffer, so a special key 'C-j'
> is dedicated to select the highlighted candidate. For selecting
> a highlighted candidate from *Completions* such key is 'M-RET'.
True, good analysis.
Specifically though it's about the case when the minibuffer is empty. I
think it would be nice for RET to submit the highlighted candidate in
that case, if there is one.
That matches icomplete-mode's behavior, actually, which is nice.
>> I also think this would make it less painful to set
>> minibuffer-completion-auto-choose to nil, which matches
>> completion-in-region better and also works much better with
>> completions-auto-update.
>
> Sorry, I don't understand how this would make
> minibuffer-completion-auto-choose=nil less painful.
>
> Since there is no concept of the default value for completion-in-region,
> 'M-RET' is the only way to choose the highlighted candidate.
Eh, this aspect is probably specific to me.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 23:37 ` Spencer Baugh
@ 2023-10-17 23:44 ` Spencer Baugh
2023-10-18 6:51 ` Juri Linkov
1 sibling, 0 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-10-17 23:44 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Spencer Baugh <sbaugh@catern.com> writes:
> That matches icomplete-mode's behavior, actually, which is nice.
Oh, actually it doesn't. It matches ido-mode and fido-mode and a host
of completion mechanisms outside core, though. I still think it's
desirable, at least as a user option.
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-17 22:57 ` Spencer Baugh
@ 2023-10-18 3:04 ` Drew Adams
2023-10-18 6:56 ` Juri Linkov
1 sibling, 0 replies; 107+ messages in thread
From: Drew Adams @ 2023-10-18 3:04 UTC (permalink / raw)
To: Spencer Baugh, Juri Linkov; +Cc: emacs-devel@gnu.org
> > I think we should choose a key to toggle completion
> > type between history/default/regular completion.
>
> That works too of course, although it causes some
> more proliferation of keys.
The approach I took in Icicles is preferable, IMO.
Food for thought:
1. There can be any number of sort orders to choose
from at any given time, i.e., in any given context.
For different calls to `completing-read' (e.g.
for different commands), some very different sort
orders can make sense.
And one of the available ways of sorting is to do
nothing - NOT sort the available candidates. This
can be useful if the completion function already
provides them in a useful order, or if any sorting
at all would be expensive for some reason.
2. Instead of wasting multiple keys, one for each
sort-order choice, a single key cycles among them:
`C-,'.
3. For any `completing-read' call there can also be
a set of alternative sort orders. You can toggle
to the current alternative sort using `C-M-,'.
And you can cycle among the available alternative
orders using `M-,' (just like `C-,').
4. Both `C-,' and `M-,' also provide another way to
choose a sort order, besides cycling to it: use
completion to choose it by name.
5. You can choose, with an option, whether, by default,
to (1) always use cycling to choose a sort order,
(2) always use completion, or (3) cycle if there are
fewer than N orders to choose from and complete if
there are N or more.
6. Reversing the current sort order is just `C-,' with
a numeric prefix arg, e.g., `C-9 C-,'.
7. Regardless of your user-option preference (#5), you
can flip to the other kind of choosing as a one-off,
on the fly, using a non-numeric prefix arg. E.g.,
if the option says to use cycling in the current
situation then `C-u C-,' switches to choosing the
order by name (completing).
8. It's very easy for users to define new sort orders.
This is quite important, IMO. It should seem clear,
from your discussion so far, why this makes sense.
9. The available sort orders for `C-,' are defined by
a user option. But commands can adjust this list
of possibilities by adding command-specific sort
orders or removing some that might be inappropriate.
10. The sort order you last chose remains in effect
for subsequent completion (e.g. other commands).
But if the sort order isn't appropriate for some
command it can turn sorting off, in which case
`C-,' lets you choose an appropriate order.
11. IMO, there is no reason at all to have different
sort orders for display and for cycling:
`display-sort-function' and `cycle-sort-function'.
At least I haven't seen (or heard) any reason.
Can anyone say why these aren't the same thing in
Emacs?
And even if there were some use case where someone
might want them to differ, why wouldn't the normal,
default case be for them to be the same (synced)?
You're apparently already beginning to wonder about
a difference between a "current" completion in
*Completions* (the one that's highlighted) and a
"current" completion in the minibuffer, no? Why
let them differ, ever - what's the use case?
In my code (both Icicles and tiny `sortie.el') the
two are the same. The current candidate in the
minibuffer is always the candidate highlighted in
*Completions* (and vice versa - identical).
12. The current sort order, and whether it's reversed,
is indicated in the mode-line of *Completions*, so
you always know what sauce you're being cooked in.
https://www.emacswiki.org/emacs/Icicles_-_Completions_Display#SortOrder
13. I wonder if any of you have even looked at the doc
describing the features I'm talking about. I get
the impression you're maybe starting to re-invent
the wheel, without looking at how existing round
things have been rolling along so far.
https://www.emacswiki.org/emacs/Icicles_-_Sorting_Candidates
(Many of the same sorting features are available with
`sortie.el' as with Icicles. Trying it with library
`keysee.el' is a simple way to see what it's like.)
https://www.emacswiki.org/emacs/Sortie
https://www.emacswiki.org/emacs/KeySee
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 23:37 ` Spencer Baugh
2023-10-17 23:44 ` Spencer Baugh
@ 2023-10-18 6:51 ` Juri Linkov
2023-10-18 12:47 ` Spencer Baugh
1 sibling, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-18 6:51 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
>> I think preselecting the default value in the middle of completions
>> would make sense only when completions were sorted by the order of the
>> list of default values (from M-n M-n ...). Then the first default value
>> would be at the top of completions, and it would easier for users
>> to navigate completions top-down.
>
> Yes, that was the case that inspired this specific idea: the case where
> completions are sorted by the list of defaults, and so the default value
> is the first completion.
>
> But it occured to me that there's no reason to limit to just the case
> where the default value is the first completion. We can just always
> move point to the default wherever it occurs in the completions, as long
> as it occurs somewhere. Seems like a nice improvement.
>
> Although I guess it does cause M-<down> to no longer go to the first
> completion, and M-<up> to no longer go to the last one. Which is a bit
> annoying.
Indeed.
> Maybe we should have bindings to move to the first and last completions.
> Whatever they are, they should also work in completion-in-region-mode,
> though, so M-< and M-> definitely won't work... Maybe M-0 M-<down> to go
> to the first, and M-0 M-<up> to go to the last? (Or vice versa?)
M-< and M-> work in the minibuffer as well as in the normal buffer.
But they don't work with your first patch ;-)
>> BTW, while looking at this case I found a problem with your first patch:
>> after navigating in *Completions* and switching back to the minibuffer
>> point is reset to the beginning of the *Completions* buffer.
>
> Good catch! If you see my other patch which I posted in this thread,
> "Keep point on the same completion in the completions buffer", that is a
> nice orthogonal improvement which incidentally also fixes that bug in
> completions-auto-update.
Your third patch adds a new feature that just hides the bug by forcing
the previous position over the wrong new one. I think the proper fix
would be to add more commands to completions-no-auto-update-commands
in your first patch. Or to change it from opt-out to opt-in by renaming
to completions-auto-update-commands.
> OK, so maybe the thing I want to propose is not "we'll change the
> default to whatever the current selected completion is" but instead "RET
> with an empty minibuffer will submit the current selected completion".
> That's equivalent, if I drop the ideas of changing the prompt and
> changing M-RET.
Agreed, I think the idea of changing the prompt on the fly won't fly.
>>> I think this has some nice benefits in reducing the number of concepts
>>> people need to track. If the minibuffer is empty, they can just use
>>> minibuffer-next-completion a few times followed by RET to select a
>>> completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
>>> would be useful even to users who don't use minibuffer-next-completion.
>>> True, good analysis.
>>
>> Specifically though it's about the case when the minibuffer is empty. I
>> think it would be nice for RET to submit the highlighted candidate in
>> that case, if there is one.
>>
>> That matches icomplete-mode's behavior, actually, which is nice.
>
> Oh, actually it doesn't. It matches ido-mode and fido-mode and a host
> of completion mechanisms outside core, though. I still think it's
> desirable, at least as a user option.
But then such idiosyncrasy of fido-mode causes a lot of bug reports
like bug#55800.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 22:57 ` Spencer Baugh
2023-10-18 3:04 ` [External] : " Drew Adams
@ 2023-10-18 6:56 ` Juri Linkov
2023-10-18 12:25 ` Spencer Baugh
1 sibling, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-18 6:56 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
>>> Also, tangentially, I think probably we should rework
>>> minibuffer-complete-history and minibuffer-complete-defaults to be
>>> persistent - as in, regular TAB afterwards continues to complete history
>>> or defaults. And there should be some way to reset back to normal.
>>> That would be a good complement to this completions-sort change, by
>>> maybe giving a way to switch on-demand to alphabetical sorting. (I've
>>> long thought this would be good and useful, but in particular it's
>>> relevant for completions-auto-update since that will otherwise nearly
>>> immediately reset the displayed completions back to normal.)
>>
>> I think we should choose a key to toggle completion type between
>> history/default/regular completion.
>
> That works too of course, although it causes some more proliferation of
> keys.
>
> I'm curious, what is the intended usage of
> minibuffer-complete-{history,defaults}? The fact that they only do a
> single completion has made them not very usable for me.
The currently limited use case is that you can type a substring,
then TAB and select the completion from the list. You are welcome
to improve this as well.
>> Actually for 'C-x b' I'd prefer to sort buffers by the order of (buffer-list),
>> not by the order buffers occur in the minibuffer history (that I'd like
>> to use for everything else).
>
> Reasonable. I suggest that this should be achieved by adding a
> display-sort-function, though. (And... actually, that
> display-sort-function could maybe just be identity, since the
> completions are generated from buffer-list so they are in that order
> anyway?)
Actually there is already a nil value in completions-sort with the tag
"No sorting". This works nicely for 'C-x b'. The remaining need is
to be able to set it only for 'C-x b', not for other completion types.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 6:56 ` Juri Linkov
@ 2023-10-18 12:25 ` Spencer Baugh
2023-10-18 17:32 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-10-18 12:25 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>>> Also, tangentially, I think probably we should rework
>>>> minibuffer-complete-history and minibuffer-complete-defaults to be
>>>> persistent - as in, regular TAB afterwards continues to complete history
>>>> or defaults. And there should be some way to reset back to normal.
>>>> That would be a good complement to this completions-sort change, by
>>>> maybe giving a way to switch on-demand to alphabetical sorting. (I've
>>>> long thought this would be good and useful, but in particular it's
>>>> relevant for completions-auto-update since that will otherwise nearly
>>>> immediately reset the displayed completions back to normal.)
>>>
>>> I think we should choose a key to toggle completion type between
>>> history/default/regular completion.
>>
>> That works too of course, although it causes some more proliferation of
>> keys.
>>
>> I'm curious, what is the intended usage of
>> minibuffer-complete-{history,defaults}? The fact that they only do a
>> single completion has made them not very usable for me.
>
> The currently limited use case is that you can type a substring,
> then TAB and select the completion from the list. You are welcome
> to improve this as well.
>
>>> Actually for 'C-x b' I'd prefer to sort buffers by the order of (buffer-list),
>>> not by the order buffers occur in the minibuffer history (that I'd like
>>> to use for everything else).
>>
>> Reasonable. I suggest that this should be achieved by adding a
>> display-sort-function, though. (And... actually, that
>> display-sort-function could maybe just be identity, since the
>> completions are generated from buffer-list so they are in that order
>> anyway?)
>
> Actually there is already a nil value in completions-sort with the tag
> "No sorting". This works nicely for 'C-x b'. The remaining need is
> to be able to set it only for 'C-x b', not for other completion types.
I feel quite strongly that we should not extend completions-sort to be
able to affect different completion types differently. Instead I think
we should leave completions-sort as a blanket configuration for what to
do if the completion metadata does not specify display-sort-function,
and if we want to allow customizing an individual completion type, that
completion type should specify a display-sort-function which can be
customized.
If we do extend completions-sort to affect different completion types
differently, I expect we'll see lots of silly things, like packages with
new completion types which automatically install changes to
completions-sort instead of just specifying their own
display-sort-function.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 6:51 ` Juri Linkov
@ 2023-10-18 12:47 ` Spencer Baugh
2023-10-18 17:28 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-10-18 12:47 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>> I think preselecting the default value in the middle of completions
>>> would make sense only when completions were sorted by the order of the
>>> list of default values (from M-n M-n ...). Then the first default value
>>> would be at the top of completions, and it would easier for users
>>> to navigate completions top-down.
>>
>> Yes, that was the case that inspired this specific idea: the case where
>> completions are sorted by the list of defaults, and so the default value
>> is the first completion.
>>
>> But it occured to me that there's no reason to limit to just the case
>> where the default value is the first completion. We can just always
>> move point to the default wherever it occurs in the completions, as long
>> as it occurs somewhere. Seems like a nice improvement.
>>
>> Although I guess it does cause M-<down> to no longer go to the first
>> completion, and M-<up> to no longer go to the last one. Which is a bit
>> annoying.
>
> Indeed.
>
>> Maybe we should have bindings to move to the first and last completions.
>> Whatever they are, they should also work in completion-in-region-mode,
>> though, so M-< and M-> definitely won't work... Maybe M-0 M-<down> to go
>> to the first, and M-0 M-<up> to go to the last? (Or vice versa?)
>
> M-< and M-> work in the minibuffer as well as in the normal buffer.
> But they don't work with your first patch ;-)
Right right, I was just saying one reason we can't use M-< and M-> for
said bindings.
Anyway, I realized that we already have a nice way to move to the first
and last completions: ? M-<up> and ? M-<down>.
That is, run minibuffer-completion-help to recreate *Completions* and
wipe out the current value of point, then go down or up to access the
first or last.
Seems great so let's just stick with that.
>>> BTW, while looking at this case I found a problem with your first patch:
>>> after navigating in *Completions* and switching back to the minibuffer
>>> point is reset to the beginning of the *Completions* buffer.
>>
>> Good catch! If you see my other patch which I posted in this thread,
>> "Keep point on the same completion in the completions buffer", that is a
>> nice orthogonal improvement which incidentally also fixes that bug in
>> completions-auto-update.
>
> Your third patch adds a new feature that just hides the bug by forcing
> the previous position over the wrong new one. I think the proper fix
> would be to add more commands to completions-no-auto-update-commands
> in your first patch. Or to change it from opt-out to opt-in by renaming
> to completions-auto-update-commands.
I would much rather not list commands as opt-in or opt-out at all, I'd
rather all commands just work without special cases. So I'm working on
features to allow that.
I don't agree with the characterization of "it just hides the bug". The
bug is that point in *Completions* gets wiped out by auto-updating. My
third patch preserves point across auto-updating. That's very directly
solving the bug.
>> OK, so maybe the thing I want to propose is not "we'll change the
>> default to whatever the current selected completion is" but instead "RET
>> with an empty minibuffer will submit the current selected completion".
>> That's equivalent, if I drop the ideas of changing the prompt and
>> changing M-RET.
>
> Agreed, I think the idea of changing the prompt on the fly won't fly.
>
>>>> I think this has some nice benefits in reducing the number of concepts
>>>> people need to track. If the minibuffer is empty, they can just use
>>>> minibuffer-next-completion a few times followed by RET to select a
>>>> completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
>>>> would be useful even to users who don't use minibuffer-next-completion.
>>>> True, good analysis.
>>>
>>> Specifically though it's about the case when the minibuffer is empty. I
>>> think it would be nice for RET to submit the highlighted candidate in
>>> that case, if there is one.
>>>
>>> That matches icomplete-mode's behavior, actually, which is nice.
>>
>> Oh, actually it doesn't. It matches ido-mode and fido-mode and a host
>> of completion mechanisms outside core, though. I still think it's
>> desirable, at least as a user option.
>
> But then such idiosyncrasy of fido-mode causes a lot of bug reports
> like bug#55800.
But we would not have those kinds of issues because when completion
starts, by default, there is no highlighted candidate.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 12:47 ` Spencer Baugh
@ 2023-10-18 17:28 ` Juri Linkov
2023-10-18 23:32 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-18 17:28 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
>>>> BTW, while looking at this case I found a problem with your first patch:
>>>> after navigating in *Completions* and switching back to the minibuffer
>>>> point is reset to the beginning of the *Completions* buffer.
>>>
>>> Good catch! If you see my other patch which I posted in this thread,
>>> "Keep point on the same completion in the completions buffer", that is a
>>> nice orthogonal improvement which incidentally also fixes that bug in
>>> completions-auto-update.
>>
>> Your third patch adds a new feature that just hides the bug by forcing
>> the previous position over the wrong new one. I think the proper fix
>> would be to add more commands to completions-no-auto-update-commands
>> in your first patch. Or to change it from opt-out to opt-in by renaming
>> to completions-auto-update-commands.
>
> I would much rather not list commands as opt-in or opt-out at all, I'd
> rather all commands just work without special cases. So I'm working on
> features to allow that.
>
> I don't agree with the characterization of "it just hides the bug". The
> bug is that point in *Completions* gets wiped out by auto-updating. My
> third patch preserves point across auto-updating. That's very directly
> solving the bug.
I agree it's helpful to keep point on the selected candidate while
adding characters to the completion. But the problem is that point
is kept for too long that affects later unralated commands.
>>>>> I think this has some nice benefits in reducing the number of concepts
>>>>> people need to track. If the minibuffer is empty, they can just use
>>>>> minibuffer-next-completion a few times followed by RET to select a
>>>>> completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
>>>>> would be useful even to users who don't use minibuffer-next-completion.
>>>>> True, good analysis.
>>>>
>>>> Specifically though it's about the case when the minibuffer is empty. I
>>>> think it would be nice for RET to submit the highlighted candidate in
>>>> that case, if there is one.
>>>>
>>>> That matches icomplete-mode's behavior, actually, which is nice.
>>>
>>> Oh, actually it doesn't. It matches ido-mode and fido-mode and a host
>>> of completion mechanisms outside core, though. I still think it's
>>> desirable, at least as a user option.
>>
>> But then such idiosyncrasy of fido-mode causes a lot of bug reports
>> like bug#55800.
>
> But we would not have those kinds of issues because when completion
> starts, by default, there is no highlighted candidate.
And the issue occurs as soon as the first candidate is highlighted.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 12:25 ` Spencer Baugh
@ 2023-10-18 17:32 ` Juri Linkov
2023-10-18 23:33 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-18 17:32 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
>> Actually there is already a nil value in completions-sort with the tag
>> "No sorting". This works nicely for 'C-x b'. The remaining need is
>> to be able to set it only for 'C-x b', not for other completion types.
>
> I feel quite strongly that we should not extend completions-sort to be
> able to affect different completion types differently. Instead I think
> we should leave completions-sort as a blanket configuration for what to
> do if the completion metadata does not specify display-sort-function,
> and if we want to allow customizing an individual completion type, that
> completion type should specify a display-sort-function which can be
> customized.
>
> If we do extend completions-sort to affect different completion types
> differently, I expect we'll see lots of silly things, like packages with
> new completion types which automatically install changes to
> completions-sort instead of just specifying their own
> display-sort-function.
Probably different completion types should provide separate options
such as e.g. 'read-char-by-name-sort' defines 'display-sort-function'
for 'read-char-by-name'.
The same could be added for 'C-x b'. But unfortunately currently
it's hard-coded in 'internal-complete-buffer':
#+begin_src c
else if (EQ (flag, Qmetadata))
return list3 (Qmetadata,
Fcons (Qcategory, Qbuffer),
Fcons (Qcycle_sort_function, Qidentity));
#+end_src
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-17 18:23 ` Juri Linkov
@ 2023-10-18 23:27 ` Spencer Baugh
0 siblings, 0 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-10-18 23:27 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> Currently if the user re-runs minibuffer-completion-help, point is
>> reset to the beginning of the buffer. This throws away information
>> unnecessarily; let's keep point on the same completion the user
>> previously selected.
>
> Are you sure everyone would want to always preselect the previous
> candidate in the middle of completions in every new completion?
Definitely not. I allowed that behavior just to demonstrate the patch.
The real version will only retrieve the previous completion when
Completions is currently displayed - in other words, it will forget
whenever Completions disappears.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 17:28 ` Juri Linkov
@ 2023-10-18 23:32 ` Spencer Baugh
0 siblings, 0 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-10-18 23:32 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>>>>> I think this has some nice benefits in reducing the number of concepts
>>>>>> people need to track. If the minibuffer is empty, they can just use
>>>>>> minibuffer-next-completion a few times followed by RET to select a
>>>>>> completion, no need to use M-RET. Plus, the new M-RET and C-u M-RET
>>>>>> would be useful even to users who don't use minibuffer-next-completion.
>>>>>> True, good analysis.
>>>>>
>>>>> Specifically though it's about the case when the minibuffer is empty. I
>>>>> think it would be nice for RET to submit the highlighted candidate in
>>>>> that case, if there is one.
>>>>>
>>>>> That matches icomplete-mode's behavior, actually, which is nice.
>>>>
>>>> Oh, actually it doesn't. It matches ido-mode and fido-mode and a host
>>>> of completion mechanisms outside core, though. I still think it's
>>>> desirable, at least as a user option.
>>>
>>> But then such idiosyncrasy of fido-mode causes a lot of bug reports
>>> like bug#55800.
>>
>> But we would not have those kinds of issues because when completion
>> starts, by default, there is no highlighted candidate.
>
> And the issue occurs as soon as the first candidate is highlighted.
Yes, but that's something the user explicitly chooses to do. (as long
as we don't preselect completions, which (notwithstanding my patch which
does that) I don't think we should do)
And even if they highlight a candidate, they can always unhighlight by
running minibuffer-completion-help (? or M-?) again.
That's a big advantage we have over fido-mode and icomplete, which lets
us avoid this class of problems: We have a way to represent the state
where no candidate is selected/highlighted.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 17:32 ` Juri Linkov
@ 2023-10-18 23:33 ` Spencer Baugh
2023-10-19 2:29 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-10-18 23:33 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>> Actually there is already a nil value in completions-sort with the tag
>>> "No sorting". This works nicely for 'C-x b'. The remaining need is
>>> to be able to set it only for 'C-x b', not for other completion types.
>>
>> I feel quite strongly that we should not extend completions-sort to be
>> able to affect different completion types differently. Instead I think
>> we should leave completions-sort as a blanket configuration for what to
>> do if the completion metadata does not specify display-sort-function,
>> and if we want to allow customizing an individual completion type, that
>> completion type should specify a display-sort-function which can be
>> customized.
>>
>> If we do extend completions-sort to affect different completion types
>> differently, I expect we'll see lots of silly things, like packages with
>> new completion types which automatically install changes to
>> completions-sort instead of just specifying their own
>> display-sort-function.
>
> Probably different completion types should provide separate options
> such as e.g. 'read-char-by-name-sort' defines 'display-sort-function'
> for 'read-char-by-name'.
Agreed.
> The same could be added for 'C-x b'. But unfortunately currently
> it's hard-coded in 'internal-complete-buffer':
>
> #+begin_src c
> else if (EQ (flag, Qmetadata))
> return list3 (Qmetadata,
> Fcons (Qcategory, Qbuffer),
> Fcons (Qcycle_sort_function, Qidentity));
> #+end_src
Not hard to fix. I will post a patch to make this customizable soon.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-18 23:33 ` Spencer Baugh
@ 2023-10-19 2:29 ` Spencer Baugh
2023-10-19 6:55 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-10-19 2:29 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1697 bytes --]
Spencer Baugh <sbaugh@catern.com> writes:
> Juri Linkov <juri@linkov.net> writes:
>
>>>> Actually there is already a nil value in completions-sort with the tag
>>>> "No sorting". This works nicely for 'C-x b'. The remaining need is
>>>> to be able to set it only for 'C-x b', not for other completion types.
>>>
>>> I feel quite strongly that we should not extend completions-sort to be
>>> able to affect different completion types differently. Instead I think
>>> we should leave completions-sort as a blanket configuration for what to
>>> do if the completion metadata does not specify display-sort-function,
>>> and if we want to allow customizing an individual completion type, that
>>> completion type should specify a display-sort-function which can be
>>> customized.
>>>
>>> If we do extend completions-sort to affect different completion types
>>> differently, I expect we'll see lots of silly things, like packages with
>>> new completion types which automatically install changes to
>>> completions-sort instead of just specifying their own
>>> display-sort-function.
>>
>> Probably different completion types should provide separate options
>> such as e.g. 'read-char-by-name-sort' defines 'display-sort-function'
>> for 'read-char-by-name'.
>
> Agreed.
>
>> The same could be added for 'C-x b'. But unfortunately currently
>> it's hard-coded in 'internal-complete-buffer':
>>
>> #+begin_src c
>> else if (EQ (flag, Qmetadata))
>> return list3 (Qmetadata,
>> Fcons (Qcategory, Qbuffer),
>> Fcons (Qcycle_sort_function, Qidentity));
>> #+end_src
>
> Not hard to fix. I will post a patch to make this customizable soon.
How about this?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-read-buffer-sort.patch --]
[-- Type: text/x-patch, Size: 3293 bytes --]
From 2c5807193713893b8cecacf6ae9318e3e504fb93 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Wed, 18 Oct 2023 22:28:59 -0400
Subject: [PATCH] Add read-buffer-sort
Add the ability to customize how read-buffer (actually
internal-complete-buffer) sorts the buffer completion candidates.
* lisp/cus-start.el (standard): Add customization information for
read-buffer-sort.
* src/minibuf.c (Finternal_complete_buffer): Use read-buffer-sort.
(syms_of_minibuf): Add read-buffer-sort.
---
lisp/cus-start.el | 4 ++++
src/minibuf.c | 26 +++++++++++++++++++++++---
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 054683d7cf6..569a0cf54b3 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -439,6 +439,10 @@ minibuffer-prompt-properties--setter
(read-buffer-function minibuffer
(choice (const nil)
function))
+ (read-buffer-sort minibuffer
+ (choice (const :tag "completions-sort controls sorting" nil)
+ (const :tag "sort matching buffer-list" buffer-list))
+ "30.1")
;; msdos.c
(dos-unsupported-char-glyph display integer)
;; nsterm.m
diff --git a/src/minibuf.c b/src/minibuf.c
index 58adde1bf66..715b4c08886 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -2186,9 +2186,13 @@ DEFUN ("internal-complete-buffer", Finternal_complete_buffer, Sinternal_complete
else if (EQ (flag, Qlambda))
return Ftest_completion (string, Vbuffer_alist, predicate);
else if (EQ (flag, Qmetadata))
- return list3 (Qmetadata,
- Fcons (Qcategory, Qbuffer),
- Fcons (Qcycle_sort_function, Qidentity));
+ {
+ Lisp_Object res = list2 (Fcons (Qcategory, Qbuffer),
+ Fcons (Qcycle_sort_function, Qidentity));
+ if (EQ (Vread_buffer_sort, Qbuffer_list))
+ res = Fcons (Fcons (Qdisplay_sort_function, Qidentity), res);
+ return Fcons (Qmetadata, res);
+ }
else
return Qnil;
}
@@ -2323,6 +2327,7 @@ syms_of_minibuf (void)
DEFSYM (Qcase_fold_search, "case-fold-search");
DEFSYM (Qmetadata, "metadata");
DEFSYM (Qcycle_sort_function, "cycle-sort-function");
+ DEFSYM (Qdisplay_sort_function, "display-sort-function");
/* A frame parameter. */
DEFSYM (Qminibuffer_exit, "minibuffer-exit");
@@ -2522,6 +2527,21 @@ syms_of_minibuf (void)
the minibuffer. However, if `minibuffer-restore-windows' is present
in `minibuffer-exit-hook', exiting the minibuffer will remove the window
showing the *Completions* buffer, if any. */);
+
+ DEFVAR_LISP ("read-buffer-sort", Vread_buffer_sort,
+ doc: /* Non-nil means sort completions in `read-buffer'.
+
+If this is nil (the default), completions in `read-buffer' are sorted
+according to `completions-sort'.
+
+If this is `buffer-list', completions are sorted to match the order of
+`buffer-list'.
+
+This variable only affects the default `read-buffer', so if
+`read-buffer-function' is set to a function which does not use
+`internal-complete-buffer', this variable will have no effect.*/);
+ Vread_buffer_sort = Qnil;
+
read_minibuffer_restore_windows = true;
defsubr (&Sactive_minibuffer_window);
--
2.41.0
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-19 2:29 ` Spencer Baugh
@ 2023-10-19 6:55 ` Juri Linkov
2023-11-19 19:22 ` sbaugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-19 6:55 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> How about this?
Looks good.
> + (read-buffer-sort minibuffer
> + (choice (const :tag "completions-sort controls sorting" nil)
> + (const :tag "sort matching buffer-list" buffer-list))
> + "30.1")
Shouldn't 'read-buffer-sort' support other choices from 'completions-sort'?
Your new choice 'historical' would sort buffers by the order of 'M-p'
the same way as 'buffer-list' will sort buffers by the order of 'M-n'.
Also 'alphabetical' would be useful for 'C-x b' when 'completions-sort'
was customized to something else.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-14 20:05 ` sbaugh
` (3 preceding siblings ...)
2023-10-17 13:48 ` sbaugh
@ 2023-10-20 6:49 ` Juri Linkov
4 siblings, 0 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-20 6:49 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> Also: it might be nice to switch between history-sorting and
> alphabetized-sorting during the course of completion, both for files and
> buffers. Maybe we could do that by making a command which puts
> completion into a mode where it just ignores the display-sort-function
> specified by the completion metadata, and just always uses
> completions-sort.
To be able to implement switching between different sort orders
with a new key, first we need to implement revert-buffer-function
(bound to 'g') in the *Completions* buffer.
Then it will be possible just to toggle a new buffer-local variable
(initially set from 'completions-sort') and to revert the *Completions*
buffer with a new sort order. Also will need to keep a previously
selected candidate that is implemented by your recent patch.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: [External] : Re: Updating *Completions* as you type
2023-10-16 16:03 ` Drew Adams
@ 2023-10-20 7:45 ` Philip Kaludercic
2023-10-20 16:10 ` Drew Adams
0 siblings, 1 reply; 107+ messages in thread
From: Philip Kaludercic @ 2023-10-20 7:45 UTC (permalink / raw)
To: Drew Adams; +Cc: Spencer Baugh, emacs-devel@gnu.org
Drew Adams <drew.adams@oracle.com> writes:
> I'm not asking you, or anyone, to use Icicles.
> Unfortunately, talking about its features can
> perhaps give the opposite impression.
I didn't understand it that way either, my I just wanted to point out
that my impressions is that people miss out on even trying your packages
out, because they aren't distributed on any standard archive. The
reason they aren't distributed on GNU or NonGNU ELPA is that you
overwrite built-in definitions -- hence my question: Are you sure this
is necessary, since if not and you could change them, your packages
could be added to GNU/NonGNU ELPA and more people could profit from your
work.
> As I tried to make clear in my posts, their aim
> was to mention various Icicles features I think
> are relevant to this thread - not to advertise
> Icicles or suggest its use.
>
> The point was to encourage consideration of such
> or similar features as useful and perhaps worth
> adding to vanilla Emacs. Nothing more.
>
> Icicles is just a reference point here. Its doc
> about such features might hopefully provide some
> food for thought. _What users can do_ is the
> point, not how such features can be implemented.
>
> It's good to see others coming around to similar
> feature ideas now. Knowledge that such features
> work _in combination_, and they have done so for
> quite a while, should be helpful, I hope.
I might be mistaken, but the reason I thought your were "advertising"
Icicles, was that you usually respond to the suggestion to add some
feature with something like "Icicles had this feature since 200X".
> ___
>
> Wrt la petite histoire -
>
> To my knowledge, the first appearance of any
> incremental completion was in icomplete-mode.
> But that wasn't a completion whose result you
> could _use_; it was only completion you could
> _see_ (and only a few completions). You could
> use it only as a guide/preview of what you could
> then type. (Much later, completion of input was
> finally added to icomplete-mode.)
>
> Next was IswitchB, which later became the model
> for Ido. Completion candidates were shown only
> in the minibuffer (and again, only a few) - no
> use of *Completions* to show candidates.
>
> Icicles came after icomplete-mode and IswitchB,
> and before Ido. It introduced incremental
> completion showing candidates in *Completions*;
> cycling among candidates (notion of "current"
> candidate); on-the-fly sorting of them; etc.
The copyright files indicate this chronology:
icomplete: 1992
icicles: 1995
iswitchb: 1996
ido: 1996
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: zcomplete
2023-10-13 6:34 ` Juri Linkov
2023-10-13 19:04 ` Spencer Baugh
2023-10-16 3:19 ` [External] : " Drew Adams
@ 2023-10-20 9:35 ` Philip Kaludercic
2023-10-22 17:28 ` zcomplete Juri Linkov
2 siblings, 1 reply; 107+ messages in thread
From: Philip Kaludercic @ 2023-10-20 9:35 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
> diff --git a/lisp/zcomplete.el b/lisp/zcomplete.el
> new file mode 100644
> index 00000000000..75a40c0afd3
> --- /dev/null
> +++ b/lisp/zcomplete.el
> @@ -0,0 +1,317 @@
> +;;; zcomplete.el --- zsh-like minibuffer completion based on icomplete -*- lexical-binding: t -*-
I have been trying out zcomplete for the last week, and it works really
well. If there is no plan to add it to the core, would you at least be
interested in having it added to GNU ELPA?
^ permalink raw reply [flat|nested] 107+ messages in thread
* RE: [External] : Re: Updating *Completions* as you type
2023-10-20 7:45 ` Philip Kaludercic
@ 2023-10-20 16:10 ` Drew Adams
0 siblings, 0 replies; 107+ messages in thread
From: Drew Adams @ 2023-10-20 16:10 UTC (permalink / raw)
To: Philip Kaludercic; +Cc: Spencer Baugh, emacs-devel@gnu.org
> The reason they aren't distributed on GNU or
> NonGNU ELPA is that you overwrite built-in
> definitions
No, that's not the reason. Not at all.
> > As I tried to make clear in my posts, their aim
> > was to mention various Icicles features I think
> > are relevant to this thread - not to advertise
> > Icicles or suggest its use.
> >
> > The point was to encourage consideration of such
> > or similar features as useful and perhaps worth
> > adding to vanilla Emacs. Nothing more.
> >
> > Icicles is just a reference point here. Its doc
> > about such features might hopefully provide some
> > food for thought. _What users can do_ is the
> > point, not how such features can be implemented.
> >
> > It's good to see others coming around to similar
> > feature ideas now. Knowledge that such features
> > work _in combination_, and they have done so for
> > quite a while, should be helpful, I hope.
>
> I might be mistaken, but the reason I thought your
> were "advertising" Icicles, was that you usually
> respond to the suggestion to add some feature with
> something like "Icicles had this feature since 200X".
I don't know whether you're mistaken about
why you thought that.
But if what you mean is that you might be
mistaken about why I say that, then yes,
you're apparently mistaken about that.
The above text should make that "why" very
clear, so I wonder why you would still be
wondering. Let me say it once more:
such features might hopefully provide
some food for thought. _What users can
do_ is the point
Many Icicles features have been adopted
(reinvented) for vanilla Emacs or other
completion libraries. Other features
have not (yet). I mentioned on-the-fly,
flexible interactive sorting as one, in
particular, because this thread broached
the question of sorting candidates.
The point in mentioning Icicles features
is that they might be of interest as
food for thought: _what_ they do, not
necessarily _how_ they do it.
If a user of vanilla Emacs or another
library can't do XYZ, and a user of
Icicles can, and if XYZ is a useful
thing to be able to do, then someone
might want to look at the feature in
Icicles, as food for thought.
It's not important that Icicles does
something, except that from Icicles you
can get a good description of a feature
and see the source code - if interested.
> > Wrt la petite histoire -
> >
> > To my knowledge, the first appearance of any
> > incremental completion was in icomplete-mode.
> > But that wasn't a completion whose result you
> > could _use_; it was only completion you could
> > _see_ (and only a few completions). You could
> > use it only as a guide/preview of what you could
> > then type. (Much later, completion of input was
> > finally added to icomplete-mode.)
> >
> > Next was IswitchB, which later became the model
> > for Ido. Completion candidates were shown only
> > in the minibuffer (and again, only a few) - no
> > use of *Completions* to show candidates.
> >
> > Icicles came after icomplete-mode and IswitchB,
> > and before Ido. It introduced incremental
> > completion showing candidates in *Completions*;
> > cycling among candidates (notion of "current"
> > candidate); on-the-fly sorting of them; etc.
>
> The copyright files indicate this chronology:
>
> icomplete: 1992
> icicles: 1995
> iswitchb: 1996
> ido: 1996
Please read what I said, which is about
incremental completion, not copyright of
the libraries.
Here's a very brief description of the
initial history of Icicles:
https://www.emacswiki.org/emacs/Icicles_-_La_Petite_Histoire
That doesn't specifically mention
incremental completion. But the Change
Log in icicles-chg.el indicates it was
added in 2006 or before then. Looking
at details in the log indicates it was
in 2005 or before (as "icompletion").
Icicles as such, with cycling of
matching candidates etc., really began
in 2005. (The name dates from then.)
From 1996 to 2005 it was essentially
elect-mbuf.el, which (1) never updated
the set of candidates to cycle among,
and (2) never tied cycling (current
candidate in *Completions*) to the
minibuffer content (no "current
candidate" there). It didn't do much
at all, except let you see the initial
set of completion candidates.
[ BTW, #2 is similar to the situation
with vanilla Emacs today wrt sorting:
the sort order for *Completions*
isn't necessarily the same as the
sort order for the minibuffer content
(`display-sort-function' versus
`cycle-sort-function').
I've asked for the reason why - why
or when that might be useful, but
I've not received any answer, ever.
Until I do, I'll just consider it a
misfeature or a missed opportunity. ]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: zcomplete
2023-10-20 9:35 ` zcomplete Philip Kaludercic
@ 2023-10-22 17:28 ` Juri Linkov
2023-10-23 5:00 ` zcomplete Protesilaos Stavrou
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-10-22 17:28 UTC (permalink / raw)
To: Philip Kaludercic; +Cc: sbaugh, emacs-devel
>> diff --git a/lisp/zcomplete.el b/lisp/zcomplete.el
>> new file mode 100644
>> index 00000000000..75a40c0afd3
>> --- /dev/null
>> +++ b/lisp/zcomplete.el
>> @@ -0,0 +1,317 @@
>> +;;; zcomplete.el --- zsh-like minibuffer completion based on icomplete -*- lexical-binding: t -*-
>
> I have been trying out zcomplete for the last week, and it works really
> well. If there is no plan to add it to the core, would you at least be
> interested in having it added to GNU ELPA?
Actually, it has many problems. Hopefully, we will fix them in the core.
I'd rather not proliferate the number of similar packages by adding
yet another package that does the same as existing mct, vcomplete.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: zcomplete
2023-10-22 17:28 ` zcomplete Juri Linkov
@ 2023-10-23 5:00 ` Protesilaos Stavrou
2023-10-23 6:45 ` zcomplete Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Protesilaos Stavrou @ 2023-10-23 5:00 UTC (permalink / raw)
To: Juri Linkov, Philip Kaludercic; +Cc: sbaugh, emacs-devel
> From: Juri Linkov <juri@linkov.net>
> Date: Sun, 22 Oct 2023 20:28:01 +0300
> [... 9 lines elided]
>> I have been trying out zcomplete for the last week, and it works really
>> well. If there is no plan to add it to the core, would you at least be
>> interested in having it added to GNU ELPA?
>
> Actually, it has many problems. Hopefully, we will fix them in the core.
> I'd rather not proliferate the number of similar packages by adding
> yet another package that does the same as existing mct, vcomplete.
Just to note that I am interested in what you do here and am happy to
remove mct altogether.
--
Protesilaos Stavrou
https://protesilaos.com
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: zcomplete
2023-10-23 5:00 ` zcomplete Protesilaos Stavrou
@ 2023-10-23 6:45 ` Juri Linkov
0 siblings, 0 replies; 107+ messages in thread
From: Juri Linkov @ 2023-10-23 6:45 UTC (permalink / raw)
To: Protesilaos Stavrou; +Cc: Philip Kaludercic, sbaugh, emacs-devel
>>> I have been trying out zcomplete for the last week, and it works really
>>> well. If there is no plan to add it to the core, would you at least be
>>> interested in having it added to GNU ELPA?
>>
>> Actually, it has many problems. Hopefully, we will fix them in the core.
>> I'd rather not proliferate the number of similar packages by adding
>> yet another package that does the same as existing mct, vcomplete.
>
> Just to note that I am interested in what you do here and am happy to
> remove mct altogether.
No need to remove mct. The core should provide the basic building blocks.
Then external packages could build more feature-rich experience.
OTOH, in the process of mutual enrichment often external packages act as
a playing ground for new features, and when they mature, some of their
features are included in the core. Even in this case the package could
continue existence with more peripheral features that satisfy even
more demanding users.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-10-19 6:55 ` Juri Linkov
@ 2023-11-19 19:22 ` sbaugh
2023-11-20 7:51 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-11-19 19:22 UTC (permalink / raw)
To: Juri Linkov; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1322 bytes --]
Juri Linkov <juri@linkov.net> writes:
>> How about this?
>
> Looks good.
>
>> + (read-buffer-sort minibuffer
>> + (choice (const :tag "completions-sort controls sorting" nil)
>> + (const :tag "sort matching buffer-list" buffer-list))
>> + "30.1")
>
> Shouldn't 'read-buffer-sort' support other choices from 'completions-sort'?
> Your new choice 'historical' would sort buffers by the order of 'M-p'
> the same way as 'buffer-list' will sort buffers by the order of 'M-n'.
> Also 'alphabetical' would be useful for 'C-x b' when 'completions-sort'
> was customized to something else.
Finally got to it, I've added that in this patch (which combines both
the read-buffer-sort and completions-sort changes).
The nice reusable part is that the new minibuffer-sort-by-history and
minibuffer-sort-alphabetically should work for any completion table. So
it will be easy to just add options for different completion tables,
e.g. read-file-name-sort, and they can just use those pre-existing
functions.
This does require adding the new dynamic variable
minibuffer-completion-base which maybe should go in some other place, or
could be derived from some other variable - I'm not sure. Possibly it's
fine as I did it.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-read-buffer-sort-to-customize-how-read-buffer-so.patch --]
[-- Type: text/x-patch, Size: 8826 bytes --]
From 5e898c3ef323971af89b80fe37d94be0bf29443f Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Tue, 17 Oct 2023 09:09:55 -0400
Subject: [PATCH] Add read-buffer-sort to customize how read-buffer sorts
completions
Add the ability to customize how read-buffer (actually
internal-complete-buffer) sorts the buffer completion candidates.
Also add minibuffer-sort-alphabetically and minibuffer-sort-by-history
to provide some reasonable options for read-buffer-sort.
And add support for them to completions-sort, too, as a simple change.
* 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.
* lisp/cus-start.el (standard): Add customization information for
read-buffer-sort.
* src/minibuf.c (Finternal_complete_buffer): Use read-buffer-sort.
(syms_of_minibuf): Add read-buffer-sort.
---
lisp/cus-start.el | 7 ++++++
lisp/minibuffer.el | 63 +++++++++++++++++++++++++++++++++++++++++-----
src/minibuf.c | 32 ++++++++++++++++++++---
3 files changed, 93 insertions(+), 9 deletions(-)
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 6d83aaf4d14..40bc4078d77 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -441,6 +441,13 @@ minibuffer-prompt-properties--setter
(read-buffer-function minibuffer
(choice (const nil)
function))
+ (read-buffer-sort minibuffer
+ (choice (const :tag "completions-sort controls sorting" nil)
+ (const :tag "sort matching buffer-list" buffer-list)
+ (const :tag "sort alphabetically" minibuffer-sort-alphabetically)
+ (const :tag "sort historically" minibuffer-sort-by-history)
+ (function :tag "User-defined function"))
+ "30.1")
;; msdos.c
(dos-unsupported-char-glyph display integer)
;; nsterm.m
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 026613c9eb2..49086ff6eff 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1307,14 +1307,26 @@ completion-cycle-threshold
(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."
+Candidate completions in the *Completions* are sorted depending
+on the value.
+
+If nil, sorting is disabled.
+If `alphabetical', candidates are sorted by
+`minibuffer-sort-alphabetically'.
+If `historical', candidates are sorted by
+`minibuffer-sort-by-history'.
+If a function, the function is called to sort the candidates.
+The sorting function takes and returns a list of completion
+candidate strings.
+
+If the completion-specific metadata provides a
+`display-sort-function', that is used instead and this value is
+ignored."
: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.
@@ -1640,6 +1652,43 @@ minibuffer--sort-preprocess-history
(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 is not
+being completed on. 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 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))
@@ -2470,6 +2519,7 @@ minibuffer-completion-help
(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
@@ -2540,7 +2590,8 @@ minibuffer-completion-help
(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
diff --git a/src/minibuf.c b/src/minibuf.c
index 58adde1bf66..04551afeb79 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -2186,9 +2186,15 @@ DEFUN ("internal-complete-buffer", Finternal_complete_buffer, Sinternal_complete
else if (EQ (flag, Qlambda))
return Ftest_completion (string, Vbuffer_alist, predicate);
else if (EQ (flag, Qmetadata))
- return list3 (Qmetadata,
- Fcons (Qcategory, Qbuffer),
- Fcons (Qcycle_sort_function, Qidentity));
+ {
+ Lisp_Object res = list2 (Fcons (Qcategory, Qbuffer),
+ Fcons (Qcycle_sort_function, Qidentity));
+ if (EQ (Vread_buffer_sort, Qbuffer_list))
+ res = Fcons (Fcons (Qdisplay_sort_function, Qidentity), res);
+ else if (FUNCTIONP (Vread_buffer_sort))
+ res = Fcons (Fcons (Qdisplay_sort_function, Vread_buffer_sort), res);
+ return Fcons (Qmetadata, res);
+ }
else
return Qnil;
}
@@ -2323,6 +2329,7 @@ syms_of_minibuf (void)
DEFSYM (Qcase_fold_search, "case-fold-search");
DEFSYM (Qmetadata, "metadata");
DEFSYM (Qcycle_sort_function, "cycle-sort-function");
+ DEFSYM (Qdisplay_sort_function, "display-sort-function");
/* A frame parameter. */
DEFSYM (Qminibuffer_exit, "minibuffer-exit");
@@ -2522,6 +2529,25 @@ syms_of_minibuf (void)
the minibuffer. However, if `minibuffer-restore-windows' is present
in `minibuffer-exit-hook', exiting the minibuffer will remove the window
showing the *Completions* buffer, if any. */);
+
+ DEFVAR_LISP ("read-buffer-sort", Vread_buffer_sort,
+ doc: /* Non-nil means sort completions in `read-buffer'.
+
+If this is nil (the default), completions in `read-buffer' are sorted
+according to `completions-sort'.
+
+If this is `buffer-list', completions are sorted to match the order of
+`buffer-list'.
+
+If a function, the function is called to sort the candidates. Some
+possible values are `minibuffer-sort-alphabetically' and
+`minibuffer-sort-by-history'.
+
+This variable only affects the default `read-buffer', so if
+`read-buffer-function' is set to a function which does not use
+`internal-complete-buffer', this variable will have no effect.*/);
+ Vread_buffer_sort = Qnil;
+
read_minibuffer_restore_windows = true;
defsubr (&Sactive_minibuffer_window);
--
2.42.1
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-19 19:22 ` sbaugh
@ 2023-11-20 7:51 ` Juri Linkov
2023-11-20 15:24 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-20 7:51 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
> Finally got to it, I've added that in this patch (which combines both
> the read-buffer-sort and completions-sort changes).
Thanks, a quick test shows that everything works nicely.
> + Lisp_Object res = list2 (Fcons (Qcategory, Qbuffer),
> + Fcons (Qcycle_sort_function, Qidentity));
> + if (EQ (Vread_buffer_sort, Qbuffer_list))
> + res = Fcons (Fcons (Qdisplay_sort_function, Qidentity), res);
> + else if (FUNCTIONP (Vread_buffer_sort))
> + res = Fcons (Fcons (Qdisplay_sort_function, Vread_buffer_sort), res);
> + return Fcons (Qmetadata, res);
I still have doubts about adding separate sorting options for
every completion category.
What do you think about adding customization of display-sort-function
to the existing option completion-category-overrides?
This would allow users such customization for 'C-x b' and 'C-x p p'
to sort buffers and projects by history:
(setopt completion-category-overrides
'((buffer (display-sort-function . minibuffer-sort-by-history))
(project-file (display-sort-function . minibuffer-sort-by-history))
And default values could be specified in completion-category-defaults.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-20 7:51 ` Juri Linkov
@ 2023-11-20 15:24 ` Spencer Baugh
2023-11-20 17:47 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-20 15:24 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> Finally got to it, I've added that in this patch (which combines both
>> the read-buffer-sort and completions-sort changes).
>
> Thanks, a quick test shows that everything works nicely.
>
>> + Lisp_Object res = list2 (Fcons (Qcategory, Qbuffer),
>> + Fcons (Qcycle_sort_function, Qidentity));
>> + if (EQ (Vread_buffer_sort, Qbuffer_list))
>> + res = Fcons (Fcons (Qdisplay_sort_function, Qidentity), res);
>> + else if (FUNCTIONP (Vread_buffer_sort))
>> + res = Fcons (Fcons (Qdisplay_sort_function, Vread_buffer_sort), res);
>> + return Fcons (Qmetadata, res);
>
> I still have doubts about adding separate sorting options for
> every completion category.
Not just every completion category, every completion table.
What are your doubts? I don't think it ends up being too many options
in practice. The discoverability is worse than a centralized solution,
but it also keeps configuration localized to the individual component,
which is nice and makes it easier to group buffer/file/etc settings
together in configuration and the Customize interface.
One important feature of separate sorting options is that they support
sorting details which are specific to the individual completion table.
For buffers, for example, sorting by the buffer-list can be done by just
setting display-sort-function to identity, but we probably shouldn't
expose that fact to the user. (We could expose a generic "sort by
defaults" but that would be less efficient.)
The sorting style might even require the sorting option to actually
change the completion table's behavior. File name completion could be
sorted by mtime, for example, by having the completion table include
mtime as a text property when read-file-name-sort=mtime, and then
setting display-sort-function to something which reads that property. I
think that can only work if we have separate sorting options.
> What do you think about adding customization of display-sort-function
> to the existing option completion-category-overrides?
>
> This would allow users such customization for 'C-x b' and 'C-x p p'
> to sort buffers and projects by history:
>
> (setopt completion-category-overrides
> '((buffer (display-sort-function . minibuffer-sort-by-history))
> (project-file (display-sort-function . minibuffer-sort-by-history))
>
> And default values could be specified in completion-category-defaults.
Hm, this could be okay. It does sacrifice the extra level of
customization possible with separate sorting options that I just
described.
I think the default values would be part of the completion table itself;
a completion table can just set display-sort-function itself, it doesn't
need completion-category-defaults to do that.
Indeed, currently completion-category-overrides and defaults are used
only to configure things which can't be directly set by the completion
table. That's my understanding of the purpose of completion categories:
the completion table returns a category symbol as a somewhat roundabout
way to configure completion-styles and completion-cycle-threshold to
values which are specific to the table.
But the completion table is already able to set display-sort-function on
its own. So it's novel to also have completion-category-overrides able
to do that.
Maybe we should decide what things are supposed to be configured by
category and what things are supposed to be configured by the table
itself. Because in theory we could allow setting completion-styles and
completion-cycle-threshold with completion table metadata, and I'm not
sure why we didn't do it that way - it could even be nice to have a
completion style which is specific to an individual completion table.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-20 15:24 ` Spencer Baugh
@ 2023-11-20 17:47 ` Juri Linkov
2023-11-20 18:50 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-20 17:47 UTC (permalink / raw)
To: Spencer Baugh; +Cc: sbaugh, emacs-devel
> For buffers, for example, sorting by the buffer-list can be done by just
> setting display-sort-function to identity, but we probably shouldn't
> expose that fact to the user. (We could expose a generic "sort by
> defaults" but that would be less efficient.)
It should be fine to use 'identity' as a value when the Customization UI
will show a more meaningful tag like "Unsorted".
> The sorting style might even require the sorting option to actually
> change the completion table's behavior. File name completion could be
> sorted by mtime, for example, by having the completion table include
> mtime as a text property when read-file-name-sort=mtime, and then
> setting display-sort-function to something which reads that property. I
> think that can only work if we have separate sorting options.
Also a separate option might be needed when a completion table
supports a non-standard sorting order such as
'mule--ucs-names-sort-by-code' when 'read-char-by-name-sort'
is customized to 'code'. But the users still should have freedom
to override all metadata: display-sort-function, affixation-function,
group-function, etc.
>> (setopt completion-category-overrides
>> '((buffer (display-sort-function . minibuffer-sort-by-history))
>> (project-file (display-sort-function . minibuffer-sort-by-history))
>>
>> And default values could be specified in completion-category-defaults.
>
> I think the default values would be part of the completion table itself;
> a completion table can just set display-sort-function itself, it doesn't
> need completion-category-defaults to do that.
OTOH, the completion table needs only to return its category in metadata.
Otherwise every completion table of the same category would need to
duplicate display-sort-function in its completing-read.
> Maybe we should decide what things are supposed to be configured by
> category and what things are supposed to be configured by the table
> itself. Because in theory we could allow setting completion-styles and
> completion-cycle-threshold with completion table metadata, and I'm not
> sure why we didn't do it that way - it could even be nice to have a
> completion style which is specific to an individual completion table.
I guess when an individual completion table needs to use metadata
slightly different from other similar cases then it should provide
a different category/subcategory.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-20 17:47 ` Juri Linkov
@ 2023-11-20 18:50 ` Spencer Baugh
2023-11-21 7:58 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-20 18:50 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> For buffers, for example, sorting by the buffer-list can be done by just
>> setting display-sort-function to identity, but we probably shouldn't
>> expose that fact to the user. (We could expose a generic "sort by
>> defaults" but that would be less efficient.)
>
> It should be fine to use 'identity' as a value when the Customization UI
> will show a more meaningful tag like "Unsorted".
Yes, that's fine. But "Unsorted" is different from "Sorted by
buffer-list", which is the behavior one gets with read-buffer. In other
words, the documentation can be more specific for read-buffer-sort.
>> The sorting style might even require the sorting option to actually
>> change the completion table's behavior. File name completion could be
>> sorted by mtime, for example, by having the completion table include
>> mtime as a text property when read-file-name-sort=mtime, and then
>> setting display-sort-function to something which reads that property. I
>> think that can only work if we have separate sorting options.
>
> Also a separate option might be needed when a completion table
> supports a non-standard sorting order such as
> 'mule--ucs-names-sort-by-code' when 'read-char-by-name-sort'
> is customized to 'code'. But the users still should have freedom
> to override all metadata: display-sort-function, affixation-function,
> group-function, etc.
>
>>> (setopt completion-category-overrides
>>> '((buffer (display-sort-function . minibuffer-sort-by-history))
>>> (project-file (display-sort-function . minibuffer-sort-by-history))
>>>
>>> And default values could be specified in completion-category-defaults.
>>
>> I think the default values would be part of the completion table itself;
>> a completion table can just set display-sort-function itself, it doesn't
>> need completion-category-defaults to do that.
>
> OTOH, the completion table needs only to return its category in metadata.
> Otherwise every completion table of the same category would need to
> duplicate display-sort-function in its completing-read.
Interesting point. In some sense, the category gives us an inheritance
mechanism for completion tables, where a completion table can just use
the defaults for its category rather than specifying all the details.
But if the completion table has some specific sorting function it wants,
it can provide that by explicitly returning it in the metadata.
And completion-category-overrides gives the user a way to do
customization of the category defaults.
So perhaps, for a given metadata, display-sort-function would be:
(or
(alist-get 'display-sort-function metadata)
(alist-get 'display-sort-function (alist-get category completion-category-overrides))
(alist-get 'display-sort-function (alist-get category completion-category-defaults))
completions-sort)
That makes sense to me.
And (alist-get 'display-sort-function metadata) is configurable with
separate completion-table-specific options, like read-buffer-sort.
If we do this, completions-sort acts like a "default" entry in
completion-category-defaults, which acts for categories which aren't
otherwise matched. Which makes a lot of sense, and makes it behave like
completion-styles and completion-cycle-threshold.
I expect some disagreement about the following question: should
completion-category-overrides override the display-sort-function
returned by the completion table? That is, should it instead be:
(or
(alist-get 'display-sort-function (alist-get category completion-category-overrides))
(alist-get 'display-sort-function metadata)
(alist-get 'display-sort-function (alist-get category completion-category-defaults))
completions-sort)
I think no. The most specific customization (customizing an individual
completion table) should override more broad customizations (customizing
an entire category). I don't think there's a reasonable use-case for
overriding a display-sort-function explicitly returned by a table - we
can just make that display-sort-function configurable directly.
We probably will want to make this clear in the documentation, of
course.
>> Maybe we should decide what things are supposed to be configured by
>> category and what things are supposed to be configured by the table
>> itself. Because in theory we could allow setting completion-styles and
>> completion-cycle-threshold with completion table metadata, and I'm not
>> sure why we didn't do it that way - it could even be nice to have a
>> completion style which is specific to an individual completion table.
>
> I guess when an individual completion table needs to use metadata
> slightly different from other similar cases then it should provide
> a different category/subcategory.
Or the individual completion table just returns that slightly different
metadata itself, and it overrides the metadata pulled from its category.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-20 18:50 ` Spencer Baugh
@ 2023-11-21 7:58 ` Juri Linkov
2023-11-21 12:40 ` sbaugh
2023-11-21 12:54 ` Updating *Completions* as you type John Yates
0 siblings, 2 replies; 107+ messages in thread
From: Juri Linkov @ 2023-11-21 7:58 UTC (permalink / raw)
To: Spencer Baugh; +Cc: sbaugh, emacs-devel
> I expect some disagreement about the following question: should
> completion-category-overrides override the display-sort-function
> returned by the completion table? That is, should it instead be:
>
> (or
> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
> (alist-get 'display-sort-function metadata)
> (alist-get 'display-sort-function (alist-get category completion-category-defaults))
> completions-sort)
I think this is the most correct precedence since the users should be
able to override the function call metadata. We have an analogous
priority levels for 'display-buffer':
1. display-buffer-overriding-action
2. display-buffer-alist
3. function call arguments that correspond to completion metadata
4. display-buffer-base-action
5. display-buffer-fallback-action
Since completion-category-overrides is a user option
it corresponds to display-buffer-alist.
And completion-category-defaults looks like
display-buffer-base-action.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 7:58 ` Juri Linkov
@ 2023-11-21 12:40 ` sbaugh
2023-11-21 17:09 ` Juri Linkov
2023-11-21 12:54 ` Updating *Completions* as you type John Yates
1 sibling, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-11-21 12:40 UTC (permalink / raw)
To: emacs-devel
Juri Linkov <juri@linkov.net> writes:
>> I expect some disagreement about the following question: should
>> completion-category-overrides override the display-sort-function
>> returned by the completion table? That is, should it instead be:
>>
>> (or
>> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
>> (alist-get 'display-sort-function metadata)
>> (alist-get 'display-sort-function (alist-get category completion-category-defaults))
>> completions-sort)
>
> I think this is the most correct precedence since the users should be
> able to override the function call metadata. We have an analogous
> priority levels for 'display-buffer':
>
> 1. display-buffer-overriding-action
> 2. display-buffer-alist
> 3. function call arguments that correspond to completion metadata
> 4. display-buffer-base-action
> 5. display-buffer-fallback-action
>
> Since completion-category-overrides is a user option
> it corresponds to display-buffer-alist.
> And completion-category-defaults looks like
> display-buffer-base-action.
A few points in favor of
(alist-get 'display-sort-function metadata)
(alist-get 'display-sort-function (alist-get category completion-category-overrides))
instead:
- Again, the user is still able to configure the display-sort-function
by configuring the individual completion table. That's not true with
display-buffer. The only configuration mechanism is
display-buffer-alist.
- Given that the user can still configure the display-sort-function, I
don't see any use case where the user should override it. (A buggy
completion table that returns the wrong display-sort-function? But
that should just be fixed.)
- display-buffer-alist is driven purely by buffer-match-p conditions, so
there's a linear sequence of overriding. The display-sort-function
has two levels: the completion table and the completion category.
Since the table is more specific than the category, it should override
the category.
- As a minor point, I, and many other Emacs users IME, find the
display-buffer configuration to be complex and hard to use, so I don't
think we should try to emulate it too much.
- The "overrides" in "completion-category-overrides" is just a name. It
doesn't mean that we have to make it override everything else.
I suppose we could add a new completion-category-table-overrides, if we
find a use case for making the category override the table but it's
rare. That's starting to reach the complexity of display-buffer-alist
though...
Alternatively, could we just add support for configuring the individual
table now, and add category-based configuration later? We don't need to
add everything all at once, and that will give us valuable user
feedback.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 7:58 ` Juri Linkov
2023-11-21 12:40 ` sbaugh
@ 2023-11-21 12:54 ` John Yates
2023-11-21 17:03 ` Juri Linkov
1 sibling, 1 reply; 107+ messages in thread
From: John Yates @ 2023-11-21 12:54 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, sbaugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1273 bytes --]
Sharing this insight in the associated documentation will aid users.
On Tue, Nov 21, 2023 at 3:31 AM Juri Linkov <juri@linkov.net> wrote:
> > I expect some disagreement about the following question: should
> > completion-category-overrides override the display-sort-function
> > returned by the completion table? That is, should it instead be:
> >
> > (or
> > (alist-get 'display-sort-function (alist-get category
> completion-category-overrides))
> > (alist-get 'display-sort-function metadata)
> > (alist-get 'display-sort-function (alist-get category
> completion-category-defaults))
> > completions-sort)
>
> I think this is the most correct precedence since the users should be
> able to override the function call metadata. We have an analogous
> priority levels for 'display-buffer':
>
> 1. display-buffer-overriding-action
> 2. display-buffer-alist
> 3. function call arguments that correspond to completion metadata
> 4. display-buffer-base-action
> 5. display-buffer-fallback-action
>
> Since completion-category-overrides is a user option
> it corresponds to display-buffer-alist.
> And completion-category-defaults looks like
> display-buffer-base-action.
>
>
--
John Yates
505 Tremont St, #803
Boston, MA 02116
[-- Attachment #2: Type: text/html, Size: 1926 bytes --]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 12:54 ` Updating *Completions* as you type John Yates
@ 2023-11-21 17:03 ` Juri Linkov
2023-11-21 22:27 ` John Yates
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-21 17:03 UTC (permalink / raw)
To: John Yates; +Cc: Spencer Baugh, sbaugh, emacs-devel
>> 1. display-buffer-overriding-action
>> 2. display-buffer-alist
>> 3. function call arguments that correspond to completion metadata
>> 4. display-buffer-base-action
>> 5. display-buffer-fallback-action
> Sharing this insight in the associated documentation will aid users.
This is thoroughly documented in (info "(elisp) Choosing Window"):
‘display-buffer’ builds a list of action functions and an action
alist, by consolidating display actions from the following sources
(in order of their precedence, from highest to lowest):
• The variable ‘display-buffer-overriding-action’.
• The user option ‘display-buffer-alist’.
• The ACTION argument.
• The user option ‘display-buffer-base-action’.
• The constant ‘display-buffer-fallback-action’.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 12:40 ` sbaugh
@ 2023-11-21 17:09 ` Juri Linkov
2023-11-21 20:45 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-21 17:09 UTC (permalink / raw)
To: sbaugh; +Cc: emacs-devel
>>> (or
>>> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
>>> (alist-get 'display-sort-function metadata)
>>> (alist-get 'display-sort-function (alist-get category completion-category-defaults))
>>> completions-sort)
>>
>> 1. display-buffer-overriding-action
>> 2. display-buffer-alist
>> 3. function call arguments that correspond to completion metadata
>> 4. display-buffer-base-action
>> 5. display-buffer-fallback-action
>
> A few points in favor of
>
> (alist-get 'display-sort-function metadata)
> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
>
> instead:
>
> - Again, the user is still able to configure the display-sort-function
> by configuring the individual completion table.
Does this mean that every individual completion table should have
a separate user option?
> That's not true with display-buffer. The only configuration
> mechanism is display-buffer-alist.
Actually several user options already exist for display-buffer such as
display-comint-buffer-action and display-tex-shell-buffer-action.
They cover a whole category of display-buffer calls that display
all types of comint buffers, etc. So these options correspond
to completion categories, not to individual completion tables.
> - Given that the user can still configure the display-sort-function, I
> don't see any use case where the user should override it. (A buggy
> completion table that returns the wrong display-sort-function? But
> that should just be fixed.)
I don't understand how the user can configure the display-sort-function,
please elaborate.
> - display-buffer-alist is driven purely by buffer-match-p conditions, so
> there's a linear sequence of overriding. The display-sort-function
> has two levels: the completion table and the completion category.
> Since the table is more specific than the category, it should override
> the category.
Agreed. But this means only one thing that a user option
for an individual completion table should take precedence
over completion-category-overrides.
> - As a minor point, I, and many other Emacs users IME, find the
> display-buffer configuration to be complex and hard to use, so I don't
> think we should try to emulate it too much.
What is an alternative? A myriad of individual options?
> - The "overrides" in "completion-category-overrides" is just a name. It
> doesn't mean that we have to make it override everything else.
Why not to do what the name suggests?
> Alternatively, could we just add support for configuring the individual
> table now, and add category-based configuration later? We don't need to
> add everything all at once, and that will give us valuable user
> feedback.
I see no need to add individual options as all. Every completion table
that significantly differs from other tables so that it needs a separate
display-sort-function, could provide a separate category. For example,
there is a category 'buffer'. If 'switch-to-buffer' needs another
display-sort-function it could provide a category 'buffer-for-switching'.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 17:09 ` Juri Linkov
@ 2023-11-21 20:45 ` Spencer Baugh
2023-11-22 7:51 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-21 20:45 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>>> (or
>>>> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
>>>> (alist-get 'display-sort-function metadata)
>>>> (alist-get 'display-sort-function (alist-get category completion-category-defaults))
>>>> completions-sort)
>>>
>>> 1. display-buffer-overriding-action
>>> 2. display-buffer-alist
>>> 3. function call arguments that correspond to completion metadata
>>> 4. display-buffer-base-action
>>> 5. display-buffer-fallback-action
>>
>> A few points in favor of
>>
>> (alist-get 'display-sort-function metadata)
>> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
>>
>> instead:
>>
>> - Again, the user is still able to configure the display-sort-function
>> by configuring the individual completion table.
>
> Does this mean that every individual completion table should have
> a separate user option?
No: only the completion tables which specify a display-sort-function in
their metadata. All such completion tables should have a user option to
configure that display-sort-function.
>> That's not true with display-buffer. The only configuration
>> mechanism is display-buffer-alist.
>
> Actually several user options already exist for display-buffer such as
> display-comint-buffer-action and display-tex-shell-buffer-action.
> They cover a whole category of display-buffer calls that display
> all types of comint buffers, etc. So these options correspond
> to completion categories, not to individual completion tables.
Interesting.
It looks like those user options configure a broad category, as you say,
and they do this by changing the ACTION function call argument in
various places.
So, those user options configure a broad category, and then more
specific configuration overrides that broad category. I suppose that's
what I also suggest for completion sorting.
>> - Given that the user can still configure the display-sort-function, I
>> don't see any use case where the user should override it. (A buggy
>> completion table that returns the wrong display-sort-function? But
>> that should just be fixed.)
>
> I don't understand how the user can configure the display-sort-function,
> please elaborate.
If a completion table specifies a display-sort-function in its metadata,
it should have a user option to configure that display-sort-function.
>> - display-buffer-alist is driven purely by buffer-match-p conditions, so
>> there's a linear sequence of overriding. The display-sort-function
>> has two levels: the completion table and the completion category.
>> Since the table is more specific than the category, it should override
>> the category.
>
> Agreed. But this means only one thing that a user option
> for an individual completion table should take precedence
> over completion-category-overrides.
Well, yes. So then we agree that a user option for an individual
completion table, if it exists, should take precedence over
completion-category-overrides? So then we're only disagreeing over
whether such options should exist?
>> - As a minor point, I, and many other Emacs users IME, find the
>> display-buffer configuration to be complex and hard to use, so I don't
>> think we should try to emulate it too much.
>
> What is an alternative? A myriad of individual options?
For display-buffer configuration? I'm not sure, I don't want to get
into it too much.
For completion sorting configuration, though, I'm not suggesting adding
many individual options. I'm quite happy with the proposal of,
"categories can determine the display-sort-function, and then options
for individual completion tables will override that".
In that world, there would be a read-buffer-sort option - but it would
be nil by default, so the read-buffer completion table by default
wouldn't specify a display-sort-function. And the user could configure
read-buffer completion sorting using completion-category-overrides
however they like; and if they set read-buffer-sort to something else,
then it will in turn override the category-based configuration.
These individual options would also provide a natural place to document
behavior like "if you configure the display-sort-function for buffer
completion to 'identity, then the buffer sort order will match
(buffer-list)". But the user could still make use of that information
by configuring the category.
>> Alternatively, could we just add support for configuring the individual
>> table now, and add category-based configuration later? We don't need to
>> add everything all at once, and that will give us valuable user
>> feedback.
>
> I see no need to add individual options as all. Every completion table
> that significantly differs from other tables so that it needs a separate
> display-sort-function, could provide a separate category. For example,
> there is a category 'buffer'. If 'switch-to-buffer' needs another
> display-sort-function it could provide a category 'buffer-for-switching'.
That won't work with the scenario I described before with sorting
file-name completion by mtime, where changing the sorting requires also
changing the completion table.
Also, this would require adding a category for essentially every
completion table. For example, I see that read-from-kill-ring specifies
a display-sort-function, currently set to 'identity. If we wanted to
make that configurable, it seems much easier to just do
(if (eq action 'metadata)
;; Keep sorted by recency
- '(metadata (display-sort-function . identity))
+ `(metadata (display-sort-function . ,read-from-kill-ring-sort))
(complete-with-action action completions string pred)))
instead of adding a category 'kill-ring and sticking that into
completion-category-defaults.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 17:03 ` Juri Linkov
@ 2023-11-21 22:27 ` John Yates
0 siblings, 0 replies; 107+ messages in thread
From: John Yates @ 2023-11-21 22:27 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, sbaugh, emacs-devel
On Tue, Nov 21, 2023 at 12:12 PM Juri Linkov <juri@linkov.net> wrote:
>
> > Sharing this insight in the associated documentation will aid users.
>
> This is thoroughly documented in (info "(elisp) Choosing Window"):
I was insufficiently clear. I meant the emerging parallel ordering of
completion-category controls and display-buffer control:
> Since completion-category-overrides is a user option
> it corresponds to display-buffer-alist.
> And completion-category-defaults looks like
> display-buffer-base-action.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-21 20:45 ` Spencer Baugh
@ 2023-11-22 7:51 ` Juri Linkov
2023-11-22 16:11 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-22 7:51 UTC (permalink / raw)
To: Spencer Baugh; +Cc: sbaugh, emacs-devel
>>> - Again, the user is still able to configure the display-sort-function
>>> by configuring the individual completion table.
>>
>> Does this mean that every individual completion table should have
>> a separate user option?
>
> No: only the completion tables which specify a display-sort-function in
> their metadata. All such completion tables should have a user option to
> configure that display-sort-function.
How then users could change the sorting order for individual tables
that don't specify a display-sort-function to use an order different
from completions-sort?
> Well, yes. So then we agree that a user option for an individual
> completion table, if it exists, should take precedence over
> completion-category-overrides?
The problem is that we can't distinguish two cases:
1. when display-sort-function is hard-coded in metadata
by the author of the completion table;
2. when display-sort-function in metadata
gets the value from the user option.
Since we can't distinguish these cases, then it makes more sense
when completion-category-overrides overrides everything:
(alist-get 'display-sort-function (alist-get category completion-category-overrides))
(alist-get 'display-sort-function metadata) ;; metadata with/out individual options
(alist-get 'display-sort-function (alist-get category completion-category-defaults))
There is no problem with this because completion-category-overrides
is a user option as well, so everything still is under user control.
> So then we're only disagreeing over whether such options should exist?
Yes, I think we should add individual options only in exceptional cases.
> These individual options would also provide a natural place to document
> behavior like "if you configure the display-sort-function for buffer
> completion to 'identity, then the buffer sort order will match
> (buffer-list)". But the user could still make use of that information
> by configuring the category.
I agree that an option with documentation could help in such cases
when a non-trivial sorting function is provided for a completion table.
>> I see no need to add individual options as all. Every completion table
>> that significantly differs from other tables so that it needs a separate
>> display-sort-function, could provide a separate category. For example,
>> there is a category 'buffer'. If 'switch-to-buffer' needs another
>> display-sort-function it could provide a category 'buffer-for-switching'.
>
> That won't work with the scenario I described before with sorting
> file-name completion by mtime, where changing the sorting requires also
> changing the completion table.
I agree that individual options are required in such rare cases when
their values affect the completion table and its formatting.
> Also, this would require adding a category for essentially every
> completion table. For example, I see that read-from-kill-ring specifies
> a display-sort-function, currently set to 'identity.
It's much simpler to add an extra line with a category.
> If we wanted to make that configurable, it seems much easier to just do
>
> (if (eq action 'metadata)
> ;; Keep sorted by recency
> - '(metadata (display-sort-function . identity))
> + `(metadata (display-sort-function . ,read-from-kill-ring-sort))
> (complete-with-action action completions string pred)))
This is an incomplete patch, there should be also a dozen of lines
with defcustom, its docstring, the version number and a list
of choices, etc. And all this for a very small percent of users
who would like to change this order. This is too wasteful.
It would be much more efficient to allow doing the same
by customizing completion-category-overrides.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-22 7:51 ` Juri Linkov
@ 2023-11-22 16:11 ` Spencer Baugh
2023-11-23 7:58 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-22 16:11 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>>> - Again, the user is still able to configure the display-sort-function
>>>> by configuring the individual completion table.
>>>
>>> Does this mean that every individual completion table should have
>>> a separate user option?
>>
>> No: only the completion tables which specify a display-sort-function in
>> their metadata. All such completion tables should have a user option to
>> configure that display-sort-function.
>
> How then users could change the sorting order for individual tables
> that don't specify a display-sort-function to use an order different
> from completions-sort?
They can use the category if the table specifies one.
If the table neither specifies a category nor provides a table-specific
option, the display sort function for that table isn't currently
configurable. Which I think we're both fine with?
So: we already accept that for some completion tables, it won't be
possible to customize their display sort function out of the box.
>> Well, yes. So then we agree that a user option for an individual
>> completion table, if it exists, should take precedence over
>> completion-category-overrides?
>
> The problem is that we can't distinguish two cases:
>
> 1. when display-sort-function is hard-coded in metadata
> by the author of the completion table;
> 2. when display-sort-function in metadata
> gets the value from the user option.
I think we should just eliminate any instances of case 1.
Case 1 just means the completion table's display sort function isn't
currently configurable. Which I think we've already accepted will be
the case for some tables, until we go and make them configurable either
by adding a table-specific option, adding a category, or both.
> Since we can't distinguish these cases, then it makes more sense
> when completion-category-overrides overrides everything:
>
> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
> (alist-get 'display-sort-function metadata) ;; metadata with/out individual options
> (alist-get 'display-sort-function (alist-get category completion-category-defaults))
>
> There is no problem with this because completion-category-overrides
> is a user option as well, so everything still is under user control.
Only if the completion table specifies a category. Which most do not.
So we'd need to change it to specify a category. And if we're doing
that, we could also change it to not hard-code a display-sort-function
at the same time.
That is, for any tables where the display-sort-function is currently
hardcoded, we can add a category, and remove the hardcoded
display-sort-function from the table metadata, and add the
display-sort-function to completion-category-defaults.
>> So then we're only disagreeing over whether such options should exist?
>
> Yes, I think we should add individual options only in exceptional cases.
>
>> These individual options would also provide a natural place to document
>> behavior like "if you configure the display-sort-function for buffer
>> completion to 'identity, then the buffer sort order will match
>> (buffer-list)". But the user could still make use of that information
>> by configuring the category.
>
> I agree that an option with documentation could help in such cases
> when a non-trivial sorting function is provided for a completion table.
>
>>> I see no need to add individual options as all. Every completion table
>>> that significantly differs from other tables so that it needs a separate
>>> display-sort-function, could provide a separate category. For example,
>>> there is a category 'buffer'. If 'switch-to-buffer' needs another
>>> display-sort-function it could provide a category 'buffer-for-switching'.
>>
>> That won't work with the scenario I described before with sorting
>> file-name completion by mtime, where changing the sorting requires also
>> changing the completion table.
>
> I agree that individual options are required in such rare cases when
> their values affect the completion table and its formatting.
OK, I think I can agree with that, if we agree that in those rare cases,
the individual options should take precedence over the category-based
configuration.
>> Also, this would require adding a category for essentially every
>> completion table. For example, I see that read-from-kill-ring specifies
>> a display-sort-function, currently set to 'identity.
>
> It's much simpler to add an extra line with a category.
>
>> If we wanted to make that configurable, it seems much easier to just do
>>
>> (if (eq action 'metadata)
>> ;; Keep sorted by recency
>> - '(metadata (display-sort-function . identity))
>> + `(metadata (display-sort-function . ,read-from-kill-ring-sort))
>> (complete-with-action action completions string pred)))
>
> This is an incomplete patch, there should be also a dozen of lines
> with defcustom, its docstring, the version number and a list
> of choices, etc. And all this for a very small percent of users
> who would like to change this order. This is too wasteful.
> It would be much more efficient to allow doing the same
> by customizing completion-category-overrides.
The docstring and list of choices for read-from-kill-ring-sort are
something we want anyway - we would like to document that 'identity for
read-for-kill-ring keeps the kill ring sorted by recency, for example.
I see no better place to document that.
The version number is also something we want anyway: if we just add a
category to read-from-kill-ring in Emacs 30, this will work only in
Emacs 30 and not in Emacs 29, and there's no way for a user to know that
other than by reading NEWS.
For such tables, I see three good possibilities (in order of my own
preference):
A.
- Add read-from-kill-ring-sort defaulting to identity (with docstring)
(diff is 1 line + defcustom)
B.
- Add read-from-kill-ring-sort defaulting to nil (with docstring)
- add the 'read-kill category to the metadata
- add 'read-kill to completion-category-defaults
(diff is 3 lines + defcustom)
C.
- Remove display-sort-function from the metadata
- add the 'read-kill category to the metadata
- add 'read-kill to completion-category-defaults
(diff is 3 lines)
If you really don't want the defcustom and associated documentation, I'm
OK with C.
The option which I think is not good is:
D.
- add the 'read-kill category to the metadata
- make completion-category-overrides take precedence over what is
specified in the table metadata
(diff is 1 line)
This is a slightly smaller diff than option C, but I think it's a
fundamentally worse approach than C, because in the rare cases where we
do want an individual option for the table, we won't have a way for that
option to take precedence over the broader category-based configuration.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-22 16:11 ` Spencer Baugh
@ 2023-11-23 7:58 ` Juri Linkov
2023-11-23 12:36 ` sbaugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-23 7:58 UTC (permalink / raw)
To: Spencer Baugh; +Cc: sbaugh, emacs-devel
>>>>> - Again, the user is still able to configure the display-sort-function
>>>>> by configuring the individual completion table.
>>>>
>>>> Does this mean that every individual completion table should have
>>>> a separate user option?
>>>
>>> No: only the completion tables which specify a display-sort-function in
>>> their metadata. All such completion tables should have a user option to
>>> configure that display-sort-function.
>>
>> How then users could change the sorting order for individual tables
>> that don't specify a display-sort-function to use an order different
>> from completions-sort?
>
> They can use the category if the table specifies one.
>
> If the table neither specifies a category nor provides a table-specific
> option, the display sort function for that table isn't currently
> configurable. Which I think we're both fine with?
I think we should gradually add a category to most completion tables
to make them completely configurable, not just with display-sort-function,
but with all possible metadata.
Adding a category resembles a long-lasting and still ongoing process of
adding specific minibuffer history as a symbol to the HIST argument
of different calls of read-from-minibuffer.
> So: we already accept that for some completion tables, it won't be
> possible to customize their display sort function out of the box.
>
>>> Well, yes. So then we agree that a user option for an individual
>>> completion table, if it exists, should take precedence over
>>> completion-category-overrides?
>>
>> The problem is that we can't distinguish two cases:
>>
>> 1. when display-sort-function is hard-coded in metadata
>> by the author of the completion table;
>> 2. when display-sort-function in metadata
>> gets the value from the user option.
>
> I think we should just eliminate any instances of case 1.
I don't think this is realistic to add an individual option in all cases.
> Case 1 just means the completion table's display sort function isn't
> currently configurable. Which I think we've already accepted will be
> the case for some tables, until we go and make them configurable either
> by adding a table-specific option, adding a category, or both.
>
>> Since we can't distinguish these cases, then it makes more sense
>> when completion-category-overrides overrides everything:
>>
>> (alist-get 'display-sort-function (alist-get category completion-category-overrides))
>> (alist-get 'display-sort-function metadata) ;; metadata with/out individual options
>> (alist-get 'display-sort-function (alist-get category completion-category-defaults))
>>
>> There is no problem with this because completion-category-overrides
>> is a user option as well, so everything still is under user control.
>
> Only if the completion table specifies a category. Which most do not.
>
> So we'd need to change it to specify a category.
Agreed.
> And if we're doing that, we could also change it to not hard-code
> a display-sort-function at the same time.
Disagreed when this means to add an option in all cases.
> That is, for any tables where the display-sort-function is currently
> hardcoded, we can add a category, and remove the hardcoded
> display-sort-function from the table metadata, and add the
> display-sort-function to completion-category-defaults.
>
>>> So then we're only disagreeing over whether such options should exist?
>>
>> Yes, I think we should add individual options only in exceptional cases.
>>
>>> These individual options would also provide a natural place to document
>>> behavior like "if you configure the display-sort-function for buffer
>>> completion to 'identity, then the buffer sort order will match
>>> (buffer-list)". But the user could still make use of that information
>>> by configuring the category.
>>
>> I agree that an option with documentation could help in such cases
>> when a non-trivial sorting function is provided for a completion table.
>>
>>>> I see no need to add individual options as all. Every completion table
>>>> that significantly differs from other tables so that it needs a separate
>>>> display-sort-function, could provide a separate category. For example,
>>>> there is a category 'buffer'. If 'switch-to-buffer' needs another
>>>> display-sort-function it could provide a category 'buffer-for-switching'.
>>>
>>> That won't work with the scenario I described before with sorting
>>> file-name completion by mtime, where changing the sorting requires also
>>> changing the completion table.
>>
>> I agree that individual options are required in such rare cases when
>> their values affect the completion table and its formatting.
>
> OK, I think I can agree with that, if we agree that in those rare cases,
> the individual options should take precedence over the category-based
> configuration.
The individual options can't take precedence until all tables don't
hardcode metadata that is hardly achievable.
>>> Also, this would require adding a category for essentially every
>>> completion table. For example, I see that read-from-kill-ring specifies
>>> a display-sort-function, currently set to 'identity.
>>
>> It's much simpler to add an extra line with a category.
>>
>>> If we wanted to make that configurable, it seems much easier to just do
>>>
>>> (if (eq action 'metadata)
>>> ;; Keep sorted by recency
>>> - '(metadata (display-sort-function . identity))
>>> + `(metadata (display-sort-function . ,read-from-kill-ring-sort))
>>> (complete-with-action action completions string pred)))
>>
>> This is an incomplete patch, there should be also a dozen of lines
>> with defcustom, its docstring, the version number and a list
>> of choices, etc. And all this for a very small percent of users
>> who would like to change this order. This is too wasteful.
>> It would be much more efficient to allow doing the same
>> by customizing completion-category-overrides.
>
> The docstring and list of choices for read-from-kill-ring-sort are
> something we want anyway - we would like to document that 'identity for
> read-for-kill-ring keeps the kill ring sorted by recency, for example.
> I see no better place to document that.
>
> The version number is also something we want anyway: if we just add a
> category to read-from-kill-ring in Emacs 30, this will work only in
> Emacs 30 and not in Emacs 29, and there's no way for a user to know that
> other than by reading NEWS.
I don't think such unnecessary defcustoms should be added lightly,
even documentation is of no help for such obvious things as 'identity'
that intuitively is understandable as keeping the original order.
> For such tables, I see three good possibilities (in order of my own
> preference):
>
> A.
> - Add read-from-kill-ring-sort defaulting to identity (with docstring)
> (diff is 1 line + defcustom)
>
> B.
> - Add read-from-kill-ring-sort defaulting to nil (with docstring)
> - add the 'read-kill category to the metadata
> - add 'read-kill to completion-category-defaults
> (diff is 3 lines + defcustom)
>
> C.
> - Remove display-sort-function from the metadata
> - add the 'read-kill category to the metadata
> - add 'read-kill to completion-category-defaults
> (diff is 3 lines)
>
> If you really don't want the defcustom and associated documentation, I'm
> OK with C.
>
> The option which I think is not good is:
>
> D.
> - add the 'read-kill category to the metadata
> - make completion-category-overrides take precedence over what is
> specified in the table metadata
>
> (diff is 1 line)
>
> This is a slightly smaller diff than option C, but I think it's a
> fundamentally worse approach than C, because in the rare cases where we
> do want an individual option for the table, we won't have a way for that
> option to take precedence over the broader category-based configuration.
I still don't understand why do you worry about this precedence when
the user option completion-category-overrides is nil by default.
Could you describe a use cases when such precedence might become a problem?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-23 7:58 ` Juri Linkov
@ 2023-11-23 12:36 ` sbaugh
2023-11-24 7:58 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-11-23 12:36 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>>>>> - Again, the user is still able to configure the display-sort-function
>>>>>> by configuring the individual completion table.
>>>>>
>>>>> Does this mean that every individual completion table should have
>>>>> a separate user option?
>>>>
>>>> No: only the completion tables which specify a display-sort-function in
>>>> their metadata. All such completion tables should have a user option to
>>>> configure that display-sort-function.
>>>
>>> How then users could change the sorting order for individual tables
>>> that don't specify a display-sort-function to use an order different
>>> from completions-sort?
>>
>> They can use the category if the table specifies one.
>>
>> If the table neither specifies a category nor provides a table-specific
>> option, the display sort function for that table isn't currently
>> configurable. Which I think we're both fine with?
>
> I think we should gradually add a category to most completion tables
> to make them completely configurable, not just with display-sort-function,
> but with all possible metadata.
>
> Adding a category resembles a long-lasting and still ongoing process of
> adding specific minibuffer history as a symbol to the HIST argument
> of different calls of read-from-minibuffer.
Agreed.
>>> The problem is that we can't distinguish two cases:
>>>
>>> 1. when display-sort-function is hard-coded in metadata
>>> by the author of the completion table;
>>> 2. when display-sort-function in metadata
>>> gets the value from the user option.
>>
>> I think we should just eliminate any instances of case 1.
>
> I don't think this is realistic to add an individual option in all cases.
That's not necessary. We could also do possibility C that I described
before:
>> C.
>> - Remove display-sort-function from the metadata
>> - add the 'read-kill category to the metadata
>> - add 'read-kill to completion-category-defaults
>> (diff is 3 lines)
That seems simple and straightforward.
>>>> If we wanted to make that configurable, it seems much easier to just do
>>>>
>>>> (if (eq action 'metadata)
>>>> ;; Keep sorted by recency
>>>> - '(metadata (display-sort-function . identity))
>>>> + `(metadata (display-sort-function . ,read-from-kill-ring-sort))
>>>> (complete-with-action action completions string pred)))
>>>
>>> This is an incomplete patch, there should be also a dozen of lines
>>> with defcustom, its docstring, the version number and a list
>>> of choices, etc. And all this for a very small percent of users
>>> who would like to change this order. This is too wasteful.
>>> It would be much more efficient to allow doing the same
>>> by customizing completion-category-overrides.
>>
>> The docstring and list of choices for read-from-kill-ring-sort are
>> something we want anyway - we would like to document that 'identity for
>> read-for-kill-ring keeps the kill ring sorted by recency, for example.
>> I see no better place to document that.
>>
>> The version number is also something we want anyway: if we just add a
>> category to read-from-kill-ring in Emacs 30, this will work only in
>> Emacs 30 and not in Emacs 29, and there's no way for a user to know that
>> other than by reading NEWS.
>
> I don't think such unnecessary defcustoms should be added lightly,
> even documentation is of no help for such obvious things as 'identity'
> that intuitively is understandable as keeping the original order.
Identity obviously keeps the original order, but what is the original
order? That is not documented anywhere and I don't think it's
intuitive. The user can always just try it and see, but that's a poor
substitute for documentation.
>> For such tables, I see three good possibilities (in order of my own
>> preference):
>>
>> A.
>> - Add read-from-kill-ring-sort defaulting to identity (with docstring)
>> (diff is 1 line + defcustom)
>>
>> B.
>> - Add read-from-kill-ring-sort defaulting to nil (with docstring)
>> - add the 'read-kill category to the metadata
>> - add 'read-kill to completion-category-defaults
>> (diff is 3 lines + defcustom)
>>
>> C.
>> - Remove display-sort-function from the metadata
>> - add the 'read-kill category to the metadata
>> - add 'read-kill to completion-category-defaults
>> (diff is 3 lines)
>>
>> If you really don't want the defcustom and associated documentation, I'm
>> OK with C.
>>
>> The option which I think is not good is:
>>
>> D.
>> - add the 'read-kill category to the metadata
>> - make completion-category-overrides take precedence over what is
>> specified in the table metadata
>>
>> (diff is 1 line)
>>
>> This is a slightly smaller diff than option C, but I think it's a
>> fundamentally worse approach than C, because in the rare cases where we
>> do want an individual option for the table, we won't have a way for that
>> option to take precedence over the broader category-based configuration.
>
> I still don't understand why do you worry about this precedence when
> the user option completion-category-overrides is nil by default.
>
> Could you describe a use cases when such precedence might become a problem?
If some table needs an individual option (because the sorting needs to
affect the completion generation), but the table shares a category with
other tables, then that individual option will be overridden by the
category configuration.
For example, project-prompt-project-name allows one to complete over
project names. If I wanted to sort its completions by some detail of
the underlying project (how recently the git repo was updated, maybe),
that would require the table to change behavior. So it would need an
individual option.
However, project-prompt-project-name uses the same category as
project-find-file. So if the user configured sorting for
project-find-file, it will override the table-specific option for
project-prompt-project-name.
I suppose another option is to simply declare that every table has to
have a unique category. That would make "category" a misnomer though.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-23 12:36 ` sbaugh
@ 2023-11-24 7:58 ` Juri Linkov
2023-11-25 16:44 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-24 7:58 UTC (permalink / raw)
To: sbaugh; +Cc: Spencer Baugh, emacs-devel
>> I don't think this is realistic to add an individual option in all cases.
>
> That's not necessary. We could also do possibility C that I described
> before:
>
>>> C.
>>> - Remove display-sort-function from the metadata
>>> - add the 'read-kill category to the metadata
>>> - add 'read-kill to completion-category-defaults
>>> (diff is 3 lines)
>
> That seems simple and straightforward.
Removing display-sort-function is still less safe
than just adding a category.
> Identity obviously keeps the original order, but what is the original
> order? That is not documented anywhere and I don't think it's
> intuitive. The user can always just try it and see, but that's a poor
> substitute for documentation.
In these rare cases when the default order is not intuitive,
this can be explained in the docstring of the command that uses
'completing-read', e.g. in the docstring of 'read-from-kill-ring'.
>> I still don't understand why do you worry about this precedence when
>> the user option completion-category-overrides is nil by default.
>>
>> Could you describe a use cases when such precedence might become a problem?
>
> If some table needs an individual option (because the sorting needs to
> affect the completion generation), but the table shares a category with
> other tables, then that individual option will be overridden by the
> category configuration.
Agreed, this is a problem.
> For example, project-prompt-project-name allows one to complete over
> project names. If I wanted to sort its completions by some detail of
> the underlying project (how recently the git repo was updated, maybe),
> that would require the table to change behavior. So it would need an
> individual option.
Or an individual subcategory.
> However, project-prompt-project-name uses the same category as
> project-find-file. So if the user configured sorting for
> project-find-file, it will override the table-specific option for
> project-prompt-project-name.
I believe they should use two different subcategories, e.g.
'project-file' and 'project-name'.
> I suppose another option is to simply declare that every table has to
> have a unique category. That would make "category" a misnomer though.
Even such subcategories as 'project-name' make sense to use in other
possible cases when reading a project name.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-24 7:58 ` Juri Linkov
@ 2023-11-25 16:44 ` Spencer Baugh
2023-11-25 18:31 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-25 16:44 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>> I don't think this is realistic to add an individual option in all cases.
>>
>> That's not necessary. We could also do possibility C that I described
>> before:
>>
>>>> C.
>>>> - Remove display-sort-function from the metadata
>>>> - add the 'read-kill category to the metadata
>>>> - add 'read-kill to completion-category-defaults
>>>> (diff is 3 lines)
>>
>> That seems simple and straightforward.
>
> Removing display-sort-function is still less safe
> than just adding a category.
Why do you say that?
The reason that comes to mind is that there are replacement completion
UIs which will need to explicitly add support for the category. So
removing display-sort-function will affect them immediately, when they
might not yet have support for getting display-sort-function from
completion-category-defaults.
That is true.
But that actually suggests a further argument in this direction: if we
use user options which change the display-sort-function in the table
metadata, we'll have support for all completion UIs out of the box.
That seems really desirable! So maybe we do want a solution like A
where we add a user option? Since that user option will work for all
completion UIs.
Announcing "you can now customize the sorting order of a bunch of
completing-read-based things in this new way" but having that new way
only work for the default completion UI is a bit sad, although of course
they can support the new way eventually.
>> Identity obviously keeps the original order, but what is the original
>> order? That is not documented anywhere and I don't think it's
>> intuitive. The user can always just try it and see, but that's a poor
>> substitute for documentation.
>
> In these rare cases when the default order is not intuitive,
> this can be explained in the docstring of the command that uses
> 'completing-read', e.g. in the docstring of 'read-from-kill-ring'.
Hm, I do think the wording on that would be a bit tricky. Since
*actually* the default behavior today is alphabetical sorting. We would
want to say "if completions-sort is nil, read-buffer completions are in
buffer-list order".
I guess it's not too bad, but we also need to document the category
symbol. And perhaps the version it was added in. All together it still
seems to me that it would be better to just mention
'read-from-kill-ring-sort' in the docstring of 'read-from-kill-ring'.
>>> I still don't understand why do you worry about this precedence when
>>> the user option completion-category-overrides is nil by default.
>>>
>>> Could you describe a use cases when such precedence might become a problem?
>>
>> If some table needs an individual option (because the sorting needs to
>> affect the completion generation), but the table shares a category with
>> other tables, then that individual option will be overridden by the
>> category configuration.
>
> Agreed, this is a problem.
>
>> For example, project-prompt-project-name allows one to complete over
>> project names. If I wanted to sort its completions by some detail of
>> the underlying project (how recently the git repo was updated, maybe),
>> that would require the table to change behavior. So it would need an
>> individual option.
>
> Or an individual subcategory.
>
>> However, project-prompt-project-name uses the same category as
>> project-find-file. So if the user configured sorting for
>> project-find-file, it will override the table-specific option for
>> project-prompt-project-name.
>
> I believe they should use two different subcategories, e.g.
> 'project-file' and 'project-name'.
I agree, but...
>> I suppose another option is to simply declare that every table has to
>> have a unique category. That would make "category" a misnomer though.
>
> Even such subcategories as 'project-name' make sense to use in other
> possible cases when reading a project name.
...if the project-name category is used for other tables too, but the
option is supposed to be specific to an individual completion table,
then we have the same problem again.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-25 16:44 ` Spencer Baugh
@ 2023-11-25 18:31 ` Juri Linkov
2023-11-26 13:33 ` sbaugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-25 18:31 UTC (permalink / raw)
To: Spencer Baugh; +Cc: Spencer Baugh, emacs-devel
>>>> I don't think this is realistic to add an individual option in all cases.
>>>
>>> That's not necessary. We could also do possibility C that I described
>>> before:
>>>
>>>>> C.
>>>>> - Remove display-sort-function from the metadata
>>>>> - add the 'read-kill category to the metadata
>>>>> - add 'read-kill to completion-category-defaults
>>>>> (diff is 3 lines)
>>>
>>> That seems simple and straightforward.
>>
>> Removing display-sort-function is still less safe
>> than just adding a category.
>
> Why do you say that?
>
> The reason that comes to mind is that there are replacement completion
> UIs which will need to explicitly add support for the category. So
> removing display-sort-function will affect them immediately, when they
> might not yet have support for getting display-sort-function from
> completion-category-defaults.
>
> That is true.
>
> But that actually suggests a further argument in this direction: if we
> use user options which change the display-sort-function in the table
> metadata, we'll have support for all completion UIs out of the box.
>
> That seems really desirable! So maybe we do want a solution like A
> where we add a user option? Since that user option will work for all
> completion UIs.
>
> Announcing "you can now customize the sorting order of a bunch of
> completing-read-based things in this new way" but having that new way
> only work for the default completion UI is a bit sad, although of course
> they can support the new way eventually.
This is what I believe they should do: we add a category,
and they support it as well.
>>> Identity obviously keeps the original order, but what is the original
>>> order? That is not documented anywhere and I don't think it's
>>> intuitive. The user can always just try it and see, but that's a poor
>>> substitute for documentation.
>>
>> In these rare cases when the default order is not intuitive,
>> this can be explained in the docstring of the command that uses
>> 'completing-read', e.g. in the docstring of 'read-from-kill-ring'.
>
> Hm, I do think the wording on that would be a bit tricky. Since
> *actually* the default behavior today is alphabetical sorting. We would
> want to say "if completions-sort is nil, read-buffer completions are in
> buffer-list order".
>
> I guess it's not too bad, but we also need to document the category
> symbol. And perhaps the version it was added in. All together it still
> seems to me that it would be better to just mention
> 'read-from-kill-ring-sort' in the docstring of 'read-from-kill-ring'.
I'm still not convinced that a user option is needed for such minor thing.
>>>> I still don't understand why do you worry about this precedence when
>>>> the user option completion-category-overrides is nil by default.
>>>>
>>>> Could you describe a use cases when such precedence might become a problem?
>>>
>>> If some table needs an individual option (because the sorting needs to
>>> affect the completion generation), but the table shares a category with
>>> other tables, then that individual option will be overridden by the
>>> category configuration.
>>
>> Agreed, this is a problem.
>>
>>> For example, project-prompt-project-name allows one to complete over
>>> project names. If I wanted to sort its completions by some detail of
>>> the underlying project (how recently the git repo was updated, maybe),
>>> that would require the table to change behavior. So it would need an
>>> individual option.
>>
>> Or an individual subcategory.
>>
>>> However, project-prompt-project-name uses the same category as
>>> project-find-file. So if the user configured sorting for
>>> project-find-file, it will override the table-specific option for
>>> project-prompt-project-name.
>>
>> I believe they should use two different subcategories, e.g.
>> 'project-file' and 'project-name'.
>
> I agree, but...
>
>>> I suppose another option is to simply declare that every table has to
>>> have a unique category. That would make "category" a misnomer though.
>>
>> Even such subcategories as 'project-name' make sense to use in other
>> possible cases when reading a project name.
>
> ...if the project-name category is used for other tables too, but the
> option is supposed to be specific to an individual completion table,
> then we have the same problem again.
And an alternative to add separate options to all these tables
doesn't look more attractive.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-25 18:31 ` Juri Linkov
@ 2023-11-26 13:33 ` sbaugh
2023-11-27 7:28 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: sbaugh @ 2023-11-26 13:33 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 4169 bytes --]
Juri Linkov <juri@linkov.net> writes:
>>>>> I don't think this is realistic to add an individual option in all cases.
>>>>
>>>> That's not necessary. We could also do possibility C that I described
>>>> before:
>>>>
>>>>>> C.
>>>>>> - Remove display-sort-function from the metadata
>>>>>> - add the 'read-kill category to the metadata
>>>>>> - add 'read-kill to completion-category-defaults
>>>>>> (diff is 3 lines)
>>>>
>>>> That seems simple and straightforward.
>>>
>>> Removing display-sort-function is still less safe
>>> than just adding a category.
>>
>> Why do you say that?
>>
>> The reason that comes to mind is that there are replacement completion
>> UIs which will need to explicitly add support for the category. So
>> removing display-sort-function will affect them immediately, when they
>> might not yet have support for getting display-sort-function from
>> completion-category-defaults.
>>
>> That is true.
>>
>> But that actually suggests a further argument in this direction: if we
>> use user options which change the display-sort-function in the table
>> metadata, we'll have support for all completion UIs out of the box.
>>
>> That seems really desirable! So maybe we do want a solution like A
>> where we add a user option? Since that user option will work for all
>> completion UIs.
>>
>> Announcing "you can now customize the sorting order of a bunch of
>> completing-read-based things in this new way" but having that new way
>> only work for the default completion UI is a bit sad, although of course
>> they can support the new way eventually.
>
> This is what I believe they should do: we add a category,
> and they support it as well.
OK, I'm fine with that, but when we do that, I think the per-table
option should override the per-category option.
>>>>> I still don't understand why do you worry about this precedence when
>>>>> the user option completion-category-overrides is nil by default.
>>>>>
>>>>> Could you describe a use cases when such precedence might become a problem?
>>>>
>>>> If some table needs an individual option (because the sorting needs to
>>>> affect the completion generation), but the table shares a category with
>>>> other tables, then that individual option will be overridden by the
>>>> category configuration.
>>>
>>> Agreed, this is a problem.
>>>
>>>> For example, project-prompt-project-name allows one to complete over
>>>> project names. If I wanted to sort its completions by some detail of
>>>> the underlying project (how recently the git repo was updated, maybe),
>>>> that would require the table to change behavior. So it would need an
>>>> individual option.
>>>
>>> Or an individual subcategory.
>>>
>>>> However, project-prompt-project-name uses the same category as
>>>> project-find-file. So if the user configured sorting for
>>>> project-find-file, it will override the table-specific option for
>>>> project-prompt-project-name.
>>>
>>> I believe they should use two different subcategories, e.g.
>>> 'project-file' and 'project-name'.
>>
>> I agree, but...
>>
>>>> I suppose another option is to simply declare that every table has to
>>>> have a unique category. That would make "category" a misnomer though.
>>>
>>> Even such subcategories as 'project-name' make sense to use in other
>>> possible cases when reading a project name.
>>
>> ...if the project-name category is used for other tables too, but the
>> option is supposed to be specific to an individual completion table,
>> then we have the same problem again.
>
> And an alternative to add separate options to all these tables
> doesn't look more attractive.
Yes, but we don't have to do that, I'm OK with a category-based
approach. I just think we should reserve the *ability* to use
table-specific options, by making a table-specific display-sort-function
override the category-specific display-sort-function.
Anyway, we're going around in circles a bit here. How about this patch
which only adds the new historical option to completions-sort? I think
we're in agreement on everything in this patch, and maybe installing it
will get some user feedback which we can use when coming back to this
later.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-historical-option-to-completions-sort.patch --]
[-- Type: text/x-patch, Size: 5242 bytes --]
From c4435be3689278d380099f2341ac242bf74639df Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Tue, 17 Oct 2023 09:09:55 -0400
Subject: [PATCH] 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.
---
lisp/minibuffer.el | 63 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 57 insertions(+), 6 deletions(-)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 5c12d9fc914..dfb30e4364c 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1314,14 +1314,26 @@ completion-cycle-threshold
(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 nil, sorting is disabled.
+If `alphabetical', candidates are sorted by
+`minibuffer-sort-alphabetically'.
+If `historical', candidates are sorted by
+`minibuffer-sort-by-history'.
+If a function, the function is called to sort the candidates.
+The sorting function takes and returns a list of completion
+candidate strings.
+
+If the completion-specific metadata provides a
+`display-sort-function', that is used instead and this value is
+ignored."
: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 +1659,43 @@ minibuffer--sort-preprocess-history
(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 is not
+being completed on. 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 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))
@@ -2409,6 +2458,7 @@ minibuffer-completion-help
(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
@@ -2473,7 +2523,8 @@ minibuffer-completion-help
(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
--
2.42.1
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-26 13:33 ` sbaugh
@ 2023-11-27 7:28 ` Juri Linkov
2023-11-28 14:38 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-27 7:28 UTC (permalink / raw)
To: sbaugh; +Cc: Spencer Baugh, emacs-devel
>> This is what I believe they should do: we add a category,
>> and they support it as well.
>
> OK, I'm fine with that, but when we do that, I think the per-table
> option should override the per-category option.
I agree that the per-table option should override the per-category option,
but see no way to distinguish customized values from hard-coded ones
without trying to turn all hard-coded values into options.
display-buffer has a similar problem, but the difference is that
it's possible to identify a buffer by its name and use a regexp
to match buffer names. Whereas for completing-read it's not easy
to identify a completion table. A category matches a set of
completion tables, so maybe we need another identification
for individual tables?
> I'm OK with a category-based approach. I just think we should reserve
> the *ability* to use table-specific options, by making a table-specific
> display-sort-function override the category-specific display-sort-function.
Probably introducing a new field to metadata could help to resolve ambiguities.
> Anyway, we're going around in circles a bit here. How about this patch
> which only adds the new historical option to completions-sort? I think
> we're in agreement on everything in this patch, and maybe installing it
> will get some user feedback which we can use when coming back to this
> later.
Thanks, everything looks nice, only a etc/NEWS announcement is missing.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-27 7:28 ` Juri Linkov
@ 2023-11-28 14:38 ` Spencer Baugh
2023-11-28 15:03 ` Eli Zaretskii
2023-11-28 17:16 ` Juri Linkov
0 siblings, 2 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-11-28 14:38 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1926 bytes --]
Juri Linkov <juri@linkov.net> writes:
>>> This is what I believe they should do: we add a category,
>>> and they support it as well.
>>
>> OK, I'm fine with that, but when we do that, I think the per-table
>> option should override the per-category option.
>
> I agree that the per-table option should override the per-category option,
> but see no way to distinguish customized values from hard-coded ones
> without trying to turn all hard-coded values into options.
Right. I guess my position is that there's not that many hard-coded
display-sort-functions (only 5 in core Emacs), so turning them all to
options is fine.
> display-buffer has a similar problem, but the difference is that
> it's possible to identify a buffer by its name and use a regexp
> to match buffer names. Whereas for completing-read it's not easy
> to identify a completion table. A category matches a set of
> completion tables, so maybe we need another identification
> for individual tables?
True, that would help. Maybe the function symbol for the completion
table? Tables are usually lambdas today, but maybe we could make it
easy to use a defun'd function instead, which would be very good for
comprehensibility in general IMO.
>> I'm OK with a category-based approach. I just think we should reserve
>> the *ability* to use table-specific options, by making a table-specific
>> display-sort-function override the category-specific display-sort-function.
>
> Probably introducing a new field to metadata could help to resolve ambiguities.
>
>> Anyway, we're going around in circles a bit here. How about this patch
>> which only adds the new historical option to completions-sort? I think
>> we're in agreement on everything in this patch, and maybe installing it
>> will get some user feedback which we can use when coming back to this
>> later.
>
> Thanks, everything looks nice, only a etc/NEWS announcement is missing.
Added.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-historical-option-to-completions-sort.patch --]
[-- Type: text/x-patch, Size: 5875 bytes --]
From 4196334888fb35395deca9418203f3622dedbaff Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Tue, 17 Oct 2023 09:09:55 -0400
Subject: [PATCH] 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.
---
etc/NEWS | 5 ++++
lisp/minibuffer.el | 63 +++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index fd633fad6fb..eefa9692e07 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -620,6 +620,11 @@ completions window. When the completions window is not visible,
then all these keys have their usual meaning in the minibuffer.
This option is supported for in-buffer completion as well.
+*** New value for 'historical' for user option 'completions-sort'
+When 'completions-sort' is set to 'historical', completion candidates
+will be sorted by their position in the minibuffer history, more
+recent candidates appearing first.
+
** Pcomplete
---
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 5c12d9fc914..dfb30e4364c 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1314,14 +1314,26 @@ completion-cycle-threshold
(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 nil, sorting is disabled.
+If `alphabetical', candidates are sorted by
+`minibuffer-sort-alphabetically'.
+If `historical', candidates are sorted by
+`minibuffer-sort-by-history'.
+If a function, the function is called to sort the candidates.
+The sorting function takes and returns a list of completion
+candidate strings.
+
+If the completion-specific metadata provides a
+`display-sort-function', that is used instead and this value is
+ignored."
: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 +1659,43 @@ minibuffer--sort-preprocess-history
(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 is not
+being completed on. 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 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))
@@ -2409,6 +2458,7 @@ minibuffer-completion-help
(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
@@ -2473,7 +2523,8 @@ minibuffer-completion-help
(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
--
2.42.1
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 14:38 ` Spencer Baugh
@ 2023-11-28 15:03 ` Eli Zaretskii
2023-11-28 17:13 ` Juri Linkov
2023-11-28 23:56 ` Spencer Baugh
2023-11-28 17:16 ` Juri Linkov
1 sibling, 2 replies; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-28 15:03 UTC (permalink / raw)
To: Spencer Baugh; +Cc: juri, sbaugh, emacs-devel
> From: Spencer Baugh <sbaugh@catern.com>
> Date: Tue, 28 Nov 2023 14:38:55 +0000 (UTC)
> Cc: Spencer Baugh <sbaugh@janestreet.com>, emacs-devel@gnu.org
>
> +*** New value for 'historical' for user option 'completions-sort'
^^^
That "for" should be removed.
> +When 'completions-sort' is set to 'historical', completion candidates
> +will be sorted by their position in the minibuffer history, more
^^^^^^^^
Not "position", but chronological order.
> +Completion candidates in the *Completions* buffer are sorted
> +depending on the value.
> +
> +If nil, sorting is disabled.
"If it's nil, sorting is disabled."
> +If `alphabetical', candidates are sorted by
> +`minibuffer-sort-alphabetically'.
"If it's `alphabetical', candidates are sorted..."
Etc.
Also, did you make sure these symbols are not highlighted as links
even if a function or variable by that name exists? I think you
should use this technique from "Documentation Tips" to prevent that:
If a symbol has a function definition and/or a variable definition,
but those are irrelevant to the use of the symbol that you are
documenting, you can write the words ‘symbol’ or ‘program’ before
the symbol name to prevent making any hyperlink.
> +If a function, the function is called to sort the candidates.
> +The sorting function takes and returns a list of completion
> +candidate strings.
Can it return the same list, or should it always return a copy?
> +If the completion-specific metadata provides a
> +`display-sort-function', that is used instead and this value is
> +ignored."
"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)
^^^^^^^^^^^^^^^^^^
"Chronological sorting"
> +(defvar minibuffer-completion-base nil
> + "The base for the current completion.
> +
> +This is the part of the current minibuffer input which is not
> +being completed on.
I couldn't understand what this sentence means.
> +(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 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'.
Again, please use "chronologically" here, not "by history".
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 15:03 ` Eli Zaretskii
@ 2023-11-28 17:13 ` Juri Linkov
2023-11-28 17:36 ` Eli Zaretskii
2023-11-28 23:56 ` Spencer Baugh
1 sibling, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-28 17:13 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Spencer Baugh, sbaugh, emacs-devel
>> :type '(choice (const :tag "No sorting" nil)
>> (const :tag "Alphabetical sorting" alphabetical)
>> + (const :tag "Historical sorting" historical)
> ^^^^^^^^^^^^^^^^^^
> "Chronological sorting"
Chronological sorting is how a list of buffers sorted by recency.
Historical sorting is how items in history are sorted by input.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 14:38 ` Spencer Baugh
2023-11-28 15:03 ` Eli Zaretskii
@ 2023-11-28 17:16 ` Juri Linkov
2023-11-28 23:36 ` Turning completion table lambdas into symbols Spencer Baugh
1 sibling, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-28 17:16 UTC (permalink / raw)
To: Spencer Baugh; +Cc: Spencer Baugh, emacs-devel
>>>> This is what I believe they should do: we add a category,
>>>> and they support it as well.
>>>
>>> OK, I'm fine with that, but when we do that, I think the per-table
>>> option should override the per-category option.
>>
>> I agree that the per-table option should override the per-category option,
>> but see no way to distinguish customized values from hard-coded ones
>> without trying to turn all hard-coded values into options.
>
> Right. I guess my position is that there's not that many hard-coded
> display-sort-functions (only 5 in core Emacs), so turning them all to
> options is fine.
And my position is that simpler to add a category or some identifier.
So we need more opinions.
>> display-buffer has a similar problem, but the difference is that
>> it's possible to identify a buffer by its name and use a regexp
>> to match buffer names. Whereas for completing-read it's not easy
>> to identify a completion table. A category matches a set of
>> completion tables, so maybe we need another identification
>> for individual tables?
>
> True, that would help. Maybe the function symbol for the completion
> table? Tables are usually lambdas today, but maybe we could make it
> easy to use a defun'd function instead, which would be very good for
> comprehensibility in general IMO.
Turning lambdas into symbols looks good, this is like the existing
'help--symbol-completion-table'.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 17:13 ` Juri Linkov
@ 2023-11-28 17:36 ` Eli Zaretskii
2023-11-29 7:11 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-28 17:36 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, sbaugh, emacs-devel
> From: Juri Linkov <juri@linkov.net>
> Cc: Spencer Baugh <sbaugh@catern.com>, sbaugh@janestreet.com,
> emacs-devel@gnu.org
> Date: Tue, 28 Nov 2023 19:13:01 +0200
>
> >> :type '(choice (const :tag "No sorting" nil)
> >> (const :tag "Alphabetical sorting" alphabetical)
> >> + (const :tag "Historical sorting" historical)
> > ^^^^^^^^^^^^^^^^^^
> > "Chronological sorting"
>
> Chronological sorting is how a list of buffers sorted by recency.
> Historical sorting is how items in history are sorted by input.
Aren't they the same order? If not, why not?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Turning completion table lambdas into symbols
2023-11-28 17:16 ` Juri Linkov
@ 2023-11-28 23:36 ` Spencer Baugh
2023-11-28 23:51 ` Dmitry Gutov
2023-11-29 7:18 ` Juri Linkov
0 siblings, 2 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-11-28 23:36 UTC (permalink / raw)
To: Juri Linkov; +Cc: Spencer Baugh, emacs-devel
Juri Linkov <juri@linkov.net> writes:
>>> display-buffer has a similar problem, but the difference is that
>>> it's possible to identify a buffer by its name and use a regexp
>>> to match buffer names. Whereas for completing-read it's not easy
>>> to identify a completion table. A category matches a set of
>>> completion tables, so maybe we need another identification
>>> for individual tables?
>>
>> True, that would help. Maybe the function symbol for the completion
>> table? Tables are usually lambdas today, but maybe we could make it
>> easy to use a defun'd function instead, which would be very good for
>> comprehensibility in general IMO.
>
> Turning lambdas into symbols looks good, this is like the existing
> 'help--symbol-completion-table'.
Like 'help--symbol-completion-table' in what way?
One thing that requires a lambda is when the table is over some custom
data. But that can sometimes be avoided by moving the logic into the
table, like this for example:
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1765,6 +1765,13 @@ project-forget-project
(defvar project--dir-history)
+(defun project--project-dir-completion-table (string pred action)
+ (cond
+ ((eq action 'metadata)
+ '(metadata . ((category . project-dir))))
+ (t
+ (complete-with-action action (cons "... (choose a dir)" project--list) string pred))))
+
(defun project-prompt-project-dir ()
"Prompt the user for a directory that is one of the known project roots.
The project is chosen among projects known from the project list,
@@ -1772,18 +1779,14 @@ project-prompt-project-dir
It's also possible to enter an arbitrary directory not in the list."
(project--ensure-read-project-list)
(let* ((dir-choice "... (choose a dir)")
- (choices
- ;; XXX: Just using this for the category (for the substring
- ;; completion style).
- (project--file-completion-table
- (append project--list `(,dir-choice))))
(project--dir-history (project-known-project-roots))
(pr-dir ""))
(while (equal pr-dir "")
;; If the user simply pressed RET, do this again until they don't.
(setq pr-dir
(let (history-add-new-input)
- (completing-read "Select project: " choices nil t nil 'project--dir-history))))
+ (completing-read "Select project: " #'project--project-dir-completion-table
+ nil t nil 'project--dir-history))))
(if (equal pr-dir dir-choice)
(read-directory-name "Select directory: " default-directory nil t)
pr-dir)))
The trickier case is when the table actually has some internal state or
calculation which it needs to preserve across multiple calls. Like I
recently asked about in my recent mail to emacs-devel with subject
"State and caching in completion tables".
If there was a canonical way for a completion table to maintain some
state which *doesn't* require the completion table to be a lambda, I
think most completion tables could become defuns instead of lambdas.
(And then they could be customized based on the function symbol)
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Turning completion table lambdas into symbols
2023-11-28 23:36 ` Turning completion table lambdas into symbols Spencer Baugh
@ 2023-11-28 23:51 ` Dmitry Gutov
2023-11-29 19:26 ` Spencer Baugh
2023-11-29 7:18 ` Juri Linkov
1 sibling, 1 reply; 107+ messages in thread
From: Dmitry Gutov @ 2023-11-28 23:51 UTC (permalink / raw)
To: Spencer Baugh, Juri Linkov; +Cc: Spencer Baugh, emacs-devel
On 29/11/2023 01:36, Spencer Baugh wrote:
> If there was a canonical way for a completion table to maintain some
> state which*doesn't* require the completion table to be a lambda, I
> think most completion tables could become defuns instead of lambdas.
> (And then they could be customized based on the function symbol)
Maybe take a look at how company-capf caches the results of calling a
CAPF function?
Depending on the data, the cache key is either
buffer/point/chars-modified-tick tuple, or the "completion session" (but
in a company-mode specific way).
For CAPF and Company, we also discussed the idea of a "session object"
some time ago, but that's not in the current API so far.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 15:03 ` Eli Zaretskii
2023-11-28 17:13 ` Juri Linkov
@ 2023-11-28 23:56 ` Spencer Baugh
2023-11-29 3:33 ` Eli Zaretskii
2023-12-03 17:25 ` Juri Linkov
1 sibling, 2 replies; 107+ messages in thread
From: Spencer Baugh @ 2023-11-28 23:56 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: juri, sbaugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 648 bytes --]
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@catern.com>
>> Date: Tue, 28 Nov 2023 14:38:55 +0000 (UTC)
>> Cc: Spencer Baugh <sbaugh@janestreet.com>, emacs-devel@gnu.org
>> :type '(choice (const :tag "No sorting" nil)
>> (const :tag "Alphabetical sorting" alphabetical)
>> + (const :tag "Historical sorting" historical)
> ^^^^^^^^^^^^^^^^^^
> "Chronological sorting"
I think "historical sorting" is more intuitive here. "Chronological"
seems more ambiguous - it could mean something different for files, for
example.
Fixed patch for everything else:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-historical-option-to-completions-sort.patch --]
[-- Type: text/x-patch, Size: 6072 bytes --]
From 326da292ef0512a518ec5ed7140c028e53cb6cd7 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Tue, 17 Oct 2023 09:09:55 -0400
Subject: [PATCH] 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.
---
etc/NEWS | 5 ++++
lisp/minibuffer.el | 65 +++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 64 insertions(+), 6 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index fd633fad6fb..12a37176ee0 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -620,6 +620,11 @@ completions window. When the completions window is not visible,
then all these keys have their usual meaning in the minibuffer.
This option is supported for in-buffer completion as well.
+*** 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 5c12d9fc914..77703a4e330 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1314,14 +1314,27 @@ completion-cycle-threshold
(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 @@ minibuffer--sort-preprocess-history
(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))
@@ -2409,6 +2460,7 @@ minibuffer-completion-help
(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
@@ -2473,7 +2525,8 @@ minibuffer-completion-help
(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
--
2.42.1
^ permalink raw reply related [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 23:56 ` Spencer Baugh
@ 2023-11-29 3:33 ` Eli Zaretskii
2023-12-03 17:25 ` Juri Linkov
1 sibling, 0 replies; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-29 3:33 UTC (permalink / raw)
To: Spencer Baugh; +Cc: juri, sbaugh, emacs-devel
> From: Spencer Baugh <sbaugh@catern.com>
> Date: Tue, 28 Nov 2023 23:56:14 +0000 (UTC)
> Cc: juri@linkov.net, sbaugh@janestreet.com, emacs-devel@gnu.org
>
> Eli Zaretskii <eliz@gnu.org> writes:
> >> From: Spencer Baugh <sbaugh@catern.com>
> >> Date: Tue, 28 Nov 2023 14:38:55 +0000 (UTC)
> >> Cc: Spencer Baugh <sbaugh@janestreet.com>, emacs-devel@gnu.org
> >> :type '(choice (const :tag "No sorting" nil)
> >> (const :tag "Alphabetical sorting" alphabetical)
> >> + (const :tag "Historical sorting" historical)
> > ^^^^^^^^^^^^^^^^^^
> > "Chronological sorting"
>
> I think "historical sorting" is more intuitive here. "Chronological"
> seems more ambiguous - it could mean something different for files, for
> example.
I don't understand why, please explain. Did history stop changing in
chronological order at some point and I missed that? That is, doesn't
the first minibuffer input always precede the second one in
chronological order?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 17:36 ` Eli Zaretskii
@ 2023-11-29 7:11 ` Juri Linkov
2023-11-29 13:09 ` Eli Zaretskii
0 siblings, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-11-29 7:11 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: sbaugh, sbaugh, emacs-devel
>> >> :type '(choice (const :tag "No sorting" nil)
>> >> (const :tag "Alphabetical sorting" alphabetical)
>> >> + (const :tag "Historical sorting" historical)
>> > ^^^^^^^^^^^^^^^^^^
>> > "Chronological sorting"
>>
>> Chronological sorting is how a list of buffers sorted by recency.
>> Historical sorting is how items in history are sorted by input.
>
> Aren't they the same order? If not, why not?
"Chronological" is more wide and thus more ambiguous and confusing for users.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Turning completion table lambdas into symbols
2023-11-28 23:36 ` Turning completion table lambdas into symbols Spencer Baugh
2023-11-28 23:51 ` Dmitry Gutov
@ 2023-11-29 7:18 ` Juri Linkov
1 sibling, 0 replies; 107+ messages in thread
From: Juri Linkov @ 2023-11-29 7:18 UTC (permalink / raw)
To: Spencer Baugh; +Cc: Spencer Baugh, emacs-devel
>>>> display-buffer has a similar problem, but the difference is that
>>>> it's possible to identify a buffer by its name and use a regexp
>>>> to match buffer names. Whereas for completing-read it's not easy
>>>> to identify a completion table. A category matches a set of
>>>> completion tables, so maybe we need another identification
>>>> for individual tables?
>>>
>>> True, that would help. Maybe the function symbol for the completion
>>> table? Tables are usually lambdas today, but maybe we could make it
>>> easy to use a defun'd function instead, which would be very good for
>>> comprehensibility in general IMO.
>>
>> Turning lambdas into symbols looks good, this is like the existing
>> 'help--symbol-completion-table'.
>
> Like 'help--symbol-completion-table' in what way?
Just an example where minibuffer-completion-table is a symbol.
> One thing that requires a lambda is when the table is over some custom
> data. But that can sometimes be avoided by moving the logic into the
> table, like this for example:
>
> +(defun project--project-dir-completion-table (string pred action)
> + (cond
> + ((eq action 'metadata)
> + '(metadata . ((category . project-dir))))
> + (t
> + (complete-with-action action (cons "... (choose a dir)" project--list) string pred))))
> ...
> - (completing-read "Select project: " choices nil t nil 'project--dir-history))))
> + (completing-read "Select project: " #'project--project-dir-completion-table
> + nil t nil 'project--dir-history))))
> If there was a canonical way for a completion table to maintain some
> state which *doesn't* require the completion table to be a lambda, I
> think most completion tables could become defuns instead of lambdas.
> (And then they could be customized based on the function symbol)
Or they could be customized based on a new symbol for table identification
without turning lambdas into defuns:
(completing-read "Select project: "
(lambda (string pred action)
(cond
((eq action 'metadata)
'(metadata
. ((category . project-dir)
(table . project-dir-completion-table))))
(t
(complete-with-action action choices string pred))))
nil t nil 'project--dir-history)
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 7:11 ` Juri Linkov
@ 2023-11-29 13:09 ` Eli Zaretskii
2023-11-29 14:14 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-29 13:09 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, sbaugh, emacs-devel
> From: Juri Linkov <juri@linkov.net>
> Cc: sbaugh@catern.com, sbaugh@janestreet.com, emacs-devel@gnu.org
> Date: Wed, 29 Nov 2023 09:11:24 +0200
>
> >> >> :type '(choice (const :tag "No sorting" nil)
> >> >> (const :tag "Alphabetical sorting" alphabetical)
> >> >> + (const :tag "Historical sorting" historical)
> >> > ^^^^^^^^^^^^^^^^^^
> >> > "Chronological sorting"
> >>
> >> Chronological sorting is how a list of buffers sorted by recency.
> >> Historical sorting is how items in history are sorted by input.
> >
> > Aren't they the same order? If not, why not?
>
> "Chronological" is more wide and thus more ambiguous and confusing for users.
Sorry, I still don't think I follow. Could you perhaps elaborate
about how "chronological" is more wide?
My problem with "history order" or "historical order" is that it could
be confusing, since we are talking about input history. So we in fact
saying something like "sort history in history order". I'd like to
avoid using the same word twice in two different meanings, as that is
bound to confuse someone.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 13:09 ` Eli Zaretskii
@ 2023-11-29 14:14 ` Spencer Baugh
2023-11-29 14:54 ` Eli Zaretskii
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-29 14:14 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Juri Linkov, Spencer Baugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1607 bytes --]
On Wed, Nov 29, 2023, 8:10 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Juri Linkov <juri@linkov.net>
> > Cc: sbaugh@catern.com, sbaugh@janestreet.com, emacs-devel@gnu.org
> > Date: Wed, 29 Nov 2023 09:11:24 +0200
> >
> > >> >> :type '(choice (const :tag "No sorting" nil)
> > >> >> (const :tag "Alphabetical sorting" alphabetical)
> > >> >> + (const :tag "Historical sorting" historical)
> > >> > ^^^^^^^^^^^^^^^^^^
> > >> > "Chronological sorting"
> > >>
> > >> Chronological sorting is how a list of buffers sorted by recency.
> > >> Historical sorting is how items in history are sorted by input.
> > >
> > > Aren't they the same order? If not, why not?
> >
> > "Chronological" is more wide and thus more ambiguous and confusing for
> users.
>
> Sorry, I still don't think I follow. Could you perhaps elaborate
> about how "chronological" is more wide?
>
> My problem with "history order" or "historical order" is that it could
> be confusing, since we are talking about input history. So we in fact
> saying something like "sort history in history order".
Oh, no, this is about sorting completion candidates, not history. The
history is still in chronological order always, it's not affected by this
setting. The setting just determines whether completion candidates are
sorted alphabetically or to match the history.
So it's "sort completions in history order".
I'd like to
> avoid using the same word twice in two different meanings, as that is
> bound to confuse someone.
>
[-- Attachment #2: Type: text/html, Size: 2974 bytes --]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 14:14 ` Spencer Baugh
@ 2023-11-29 14:54 ` Eli Zaretskii
2023-11-29 15:21 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-29 14:54 UTC (permalink / raw)
To: Spencer Baugh; +Cc: juri, sbaugh, emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 29 Nov 2023 09:14:05 -0500
> Cc: Juri Linkov <juri@linkov.net>, Spencer Baugh <sbaugh@catern.com>, emacs-devel@gnu.org
>
> My problem with "history order" or "historical order" is that it could
> be confusing, since we are talking about input history. So we in fact
> saying something like "sort history in history order".
>
> Oh, no, this is about sorting completion candidates, not history. The history is still in chronological
> order always, it's not affected by this setting. The setting just determines whether completion
> candidates are sorted alphabetically or to match the history.
>
> So it's "sort completions in history order".
"History order" still sounds too heavy-handed. How about "in the
order of their typing" or somesuch?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 14:54 ` Eli Zaretskii
@ 2023-11-29 15:21 ` Spencer Baugh
2023-11-29 15:52 ` Eli Zaretskii
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-29 15:21 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: juri, sbaugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1123 bytes --]
On Wed, Nov 29, 2023 at 9:54 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Spencer Baugh <sbaugh@janestreet.com>
> > Date: Wed, 29 Nov 2023 09:14:05 -0500
> > Cc: Juri Linkov <juri@linkov.net>, Spencer Baugh <sbaugh@catern.com>,
> emacs-devel@gnu.org
> >
> > My problem with "history order" or "historical order" is that it could
> > be confusing, since we are talking about input history. So we in fact
> > saying something like "sort history in history order".
> >
> > Oh, no, this is about sorting completion candidates, not history. The
> history is still in chronological
> > order always, it's not affected by this setting. The setting just
> determines whether completion
> > candidates are sorted alphabetically or to match the history.
> >
> > So it's "sort completions in history order".
>
> "History order" still sounds too heavy-handed. How about "in the
> order of their typing" or somesuch?
>
Why heavy-handed? I feel confident that more users will understand
"History order" than "in the order of their typing".
How about "Sorted in the order of minibuffer history"?
[-- Attachment #2: Type: text/html, Size: 1822 bytes --]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 15:21 ` Spencer Baugh
@ 2023-11-29 15:52 ` Eli Zaretskii
2023-11-29 19:17 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-29 15:52 UTC (permalink / raw)
To: Spencer Baugh; +Cc: juri, sbaugh, emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 29 Nov 2023 10:21:47 -0500
> Cc: juri@linkov.net, sbaugh@catern.com, emacs-devel@gnu.org
>
> > So it's "sort completions in history order".
>
> "History order" still sounds too heavy-handed. How about "in the
> order of their typing" or somesuch?
>
> Why heavy-handed?
Because "history" has meaning outside of Emacs.
> I feel confident that more users will understand "History order" than "in the
> order of their typing".
>
> How about "Sorted in the order of minibuffer history"?
That's better, but if you are okay with that, how about "Sorted in the
chronological order of minibuffer input"?
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 15:52 ` Eli Zaretskii
@ 2023-11-29 19:17 ` Spencer Baugh
2023-11-30 6:12 ` Eli Zaretskii
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-29 19:17 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: juri, sbaugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 720 bytes --]
On Wed, Nov 29, 2023 at 10:52 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Spencer Baugh <sbaugh@janestreet.com>
> > Date: Wed, 29 Nov 2023 10:21:47 -0500
> > Cc: juri@linkov.net, sbaugh@catern.com, emacs-devel@gnu.org
> > I feel confident that more users will understand "History order" than
> "in the
> > order of their typing".
> >
> > How about "Sorted in the order of minibuffer history"?
>
> That's better, but if you are okay with that, how about "Sorted in the
> chronological order of minibuffer input"?
>
That does not mention history, so I think it's worse - how are user
supposed to know it's about history? But I'm okay with "Sorted in
chronological order of minibuffer history".
[-- Attachment #2: Type: text/html, Size: 1321 bytes --]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Turning completion table lambdas into symbols
2023-11-28 23:51 ` Dmitry Gutov
@ 2023-11-29 19:26 ` Spencer Baugh
2023-12-01 0:36 ` Dmitry Gutov
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-29 19:26 UTC (permalink / raw)
To: emacs-devel
Dmitry Gutov <dmitry@gutov.dev> writes:
> On 29/11/2023 01:36, Spencer Baugh wrote:
>> If there was a canonical way for a completion table to maintain some
>> state which*doesn't* require the completion table to be a lambda, I
>> think most completion tables could become defuns instead of lambdas.
>> (And then they could be customized based on the function symbol)
>
> Maybe take a look at how company-capf caches the results of calling a
> CAPF function?
>
> Depending on the data, the cache key is either
> buffer/point/chars-modified-tick tuple, or the "completion session"
> (but in a company-mode specific way).
Hm, I think I more want to support state/caching inside the completion
table itself. Not just caching the output of the completions. That
allows a lot more flexibility.
For example, project-prompt-project-name could be changed to use a new
completion table defun named project--project-name-completion-table.
project--project-name-completion-table would internally maintain a map
between project directories and project names, which it adds to whenever
completion is requested (instead of creating that map up front in
project-prompt-project-name, as we currently do). If there was no
support for state between completion table invocations,
project--project-name-completion-table would have to call
project--find-in-directory and project-name for each project on each
completion table invocation, which would be slow.
> For CAPF and Company, we also discussed the idea of a "session object"
> some time ago, but that's not in the current API so far.
Right, I think I'd much rather some kind of "session object" at the
level of completing-read/the programmed completion API.
Do you have a link to the previous discussion?
I haven't thought too much about it, but maybe some new dynamic variable
which is bound to nil at the top level of completing-read-default, so
the completion table can change it over time and preserve state through
the course of the completion. Works fine with nested completing-reads.
Alternatively, if today a completion table is always invoked with the
same current buffer (probably the case?), we could formalize that and
just let a completion table store state in buffer-local variables.
Maybe with some new 'initialize operation in completion tables which is
called when a new completing-read starts, or maybe the completion table
can just detect that somehow and initialize the variables itself. That
is nicer than having a single variable which all completion tables
share. However, completion table writers would need to be careful not
to break when doing nested completing-reads on the same table.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-29 19:17 ` Spencer Baugh
@ 2023-11-30 6:12 ` Eli Zaretskii
2023-11-30 12:33 ` Spencer Baugh
0 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-30 6:12 UTC (permalink / raw)
To: Spencer Baugh; +Cc: juri, sbaugh, emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 29 Nov 2023 14:17:57 -0500
> Cc: juri@linkov.net, sbaugh@catern.com, emacs-devel@gnu.org
>
> On Wed, Nov 29, 2023 at 10:52 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Spencer Baugh <sbaugh@janestreet.com>
> > Date: Wed, 29 Nov 2023 10:21:47 -0500
> > Cc: juri@linkov.net, sbaugh@catern.com, emacs-devel@gnu.org
> > I feel confident that more users will understand "History order" than "in the
> > order of their typing".
> >
> > How about "Sorted in the order of minibuffer history"?
>
> That's better, but if you are okay with that, how about "Sorted in the
> chronological order of minibuffer input"?
>
> That does not mention history, so I think it's worse - how are user supposed to know it's about
> history?
?? Didn't you yourself say several messages ago it was NOT about
history? I quote:
> > Oh, no, this is about sorting completion candidates, not history.
So now you say this IS about history?
> But I'm okay with "Sorted in chronological order of minibuffer history".
This is tautology: history is always in chronological order. We are
in effect wasting one word by repeating another.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-30 6:12 ` Eli Zaretskii
@ 2023-11-30 12:33 ` Spencer Baugh
2023-11-30 14:10 ` Eli Zaretskii
0 siblings, 1 reply; 107+ messages in thread
From: Spencer Baugh @ 2023-11-30 12:33 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Juri Linkov, Spencer Baugh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1691 bytes --]
On Thu, Nov 30, 2023, 1:12 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Spencer Baugh <sbaugh@janestreet.com>
> > Date: Wed, 29 Nov 2023 14:17:57 -0500
> > Cc: juri@linkov.net, sbaugh@catern.com, emacs-devel@gnu.org
> >
> > On Wed, Nov 29, 2023 at 10:52 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > > From: Spencer Baugh <sbaugh@janestreet.com>
> > > Date: Wed, 29 Nov 2023 10:21:47 -0500
> > > Cc: juri@linkov.net, sbaugh@catern.com, emacs-devel@gnu.org
> > > I feel confident that more users will understand "History order" than
> "in the
> > > order of their typing".
> > >
> > > How about "Sorted in the order of minibuffer history"?
> >
> > That's better, but if you are okay with that, how about "Sorted in the
> > chronological order of minibuffer input"?
> >
> > That does not mention history, so I think it's worse - how are user
> supposed to know it's about
> > history?
>
> ?? Didn't you yourself say several messages ago it was NOT about
> history? I quote:
>
> > > Oh, no, this is about sorting completion candidates, not history.
>
> So now you say this IS about history?
>
It's about sorting completion candidates so that their order matches the
order of the minibuffer history. So yes, it relates to history. But it's
not sorting the history - that's what I meant.
> But I'm okay with "Sorted in chronological order of minibuffer history".
>
> This is tautology: history is always in chronological order. We are
> in effect wasting one word by repeating another.
>
Okay, I agree. I think "history" is the more important of the two words
here, so how about "Sorted in order of minibuffer history"
>
[-- Attachment #2: Type: text/html, Size: 3346 bytes --]
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-30 12:33 ` Spencer Baugh
@ 2023-11-30 14:10 ` Eli Zaretskii
0 siblings, 0 replies; 107+ messages in thread
From: Eli Zaretskii @ 2023-11-30 14:10 UTC (permalink / raw)
To: Spencer Baugh; +Cc: juri, sbaugh, emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Thu, 30 Nov 2023 07:33:01 -0500
> Cc: Juri Linkov <juri@linkov.net>, Spencer Baugh <sbaugh@catern.com>, emacs-devel@gnu.org
>
> > But I'm okay with "Sorted in chronological order of minibuffer history".
>
> This is tautology: history is always in chronological order. We are
> in effect wasting one word by repeating another.
>
> Okay, I agree. I think "history" is the more important of the two words here, so how about "Sorted in
> order of minibuffer history"
I can live with that.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Turning completion table lambdas into symbols
2023-11-29 19:26 ` Spencer Baugh
@ 2023-12-01 0:36 ` Dmitry Gutov
0 siblings, 0 replies; 107+ messages in thread
From: Dmitry Gutov @ 2023-12-01 0:36 UTC (permalink / raw)
To: Spencer Baugh, emacs-devel
On 29/11/2023 21:26, Spencer Baugh wrote:
>> For CAPF and Company, we also discussed the idea of a "session object"
>> some time ago, but that's not in the current API so far.
> Right, I think I'd much rather some kind of "session object" at the
> level of completing-read/the programmed completion API.
>
> Do you have a link to the previous discussion?
It's been here and there, but the last mention was right in the middle
of this:
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47711#272
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47711#320
> I haven't thought too much about it, but maybe some new dynamic variable
> which is bound to nil at the top level of completing-read-default, so
> the completion table can change it over time and preserve state through
> the course of the completion. Works fine with nested completing-reads.
That could work. If you further progress on this (in a new thread?), I
suggest you tag all the interested parties (or include Stefan, at least).
> Alternatively, if today a completion table is always invoked with the
> same current buffer (probably the case?), we could formalize that and
> just let a completion table store state in buffer-local variables.
> Maybe with some new 'initialize operation in completion tables which is
> called when a new completing-read starts, or maybe the completion table
> can just detect that somehow and initialize the variables itself. That
> is nicer than having a single variable which all completion tables
> share. However, completion table writers would need to be careful not
> to break when doing nested completing-reads on the same table.
It's not rocket science, but the hard part is to pick a protocol that's
backward-compatible and weave it through all the related pieces of code.
Also see the note about backspacing around here:
https://github.com/minad/corfu/wiki#configuring-corfu-for-eglot (where
doing an edit before the current BEG doesn't abort completion but does
make the cache invalid), but that might be something to handle in the
caching logic anyway.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-11-28 23:56 ` Spencer Baugh
2023-11-29 3:33 ` Eli Zaretskii
@ 2023-12-03 17:25 ` Juri Linkov
2023-12-03 17:56 ` Eli Zaretskii
1 sibling, 1 reply; 107+ messages in thread
From: Juri Linkov @ 2023-12-03 17:25 UTC (permalink / raw)
To: Spencer Baugh; +Cc: Eli Zaretskii, sbaugh, emacs-devel
> Fixed patch for everything else:
No more comments in three days, so your latest patch is pushed now, thanks.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-12-03 17:25 ` Juri Linkov
@ 2023-12-03 17:56 ` Eli Zaretskii
2023-12-06 17:17 ` Juri Linkov
0 siblings, 1 reply; 107+ messages in thread
From: Eli Zaretskii @ 2023-12-03 17:56 UTC (permalink / raw)
To: Juri Linkov; +Cc: sbaugh, sbaugh, emacs-devel
> From: Juri Linkov <juri@linkov.net>
> Cc: Eli Zaretskii <eliz@gnu.org>, sbaugh@janestreet.com, emacs-devel@gnu.org
> Date: Sun, 03 Dec 2023 19:25:16 +0200
>
> > Fixed patch for everything else:
>
> No more comments in three days, so your latest patch is pushed now, thanks.
The NEWS entry says:
*** 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.
But if "more recent candidates appear first", this is not the
chronological order, this is the reverse chronological order. So
which part of the above is correct, the "chronological order" part or
the "more recent candidates first" part?
Btw, the doc string of minibuffer-sort-by-history seems to indicate
that both the above NEWS entry and the doc string of the user options
omit crucial details:
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.
This "alphabetical order first" part is not mentioned anywhere else.
It should at least be mentioned in the doc string of the user option
and at least hinted upon in NEWS.
^ permalink raw reply [flat|nested] 107+ messages in thread
* Re: Updating *Completions* as you type
2023-12-03 17:56 ` Eli Zaretskii
@ 2023-12-06 17:17 ` Juri Linkov
0 siblings, 0 replies; 107+ messages in thread
From: Juri Linkov @ 2023-12-06 17:17 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: sbaugh, sbaugh, emacs-devel
> The NEWS entry says:
>
> *** 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.
>
> But if "more recent candidates appear first", this is not the
> chronological order, this is the reverse chronological order. So
> which part of the above is correct, the "chronological order" part or
> the "more recent candidates first" part?
In fact the word "chronological" bears no significance in this context.
This feature is about the *history* variables, not some "chronological"
variables. So this should be sufficient:
*** New value 'historical' for user option 'completions-sort'
When 'completions-sort' is set to 'historical', completion candidates
will be sorted by their order in the minibuffer history,
with more recent candidates appearing first.
> Btw, the doc string of minibuffer-sort-by-history seems to indicate
> that both the above NEWS entry and the doc string of the user options
> omit crucial details:
>
> 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.
>
> This "alphabetical order first" part is not mentioned anywhere else.
> It should at least be mentioned in the doc string of the user option
> and at least hinted upon in NEWS.
Agreed.
^ permalink raw reply [flat|nested] 107+ messages in thread
end of thread, other threads:[~2023-12-06 17:17 UTC | newest]
Thread overview: 107+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-12 23:53 Updating *Completions* as you type sbaugh
2023-10-13 6:31 ` Eli Zaretskii
2023-10-13 18:01 ` Spencer Baugh
2023-10-14 7:09 ` Eli Zaretskii
2023-10-14 19:26 ` Björn Bidar
[not found] ` <874jit2ef7.fsf@>
2023-10-14 19:38 ` Eli Zaretskii
2023-10-14 16:51 ` Juri Linkov
2023-10-14 17:56 ` sbaugh
2023-10-14 19:51 ` Dmitry Gutov
2023-10-13 6:34 ` Juri Linkov
2023-10-13 19:04 ` Spencer Baugh
2023-10-14 16:58 ` Juri Linkov
2023-10-14 20:05 ` sbaugh
2023-10-15 6:06 ` Eli Zaretskii
2023-10-15 15:55 ` sbaugh
2023-10-16 11:38 ` Eli Zaretskii
2023-10-16 14:50 ` Michael Albinus
2023-10-16 15:58 ` [External] : " Drew Adams
2023-10-16 12:16 ` sbaugh
2023-10-17 18:23 ` Juri Linkov
2023-10-18 23:27 ` Spencer Baugh
2023-10-15 7:32 ` Juri Linkov
2023-10-16 19:28 ` Rudolf Adamkovič
2023-10-17 18:38 ` Juri Linkov
2023-10-15 20:31 ` Eshel Yaron
2023-10-16 3:18 ` [External] : " Drew Adams
2023-10-16 16:54 ` Juri Linkov
2023-10-17 13:48 ` sbaugh
2023-10-17 18:35 ` Juri Linkov
2023-10-17 22:57 ` Spencer Baugh
2023-10-18 3:04 ` [External] : " Drew Adams
2023-10-18 6:56 ` Juri Linkov
2023-10-18 12:25 ` Spencer Baugh
2023-10-18 17:32 ` Juri Linkov
2023-10-18 23:33 ` Spencer Baugh
2023-10-19 2:29 ` Spencer Baugh
2023-10-19 6:55 ` Juri Linkov
2023-11-19 19:22 ` sbaugh
2023-11-20 7:51 ` Juri Linkov
2023-11-20 15:24 ` Spencer Baugh
2023-11-20 17:47 ` Juri Linkov
2023-11-20 18:50 ` Spencer Baugh
2023-11-21 7:58 ` Juri Linkov
2023-11-21 12:40 ` sbaugh
2023-11-21 17:09 ` Juri Linkov
2023-11-21 20:45 ` Spencer Baugh
2023-11-22 7:51 ` Juri Linkov
2023-11-22 16:11 ` Spencer Baugh
2023-11-23 7:58 ` Juri Linkov
2023-11-23 12:36 ` sbaugh
2023-11-24 7:58 ` Juri Linkov
2023-11-25 16:44 ` Spencer Baugh
2023-11-25 18:31 ` Juri Linkov
2023-11-26 13:33 ` sbaugh
2023-11-27 7:28 ` Juri Linkov
2023-11-28 14:38 ` Spencer Baugh
2023-11-28 15:03 ` Eli Zaretskii
2023-11-28 17:13 ` Juri Linkov
2023-11-28 17:36 ` Eli Zaretskii
2023-11-29 7:11 ` Juri Linkov
2023-11-29 13:09 ` Eli Zaretskii
2023-11-29 14:14 ` Spencer Baugh
2023-11-29 14:54 ` Eli Zaretskii
2023-11-29 15:21 ` Spencer Baugh
2023-11-29 15:52 ` Eli Zaretskii
2023-11-29 19:17 ` Spencer Baugh
2023-11-30 6:12 ` Eli Zaretskii
2023-11-30 12:33 ` Spencer Baugh
2023-11-30 14:10 ` Eli Zaretskii
2023-11-28 23:56 ` Spencer Baugh
2023-11-29 3:33 ` Eli Zaretskii
2023-12-03 17:25 ` Juri Linkov
2023-12-03 17:56 ` Eli Zaretskii
2023-12-06 17:17 ` Juri Linkov
2023-11-28 17:16 ` Juri Linkov
2023-11-28 23:36 ` Turning completion table lambdas into symbols Spencer Baugh
2023-11-28 23:51 ` Dmitry Gutov
2023-11-29 19:26 ` Spencer Baugh
2023-12-01 0:36 ` Dmitry Gutov
2023-11-29 7:18 ` Juri Linkov
2023-11-21 12:54 ` Updating *Completions* as you type John Yates
2023-11-21 17:03 ` Juri Linkov
2023-11-21 22:27 ` John Yates
2023-10-20 6:49 ` Juri Linkov
2023-10-17 15:01 ` sbaugh
2023-10-17 18:20 ` Juri Linkov
2023-10-17 23:37 ` Spencer Baugh
2023-10-17 23:44 ` Spencer Baugh
2023-10-18 6:51 ` Juri Linkov
2023-10-18 12:47 ` Spencer Baugh
2023-10-18 17:28 ` Juri Linkov
2023-10-18 23:32 ` Spencer Baugh
2023-10-16 3:19 ` [External] : " Drew Adams
2023-10-20 9:35 ` zcomplete Philip Kaludercic
2023-10-22 17:28 ` zcomplete Juri Linkov
2023-10-23 5:00 ` zcomplete Protesilaos Stavrou
2023-10-23 6:45 ` zcomplete Juri Linkov
2023-10-13 18:11 ` Updating *Completions* as you type Daniel Semyonov
2023-10-13 18:48 ` Spencer Baugh
2023-10-16 3:16 ` [External] : " Drew Adams
2023-10-16 9:25 ` Philip Kaludercic
2023-10-16 16:03 ` Drew Adams
2023-10-20 7:45 ` Philip Kaludercic
2023-10-20 16:10 ` Drew Adams
2023-10-16 22:55 ` Emanuel Berg
2023-10-17 6:09 ` Emanuel Berg
2023-10-17 0:44 ` Michael Heerdegen
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).