New variable 'completion-frontend-properties' (bug#80990)

Allow completion "frontends" to provide extra information
that the backends they call can use to adjust or optimize
their behavior.
See some relevant discussion at
https://yhetil.org/emacs/jwv7bpl28y6.fsf-monnier+emacs@gnu.org/

* lisp/minibuffer.el (completion-frontend-properties):
New variable.
(completion-lazy-hilit-p): New function.
(completion-hilit-commonality, completion-lazy-hilit)
(completion-pcm--hilit-commonality)
(completion-flex-all-completions): Use it instead of
checking the 'completion-lazy-hilit' variable directly.
* lisp/completion-preview.el (completion-preview--capf-wrapper):
Bind 'completion-frontend-properties'.
(completion-preview--try-table): Add comment.
* etc/NEWS: Announce 'completion-frontend-properties'.
This commit is contained in:
Eshel Yaron 2026-05-08 12:45:00 +02:00
parent 876a1db6ee
commit 66729f3e50
No known key found for this signature in database
GPG key ID: EF3EE9CA35D78618
3 changed files with 45 additions and 8 deletions

View file

@ -45,6 +45,13 @@ applies, and please also update docstrings as needed.
* Lisp Changes in Emacs 32.1 * Lisp Changes in Emacs 32.1
---
** New variable 'completion-frontend-properties'.
This variable generalizes the 'completion-lazy-hilit' variable added in
Emacs 30. It allows Lisp programs that present completion candidates
("completion frontends") to provide additional information which can be
used to adjust or optimize completion candidates computation.
* Changes in Emacs 32.1 on Non-Free Operating Systems * Changes in Emacs 32.1 on Non-Free Operating Systems

View file

@ -499,7 +499,12 @@ candidates or if there are multiple matching completions and
(sort-fn (or (completion-metadata-get md 'cycle-sort-function) (sort-fn (or (completion-metadata-get md 'cycle-sort-function)
(completion-metadata-get md 'display-sort-function) (completion-metadata-get md 'display-sort-function)
completion-preview-sort-function)) completion-preview-sort-function))
(all (let ((completion-lazy-hilit t) (all (let (;; This is somewhat redundant since we also specify
;; non-nil `lazy-highlight' in
;; `completion-frontend-properties', but we keep it
;; for compatibility with backends that do not know
;; about `completion-frontend-properties' yet.
(completion-lazy-hilit t)
;; FIXME: This does not override styles prescribed ;; FIXME: This does not override styles prescribed
;; by the completion category via ;; by the completion category via
;; e.g. `completion-category-defaults'. ;; e.g. `completion-category-defaults'.
@ -525,7 +530,9 @@ candidates or if there are multiple matching completions and
(defun completion-preview--capf-wrapper (capf) (defun completion-preview--capf-wrapper (capf)
"Translate return value of CAPF to properties for completion preview overlay." "Translate return value of CAPF to properties for completion preview overlay."
(let ((res (ignore-errors (funcall capf)))) (let* ((completion-frontend-properties '((no-annotations . t)
(lazy-highlight . t)))
(res (ignore-errors (funcall capf))))
(and (consp res) (and (consp res)
(not (functionp res)) (not (functionp res))
(seq-let (beg end table &rest plist) res (seq-let (beg end table &rest plist) res

View file

@ -2586,7 +2586,7 @@ and with BASE-SIZE appended as the last element."
com-str-len (1+ com-str-len) com-str-len (1+ com-str-len)
'face 'completions-first-difference str)) 'face 'completions-first-difference str))
str))) str)))
(if completion-lazy-hilit (if (completion-lazy-hilit-p)
(setq completion-lazy-hilit-fn hilit-fn) (setq completion-lazy-hilit-fn hilit-fn)
(setq completions (setq completions
(mapcar (mapcar
@ -2604,6 +2604,11 @@ and with BASE-SIZE appended as the last element."
completions))) completions)))
(nconc completions base-size)))) (nconc completions base-size))))
(defun completion-lazy-hilit-p ()
"Return non-nil if the completion frontend supports lazy highlighting."
(or completion-lazy-hilit
(alist-get 'lazy-highlight completion-frontend-properties)))
(defun display-completion-list (completions &optional common-substring group-fun) (defun display-completion-list (completions &optional common-substring group-fun)
"Display the list of completions, COMPLETIONS, using `standard-output'. "Display the list of completions, COMPLETIONS, using `standard-output'.
Each element may be just a symbol or string Each element may be just a symbol or string
@ -3198,6 +3203,23 @@ Also respects the obsolete wrapper hook `completion-in-region-functions'.
(delq (assq 'completion-in-region-mode minor-mode-map-alist) (delq (assq 'completion-in-region-mode minor-mode-map-alist)
minor-mode-map-alist)) minor-mode-map-alist))
(defvar completion-frontend-properties nil
"Alist of properties describing the current completion frontend.
Frontends may let-bind this variable while calling a completion backend
to provide information which the backend can use to optimize or adjust
its behavior. More specifically, frontends should bind this variable
when calling `completion-try-completion' or `completion-all-completions'.
Currently known frontend properties are:
- \\+`no-annotations': if non-nil, the frontend ignores any
`annotation-function'/`affixation-function'.
- \\+`lazy-highlight': If non-nil, the front-end does not require
`completion-all-completions' completions to be highlighted and knows
to call the function `completion-lazy-hilit' as needed instead.")
(defvar completion-at-point-functions '(tags-completion-at-point-function) (defvar completion-at-point-functions '(tags-completion-at-point-function)
"Special hook to find the completion table for the entity at point. "Special hook to find the completion table for the entity at point.
Each function on this hook is called in turn without any argument and Each function on this hook is called in turn without any argument and
@ -4501,9 +4523,10 @@ strings with the `face' property.")
(defun completion-lazy-hilit (str) (defun completion-lazy-hilit (str)
"Return a copy of completion candidate STR that is `face'-propertized. "Return a copy of completion candidate STR that is `face'-propertized.
See documentation of the variable `completion-lazy-hilit' for more Apply `completion-lazy-hilit-fn' if it is set and the frontend supports
details." lazy highlighting (see `completion-lazy-hilit-p'), otherwise return STR
(if (and completion-lazy-hilit completion-lazy-hilit-fn) as is."
(if (and (completion-lazy-hilit-p) completion-lazy-hilit-fn)
(funcall completion-lazy-hilit-fn (copy-sequence str)) (funcall completion-lazy-hilit-fn (copy-sequence str))
str)) str))
@ -4556,7 +4579,7 @@ see) for later lazy highlighting."
(re (completion-pcm--segments->regex segments 'group)) (re (completion-pcm--segments->regex segments 'group))
(point-idx (completion-pcm--segments-point-idx segments))) (point-idx (completion-pcm--segments-point-idx segments)))
(setq completion-pcm--regexp re) (setq completion-pcm--regexp re)
(cond (completion-lazy-hilit (cond ((completion-lazy-hilit-p)
(setq completion-lazy-hilit-fn (setq completion-lazy-hilit-fn
(lambda (str) (completion--hilit-from-re str re point-idx))) (lambda (str) (completion--hilit-from-re str re point-idx)))
completions) completions)
@ -5036,7 +5059,7 @@ usual. Returns (ALL PAT PREFIX SUFFIX)."
(1+ special-match) (+ 2 special-match) (1+ special-match) (+ 2 special-match)
'completions-first-difference nil str)))) 'completions-first-difference nil str))))
str)) str))
(unless completion-lazy-hilit (unless (completion-lazy-hilit-p)
(setq all (mapcar completion-lazy-hilit-fn all))) (setq all (mapcar completion-lazy-hilit-fn all)))
;; Store pattern for adjust-metadata to use ;; Store pattern for adjust-metadata to use
(setq completion-flex--pattern-str pattern-str) (setq completion-flex--pattern-str pattern-str)