emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Updating *Completions* as you type


From: sbaugh
Subject: Re: Updating *Completions* as you type
Date: Sat, 14 Oct 2023 16:05:11 -0400
User-agent: Gnus/5.13 (Gnus v5.13)

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?

>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

>> 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.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]