1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-05 22:20:24 -08:00

Do eager display of *Completions* while idle

Don't block user input while rendering the *Completions* buffer
due to eager-display.  This allows eager-display to be used with
larger and slower completion tables without interfering with the
user.  Like in eager-update, we use while-no-input and
non-essential to ensure that eager-display happens without
blocking the user.

To support this, we remove the ability to set eager-display to a
function.  The only user was tmm.el, which nows sets
eager-display to t and adds a completion-setup-hook instead.
(This also fixes a bug in tmm where dismissing and redisplaying
the *Completions* buffer would not have the special help text)

* lisp/minibuffer.el (completion-eager-display--timer)
(completions--eager-display, completions--start-eager-display):
Add. (bug#79819)
(completing-read-default): Call
completions--start-eager-display, stop supporting functionp
eager-display.
* lisp/tmm.el (tmm-add-prompt): Delete.
(tmm--completion-setup-hook): Add.
(tmm-add-prompt): Add completion-setup-hook, set eager-display
to t.
(tmm-goto-completions): Call minibuffer-completion-help instead
of tmm-add-prompt.
This commit is contained in:
Spencer Baugh 2025-11-11 20:11:20 -05:00 committed by Juri Linkov
parent 4e08b2d434
commit ab8d3624c4
2 changed files with 36 additions and 21 deletions

View file

@ -141,8 +141,7 @@ This metadata is an alist. Currently understood keys are:
- `cycle-sort-function': function to sort entries when cycling.
Works like `display-sort-function'.
- `eager-display': non-nil to request eager display of the
completion candidates. Can also be a function which is invoked
after minibuffer setup.
completion candidates.
The metadata of a completion table should be constant between two boundaries."
(let ((metadata (if (functionp table)
(funcall table string pred 'metadata))))
@ -1278,7 +1277,7 @@ an association list that can specify properties such as:
- `group-function': function for grouping the completion candidates.
- `annotation-function': function to add annotations in *Completions*.
- `affixation-function': function to prepend/append a prefix/suffix.
- `eager-display': function to show *Completions* eagerly.
- `eager-display': non-nil to show *Completions* eagerly.
Categories are symbols such as `buffer' and `file', used when
completing buffer and file names, respectively.
@ -1300,7 +1299,7 @@ possible values are the same as in `completions-sort'.
- `group-function': function for grouping the completion candidates.
- `annotation-function': function to add annotations in *Completions*.
- `affixation-function': function to prepend/append a prefix/suffix.
- `eager-display': function to show *Completions* eagerly.
- `eager-display': non-nil to show *Completions* eagerly.
See more description of metadata in `completion-metadata'.
Categories are symbols such as `buffer' and `file', used when
@ -2754,6 +2753,24 @@ so that the update is less likely to interfere with user typing."
((completion--eager-update-p (minibuffer-prompt-end))
(minibuffer-completion-help))))))
(defvar completion-eager-display--timer nil)
(defun completions--eager-display ()
"Try to display *Completions* without blocking input."
;; If the user has left the minibuffer, give up on eager display of
;; *Completions*.
(when (minibufferp nil t)
(when (while-no-input
(let ((non-essential t))
(minibuffer-completion-help)))
;; If we got interrupted, try again the next time the user is idle.
(completions--start-eager-display))))
(defun completions--start-eager-display ()
"Display the *Completions* buffer when the user is next idle."
(setq completion-eager-display--timer
(run-with-idle-timer 0 nil #'completions--eager-display)))
(defun completions--post-command-update ()
"Update displayed *Completions* buffer after command, once."
(remove-hook 'post-command-hook #'completions--post-command-update)
@ -5143,14 +5160,14 @@ See `completing-read' for the meaning of the arguments."
;; `completion-eager-display' is t or if eager display
;; has been requested by the completion table.
(when completion-eager-display
(let* ((md (completion-metadata
(when (or (eq completion-eager-display t)
(completion-metadata-get
(completion-metadata
(buffer-substring-no-properties
(minibuffer-prompt-end) (point))
collection predicate))
(fun (completion-metadata-get md 'eager-display)))
(when (or fun (eq completion-eager-display t))
(funcall (if (functionp fun)
fun #'minibuffer-completion-help))))))
collection predicate)
'eager-display))
(completions--start-eager-display))))
(read-from-minibuffer prompt initial-input keymap
nil hist def inherit-input-method))))
(when (and (equal result "") def)

View file

@ -218,7 +218,9 @@ is used to go back through those sub-menus."
(car (nth index-of-default tmm-km-list))
(minibuffer-with-setup-hook
(lambda ()
(setq tmm-old-mb-map (tmm-define-keys t)))
(setq tmm-old-mb-map (tmm-define-keys t))
(add-hook 'completion-setup-hook
#'tmm--completion-setup-hook 'append 'local))
;; tmm-km-list is reversed, because history
;; needs it in LIFO order. But default list
;; needs it in non-reverse order, so that the
@ -231,7 +233,7 @@ is used to go back through those sub-menus."
" (up/down to change, PgUp to menu): ")
(completion-table-with-metadata
tmm-km-list '((category . tmm)
(eager-display . tmm-add-prompt)
(eager-display . t)
(display-sort-function . identity)
(cycle-sort-function . identity)))
nil t nil
@ -416,20 +418,16 @@ Stores a list of all the shortcuts in the free variable `tmm-short-cuts'."
(goto-char next)))
(set-buffer-modified-p nil)))
(defun tmm-add-prompt ()
(defun tmm--completion-setup-hook ()
(unless tmm-c-prompt
(error "No active menu entries"))
(or tmm-completion-prompt
(add-hook 'completion-setup-hook
#'tmm-completion-delete-prompt 'append))
(unwind-protect
(minibuffer-completion-help)
(remove-hook 'completion-setup-hook #'tmm-completion-delete-prompt))
(with-current-buffer "*Completions*"
(tmm-completion-delete-prompt))
(with-current-buffer standard-output
(tmm-remove-inactive-mouse-face)
(when tmm-completion-prompt
(let ((inhibit-read-only t)
(window (get-buffer-window "*Completions*")))
(window (get-buffer-window)))
(goto-char (point-min))
(insert
(if tmm-shortcut-inside-entry
@ -474,7 +472,7 @@ Stores a list of all the shortcuts in the free variable `tmm-short-cuts'."
(defun tmm-goto-completions ()
"Jump to the completions buffer."
(interactive)
(tmm-add-prompt)
(minibuffer-completion-help)
(setq tmm-c-prompt (buffer-substring (minibuffer-prompt-end) (point-max)))
;; Clear minibuffer old contents before using *Completions* buffer for
;; selection.