It looks like this can be done via a completing-read collection function,
https://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html
Some basic, dirty experimentation got me to something like this:
(setq lexical-binding t)
(defun dogs-filter (seq)
(lambda (str pred flag)
(pcase flag
('metadata
(list 'metadata
(cons 'annotation-function
(lambda (c)
(format "\n\t%s" (alist-get c seq nil nil #'string=))))))
('t
(if (string-blank-p str)
(all-completions str seq)
(all-completions
str
(lambda (s _ _)
(seq-map
#'car
(seq-filter
(lambda (x)
(unless (string-blank-p str)
(or
(s-contains-p str (car x) :ignore-case)
(s-contains-p str (cdr x) :ignore-case))))
seq)))))))))
(let* ((coll '(("Affenpinscher" . "Loyal and amusing")
("Akita" . "Ancient Japanese")
("Bulldog" . "Kind but courageous")
("Caucasian Shepherd" . "Serious guarding breed")
("Miniature Schnauzer" . "Long-lived and low-shedding"))))
(completing-read
"Select a breed: "
(dogs-filter coll)))
There's some weird case I can't seem to solve at the moment inside seq-filter, that's why I had to do that weird "if" check, otherwise it won't show the rows unless something typed.
But it works as I wanted. With the completion-fn, I no longer have to use completion-extra-properties
, they can be attached via metadata right in that function.
Doing that way you can also attach metadata that allows you to set the category (e.g., file, url, etc.), grouping, annotations, affixation, and more. Setting a proper category, for example for URLs (if you're dealing with those) would correctly dispatch Embark actions.
Unfortunately, the documentation is not very clear and is lacking examples, it's a bit tricky to get it right, but that's the gist of how it gets done.
Another great example of using a collection function I've found in this blogpost: https://kisaragi-hiu.com/emacs-completion-metadata.html
In this Reddit post where I asked the same exact question, a lot of opinions were like: "you shouldn't be doing that, annotations are not made for that", and frankly, I think they are missing the point. In this comment, I tried to explain why Programmed Completions are so powerful and that they can be used not only to match what's in annotations but for cases when you want to match on something that practically, can't be displayed at all.
I'd recommend learning this powerful tool and don't let the ascetic language of the official documentation keep you from building some awesome things in elisp.