Subject: Re: bug#74718: 29.4; Huge metadata with flex completion style

From: Daniel Mendler <[email-masked]>
Date: Tue, 10 Dec 2024 16:24:40 +0100

Thierry Volpiatto <[email-masked]> writes:
> From emacs -Q:
>
> 1) Open some buffers
> 2) eval this in scratch:
>
> (setq completion-styles '(flex))
> (let* ((collection (mapcar #'buffer-name (buffer-list)))
>        (metadata (completion-metadata "" collection nil))
>        (completion-function (lambda (str _pred _action)
>                               (let* ((comps (completion-all-completions str collection nil (length str) metadata))
> 				     (sort-fn (completion-metadata-get metadata 'display-sort-function))
> 				     (last (last comps)))
> 				(when (cdr last)
> 				  (setcdr last nil))
> 				(message "%S" metadata)
> 				(if (and sort-fn (> (length str) 0)) (funcall sort-fn comps) comps)))))
>   (completing-read "test: " completion-function))

Hello Thierry,

`completion-all-completions' should not be called inside completion
tables. Instead they should use `all-completions' to perform filtering
instead. `completion-all-completions' is the "frontend" API, which uses
completion styles, which then call the completion table backend.

The prototypical programmable completion table has the following form,
where `complete-with-action' provides the default implementation for the
ACTION argument:

(let ((candidates '("list" "of" "candidates")))
  (lambda (str pred action)
    (complete-with-action action candidates str pred)))

Depending on your use case, you may want to implement some ACTIONs
yourself, e.g., `metadata':

(let ((candidates '("list" "of" "candidates")))
  (lambda (str pred action)
    (if (eq action 'metadata)
        `(metadata (category . my-candidate-category))
      (complete-with-action action candidates str pred))))

Furthermore candidates can be computed dynamically, see the completion
tables `completion-table-dynamic' or `completion-table-with-cache'.

Daniel