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. - `cycle-sort-function': function to sort entries when cycling.
Works like `display-sort-function'. Works like `display-sort-function'.
- `eager-display': non-nil to request eager display of the - `eager-display': non-nil to request eager display of the
completion candidates. Can also be a function which is invoked completion candidates.
after minibuffer setup.
The metadata of a completion table should be constant between two boundaries." The metadata of a completion table should be constant between two boundaries."
(let ((metadata (if (functionp table) (let ((metadata (if (functionp table)
(funcall table string pred 'metadata)))) (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. - `group-function': function for grouping the completion candidates.
- `annotation-function': function to add annotations in *Completions*. - `annotation-function': function to add annotations in *Completions*.
- `affixation-function': function to prepend/append a prefix/suffix. - `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 Categories are symbols such as `buffer' and `file', used when
completing buffer and file names, respectively. 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. - `group-function': function for grouping the completion candidates.
- `annotation-function': function to add annotations in *Completions*. - `annotation-function': function to add annotations in *Completions*.
- `affixation-function': function to prepend/append a prefix/suffix. - `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'. See more description of metadata in `completion-metadata'.
Categories are symbols such as `buffer' and `file', used when 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)) ((completion--eager-update-p (minibuffer-prompt-end))
(minibuffer-completion-help)))))) (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 () (defun completions--post-command-update ()
"Update displayed *Completions* buffer after command, once." "Update displayed *Completions* buffer after command, once."
(remove-hook 'post-command-hook #'completions--post-command-update) (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 ;; `completion-eager-display' is t or if eager display
;; has been requested by the completion table. ;; has been requested by the completion table.
(when completion-eager-display (when completion-eager-display
(let* ((md (completion-metadata (when (or (eq completion-eager-display t)
(completion-metadata-get
(completion-metadata
(buffer-substring-no-properties (buffer-substring-no-properties
(minibuffer-prompt-end) (point)) (minibuffer-prompt-end) (point))
collection predicate)) collection predicate)
(fun (completion-metadata-get md 'eager-display))) 'eager-display))
(when (or fun (eq completion-eager-display t)) (completions--start-eager-display))))
(funcall (if (functionp fun)
fun #'minibuffer-completion-help))))))
(read-from-minibuffer prompt initial-input keymap (read-from-minibuffer prompt initial-input keymap
nil hist def inherit-input-method)))) nil hist def inherit-input-method))))
(when (and (equal result "") def) (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)) (car (nth index-of-default tmm-km-list))
(minibuffer-with-setup-hook (minibuffer-with-setup-hook
(lambda () (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 ;; tmm-km-list is reversed, because history
;; needs it in LIFO order. But default list ;; needs it in LIFO order. But default list
;; needs it in non-reverse order, so that the ;; 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): ") " (up/down to change, PgUp to menu): ")
(completion-table-with-metadata (completion-table-with-metadata
tmm-km-list '((category . tmm) tmm-km-list '((category . tmm)
(eager-display . tmm-add-prompt) (eager-display . t)
(display-sort-function . identity) (display-sort-function . identity)
(cycle-sort-function . identity))) (cycle-sort-function . identity)))
nil t nil nil t nil
@ -416,20 +418,16 @@ Stores a list of all the shortcuts in the free variable `tmm-short-cuts'."
(goto-char next))) (goto-char next)))
(set-buffer-modified-p nil))) (set-buffer-modified-p nil)))
(defun tmm-add-prompt () (defun tmm--completion-setup-hook ()
(unless tmm-c-prompt (unless tmm-c-prompt
(error "No active menu entries")) (error "No active menu entries"))
(or tmm-completion-prompt (or tmm-completion-prompt
(add-hook 'completion-setup-hook (tmm-completion-delete-prompt))
#'tmm-completion-delete-prompt 'append)) (with-current-buffer standard-output
(unwind-protect
(minibuffer-completion-help)
(remove-hook 'completion-setup-hook #'tmm-completion-delete-prompt))
(with-current-buffer "*Completions*"
(tmm-remove-inactive-mouse-face) (tmm-remove-inactive-mouse-face)
(when tmm-completion-prompt (when tmm-completion-prompt
(let ((inhibit-read-only t) (let ((inhibit-read-only t)
(window (get-buffer-window "*Completions*"))) (window (get-buffer-window)))
(goto-char (point-min)) (goto-char (point-min))
(insert (insert
(if tmm-shortcut-inside-entry (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 () (defun tmm-goto-completions ()
"Jump to the completions buffer." "Jump to the completions buffer."
(interactive) (interactive)
(tmm-add-prompt) (minibuffer-completion-help)
(setq tmm-c-prompt (buffer-substring (minibuffer-prompt-end) (point-max))) (setq tmm-c-prompt (buffer-substring (minibuffer-prompt-end) (point-max)))
;; Clear minibuffer old contents before using *Completions* buffer for ;; Clear minibuffer old contents before using *Completions* buffer for
;; selection. ;; selection.