emacslispelispcompletion

How to return the value instead of key by completing-read


(completing-read
 "Complete a foo: "
 '(("foobar1" "~/foobar1/") ("barfoo" "/usr/barfoo/") ("foobaz" "/hello/")))

As shown above, I would like to prompt for "foobar1","barfoo", and "foobaz" but getting the paired directory in return.

Moverover, if I have a hash-table like this

(cl-defstruct person ID name)
(setq person-object (make-person :ID 123 :name "foo"))
(setq person-table (make-hash-table))
(pushash (person-ID person-object) person-object person-table)

How can I prompt for the person name but getting a person ID in return?


Solution

  • @legoscia provided a good answer: completing-read does not give you access to the value associated with a key that it uses for completion. E.g., for an alist COLLECTION argument, it does not give you access to the cdr of a chosen alist key.

    For an alist you can use assoc to get the first matching alist element, and for a hash table you can maphash or do a get.

    But these approaches preclude getting the particular value associated with a particular chosen key occurrence when there are duplicates of the key, that is, when multiple candidates have the same key, or name.

    You cannot get the 2nd matching element, or the 13th. In fact, vanilla Emacs completing-read eliminates duplication of completion candidates that have the same key (name). For vanilla Emacs, any information in the cdr of an alist entry is wasted. You can use an alist, for convenience, if you already have one, but if not then you might as well just use a list of names (strings or symbols), not conses.

    If you use Icicles then alist entries are not wasted. There is no problem retrieving cdr values. You can easily get to the complete information of a candidate you choose, after completing-read is done.

    Icicles does this by using propertized strings as candidates, and by enhancing completing-read so that it can return the complete string, properties and all, that a user chooses. You can recuperate the complete alist entry from the propertized string that is returned.

    When is it important to be able to have and use duplicate keys that can have different associated values? And how can a user tell them apart (e.g., in *Completions*), if they are duplicates?

    Examples:

    In Icicles, how does a user choose one among several completion candidates that have the same name?

    What do you have to do, to be able to take advantage of this Icicles feature in your own code?

    See Defining Tripping Commands for how to define your own commands that let users trip among (explore) candidates might have associated positional or other navigational information. (See Tripping for predefined Icicles tripping commands.)

    A brief overview of what to do in your command:

    1. Bind variable icicle-whole-candidate-as-text-prop-p to non-nil.

    2. Set variable icicle-candidates-alist to the alist that you pass to completing-read. This has the effect of encoding, as a text property on the candidate display string, the entire corresponding original alist entry.

    3. Use icicle-get-alist-candidate after calling completing-read, to recover that complete information about the candidate the user chooses, that is, the complete alist element, kncluding the cdr.

    (See also: Note to programmers using Icicles.)