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

(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?

There's no way to get completing-read to return the value instead of the key, so you have to do the lookup yourself:
(let ((completions '(("foobar1" "~/foobar1/") ("barfoo" "/usr/barfoo/") ("foobaz" "/hello/"))))
(cadr (assoc (completing-read "Complete a foo: " completions) completions)))
As for the hash table, since the name is not the key, you need to iterate through every object in the hash table to find it, using maphash. Since it would be wasteful to keep iterating after you've found what you're looking for, you could use catch and throw, like this:
(catch 'found-it
(maphash
(lambda (key value)
(when (equal (person-name value) desired-name)
(throw 'found-it key)))
person-table))
This will return the person ID, or nil if there's no person whose name equals desired-name.

#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:
Bookmarks that have the same name but are for different targets - for example, for different files with the same relative name in different directories.
Lines or other text in a buffer that match a pattern or that contain a marker. This includes matches in Icicles search, where you can define search contexts any way you like (not just lines). It also includes buffer zones (including restrictions, aka narrowings) and buffer positions (markers).
Candidates that have the same text but whose annotations are different. (User input is not matched against annotations shown in *Completions*.)
Imenu items that have the same name, e.g., multiple definitions of objects (e.g. functions) that have the same name.
Tagged items (e.g. functions) that have the same name.
Candidates that are other Lisp objects, such as frames, that can have the same name.
In Icicles, how does a user choose one among several completion candidates that have the same name?
Users can control the order (sorting) of the candidates, including changing order on the fly. *Completions* shows them to you in a specific order. You can cycle among candidates or choose any of them directly. You are not limited to matching, to choose. (With duplicate candidates, matching can be insufficient to get you to only one of them.)
*Completions* can also show you additional information about candidates, which distinguishes them even when they have the same name/text. Such info could be surrounding text (if the candidates are matching buffer text), or candidate metadata (e.g. file or bookmark attributes).
You can also see important additional information about the current candidate (e.g. during cycling) in the mode line.
You can get additional information (complete *Help*) about the current candidate on demand, by hitting a key.
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:
Bind variable icicle-whole-candidate-as-text-prop-p to non-nil.
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.
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.)

http://www.howardism.org/Technical/Emacs/alt-completing-read.html
You have been looking for alt-completing-read !
Simpler version
(let ((choices '(("First" . 'first-choice)
("Second" . 'second-choice)
("Third" . 'third-choice))))
(alist-get
(completing-read "Choose: " choices)
choices nil nil 'equal))
Complex version
(defun alt-completing-read (prompt collection &optional predicate require-match initial-input hist def inherit-input-method)
"Calls `completing-read' but returns the value from COLLECTION.
Simple wrapper around the `completing-read' function that assumes
the collection is either an alist, or a hash-table, and returns
the _value_ of the choice, not the selected choice. For instance,
give a variable of choices like:
(defvar favorite-hosts '((\"Glamdring\" . \"192.168.5.12\")
(\"Orcrist\" . \"192.168.5.10\")
(\"Sting\" . \"192.168.5.220\")
(\"Gungnir\" . \"192.168.5.25\")))
We can use this function to `interactive' without needing to call
`alist-get' afterwards:
(defun favorite-ssh (hostname)
\"Start a SSH session to a given HOSTNAME.\"
(interactive (list (alt-completing-read \"Host: \" favorite-hosts)))
(message \"Rockin' and rollin' to %s\" hostname))"
;; Yes, Emacs really should have an `alistp' predicate to make this code more readable:
(cl-flet ((assoc-list-p (obj) (and (listp obj) (consp (car obj)))))
(let* ((choice
(completing-read prompt collection predicate require-match initial-input hist def inherit-input-method))
(results (cond
((hash-table-p collection) (gethash choice collection))
((assoc-list-p collection) (alist-get choice collection def nil 'equal))
(t choice))))
(if (listp results) (first results) results))))

Related

Emacs customizable variable with dynamic set of possible values

I want to define a customizable variable in Emacs Lisp whose possible values are restricted to a certain list, but the list should be dynamically created by a function each time the user opens the customization buffer. Thus, something similar to
(defcustom my-variable
[...]
:type '(choice [...])
but choice seems to support only a static set of values. What I want is something like
(defcustom my-variable
[...]
:type '(choice my-function)
where my-function is a function that returns the list of possible values, and is evaluated each time the customization buffer is created.
Is that possible?
(defun my-function ()
"..."
'(42 "a" b (x y) "c"))
(defcustom foo 42
"..."
:group 'convenience
:type '(restricted-sexp
:match-alternatives ((lambda (x)
(car (member x (my-function)))))))
Function my-function could provide a different list of possibilities each time (or whenever, based on whatever).
This simple example doesn't provide much in the way of feedback (and no doc strings).
But the idea is this: restricted-sexp is the most general defstruct type-defining construct. This is what the Elisp manual, node Composite Types says:
(restricted-sexp :match-alternatives CRITERIA)
This is the most general composite type construct. The value may
be any Lisp object that satisfies one of CRITERIA. CRITERIA should
be a list, and each element should be one of these possibilities:
A predicate—that is, a function of one argument that returns
either nil or non-nil according to the argument. Using a
predicate in the list says that objects for which the
predicate returns non-nil are acceptable.
A quoted constant—that is, 'OBJECT. This sort of element in
the list says that OBJECT itself is an acceptable value.
For example,
(restricted-sexp :match-alternatives
(integerp 't 'nil))
allows integers, t and nil as legitimate values.
The customization buffer shows all legitimate values using their
read syntax, and the user edits them textually.
In the example I gave, the list of CRITERIA is a singleton, with just this function:
(lambda (x) (car (member x (my-function))))
That function ensures that the value you use for the option is a member of the list that function my-function returns. (And it makes the value be the car of what member returns, i.e., the particular member of the list that the user enters.
When using M-x customize-option you won't be able to set a new value if it isn't one of the values returned by my-function.
Instead of seeing feedback that the value was set to what you entered, you continue to see this help text:
EDITED, shown value does not take effect until you set or save it.
If you provide a valid value then you get confirmation that the value was set.
Admittedly, what you might really want is to provide for completion etc. in the editing field. For that, you would need to use/define an appropriate widget, because Customize, out of the box, provides for completion only for a limited set of defcustom type constructs (files, colors, etc.). You can see which ones by searching for completion starting in node Simple Types.
restricted-sexp is really a wonderful thing. It should be improved by Emacs to be more useful. But even as it is it should be used more, to provide more-specific type checking. Too many users defining defcustoms are a bit lazy, IMO, not bothering to provide a specific type definition even when that might be as simple as using choice. (Too many just use a type of sexp.)
I found a solution: I defined my-variable with type choice and only one default entry, then I wrote a function that updates the choice entries dynamically, and added that function to 'Custom-mode-hook. This hook is called each time Custom mode is entered. Thus, whenever the user is about to customize my-variable, the choice entries are updated before. Here is a sketch of code:
(defcustom my-variable
"None"
:type '(choice (const :tag "None" "None")))
(defun my-function ()
;; Function that provides the possible values of my-variable
)
(defun my-update-variable-allowed-values ()
(let* ( (choices '((const :tag "None" "None"))) )
(dolist (val (my-function))
(setq choices (cons (list 'const ':tag val val) choices)))
(setq choices (cons 'choice choices))
(put 'my-variable 'custom-type choices)))
(add-hook 'Custom-mode-hook 'my-update-variable-allowed-values)

Presenting a list

I have this list of names and different languages
(setq l '((david spanish german)
(amanda italian spanish english)
(tom german french)))
I want to do the next with a function: for each language, I need every name relationed with every language.
For example, if I call the function with the list L:
(lenguages L)
I want to show this:
( (english (amanda))
(spanish (david amanda))
(italian (amanda))
(german(david tom))
(french(tom))
)
I have an idea of how to do this, but it shows just one item.
(defun lenguages(names)
(cond((null names) nil)
((list (cadar names) (list (caar names))))))
this last function only show (spanish (david))
An iteration-based task like this is best suited to Common Lisp's immensely powerful loop macro. You can read all the details about this macro in the GigaMonkeys book, but we'll just go over the parts you need for this problem here. Let's start with the function definition.
(defun lenguages (names)
...)
Inside this, we want to iterate over the provided list. We also want to collect some keys, so a hash table would be useful to have. Hash tables (called maps or dicts in many other languages) associate keys to values in a time-efficient way.
(loop with hash = (make-hash-table)
for entry in names
for name = (car entry)
do ...
finally ...)
The loop macro is very powerful and has a language all its own. The with clause declares a local variable, in this case a hash table. The first for defines an iteration variable. The loop will run with entry bound to each entry of names and will stop when it runs out of entries. The third line is another local variable, but unlike with, a for variable is rebound every time, so at each iteration name will be the first element of entry. The do block contains arbitrary Lisp code that will be executed each iteration, and finally contains a block of Lisp code to execute at the end of the loop.
Inside the do block, we want to add the person's name to the hash table entry for each language they know, so we need another loop to loop over the known languages.
(loop for lang in (cdr entry)
do (push name (gethash lang hash)))
This loop goes inside the do block of the outer one. For each language in the person's list of known languages, we want to prepend that person's name onto the hash value for that language. Normally, we would have to consider the case in which the hash key doesn't exist, but luckily for us Common Lisp defaults to nil if the hash key doesn't exist, and prepending an element to nil creates a one-element list, which is just what we want.
Now, when this loop is done, the hash table will contain all the languages and keys and lists of people who know them as values. This is the data that you want, but it's not in the format you want. In fact, if we put this in our finally block
(return hash)
We would get some semi-useful output* that tells us we're on the right track.
#S(HASH-TABLE :TEST FASTHASH-EQL ((TOM GERMAN FRENCH) . (TOM TOM))
((AMANDA ITALIAN SPANISH ENGLISH) . (AMANDA AMANDA AMANDA))
((DAVID SPANISH GERMAN) . (DAVID DAVID)))
Instead, let's do one more loop to convert this hash table to the list that you want it to be. Here's what we want in the finally block now.
(return (loop for key being the hash-keys of hash using (hash-value value)
collect (list key value)))
This uses the relatively obscure being syntax for the loop macro, which allows easy iteration over hash tables. You should read this as: for every key-value pair, collect a list containing the key followed by the value into a list, then return the accumulated list. This is yet another of the loop macros interesting features: it tries to provide primitives for common use cases such as accumulating values into a list. And it comes in handy in cases like this.
Here's the complete code block.
(defun lenguages (names)
(loop with hash = (make-hash-table)
for entry in names
for name = (car entry)
do (loop for lang in (cdr entry)
do (push name (gethash lang hash)))
finally (return (loop for key being the hash-keys of hash using (hash-value value)
collect (list key value)))))
That link I provided earlier is to the GigaMonkeys book on Common Lisp, which is available online for free. I strongly encourage reading through it, as it's an amazing reference for all things Common Lisp. Especially if you're just starting out, that book can really set you in the right direction.
* Your output format may vary on this. The implementation chooses how to output structs.
The other answer is fine: here is a version which does not use loop or intermediate hashtables, but instead builds the required association-list directly. It's worth comparing the efficiency of this against the hash-table-based one: it does a lot more searching down lists, but in practice, for small amounts of data such things are often faster (hashtables have nontrivial overhead in many implementations) and it will always use less storage as it builds no structure it does not return.
Note that:
this will return results in a different order in general (it has no dependency on hash ordering);
this will ensure there is only one occurrence of each person for each language: (languages '((david german german))) is ((german (david))) not ((german (david david))) -- it pays some performance cost (which could be ameliorated for large data using more hashtables) for doing this.
So, here it is:
(defun languages (people)
(let ((langs '())) ;the map we are building
(dolist (pl people langs)
(destructuring-bind (person . person-languages) pl
(dolist (lang person-languages)
(let ((entry (assoc lang langs)))
(if (not (null entry))
;; there's an entry for lang: add the person to it
(pushnew person (second entry))
;; there is no entry, create one with person in it
(setf langs `((,lang (,person)) ,#langs)))))))))
(Note also that the loop based version could use loop's destructuring, which might be a little clearer.)

Where/How to store text, if not in kill-ring/registers [elisp, emacs]

I would like to be able to store text between 2 positions (the string in between), but I don't know where to conveniently store it, perhaps just locally, or even globally (let or setq). The answer is probably out there, but I couldn't find it.
Example:
I would like to store text in a symbol in order to search for it backwards. Let's say the region from (point) until the first whitespace character.
My previous way of doing this was using (kill-ring-save), but I know this is a bad practice.
From (here) (message "hello")(point)
I would be interested in both better techniques for doing this, as well as the best way to store a string which is somehwere around (point).
The regular no-frills answer would be to just use let. Contrary to what you seem to believe, it does not allocate global storage. In fact, it does just the opposite.
(let ((myvalue "temporary string"))
(message myvalue) )
=> "temporary string"
myvalue
=> Lisp error: (void-variable myvalue)
And you can easily write a function with a variable whose value is set only during the function's execution. The interactive form allows you to easily obtain the values of point and mark.
(defun mysearch (point mark)
(interactive "r")
(let ((str (buffer-substring-no-properties point mark))
(message "your search for %s can commence ..." str) ) )
A common idiom is to use save-excursion to move point to another place, then grab the region between the original location and where you ended up, then do something with it. When you exit the save-excursion, the cursor's position (and several other things) will be restored to how they were before.
(defun mysearch ()
(interactive)
(save-excursion
(let ((here (point)) str)
(forward-word -1)
(setq str (buffer-substring-no-properties (point) here))
(message "your search for %s can commence ..." str) ) ) )
Perhaps you also want to look at http://ergoemacs.org/emacs/elisp_idioms.html
If you need to persist the value between function invocations, then the common thing to do is to defvar a variable like #phils suggests. Several variables with a common prefix sounds like you should be creating a separate module for yourself. For a flexible solution with low namespace footprint, create your own obarray (and achieve some sort of guru status). See also http://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html#Definition%20of%20mapatoms
If a temporary local scope is all you require, then you definitely want to use let.
Otherwise you would usually define a variable (keeping in mind when you name it that elisp has no name spaces, so best practice is to use as reliably unique a prefix for all symbol names in a given library as practical).
(defvar SYMBOL &optional INITVALUE DOCSTRING)
If you omit the INITVALUE argument, the variable will not be bound initially, but ensures that your variable will use dynamic binding once used.
Then you just setq the variable as required.
Edit:
To obtain a buffer's contents between two points, use either of
(buffer-substring START END)
(buffer-substring-no-properties START END)
depending on whether or not you wish to preserve text properties.

How to acquire unique object id in Emacs Lisp?

Does emacs lisp have a function that provides a unique object identifier, such as e.g. a memory address? Python has id(), which returns an integer guaranteed to be unique among presently existing objects. What about elisp?
The only reason I know for wanting a function like id() is to compare objects, and ensure that they only compare equal if they are the same (as in, in the same memory location). In Lisps, this is done a bit differently from in Python:
In most lisps, including elisp, there are several different notions of equality. The most expensive, and weakest equivalence is equal. This is not what you want, since two lists (say) are equal if they have the same elements (tested recursively with equal). As such
(equal (list 1 2) (list 1 2)) => T
is true. At the other end of the spectrum is eq, which tests "identity" rather than equality:
(eq (list 1 2) (list 1 2)) => NIL
This is what you want, I think.
So, it seems that Python works by providing one equality test, and then a function that gives you a memory location for each object, which then can be compared as integers. In Elisp (and at least Common Lisp too), on the other hand, there is more than one meaning of "equality".
Note, there is also "eql", which lies somewhere between the two.
(EDIT: My original answer probably wasn't clear enough about why the distinction between eq and equal probably solves the problem the original poster was having)
There is no such feature in Emacs Lisp, as far as I know. If you only need equality, use eq, which performs a pointer comparison behind the scenes.
If you need a printable unique identifier, use gensym from the cl package.
If you need a unique identifier to serve as an index in a data structure, use gensym (or maintain your own unique id — gensym is simpler and less error-prone).
Some languages bake a unique id into every object, but this has a cost: either every object needs extra memory to store the id, or the id is derived from the address of the object, which precludes modifying the address. Python chooses to pay the cost, Emacs chooses not to.
My whole point in asking the question was that I was looking for a way to distinguish between the printed representations of different symbols that have the same name. Thanks to the elisp manual, I've discovered the variable print-gensym, which, when non-nil, causes #: to be prepended to uninterned symbols printed. Moreover, if the same call to print prints the same uninterned symbol more than once, it will mark the first one with #N= and subsequent ones with `#N#. This is exactly the kind of functionality I was looking for. For example:
(setq print-gensym t)
==> t
(make-symbol "foo")
==> #:foo
(setq a (make-symbol "foo"))
==> #:foo
(cons a a)
==> (#1=#:foo . #1#)
(setq b (make-symbol "foo"))
==> #:foo
(cons a b)
==> (#:foo . #:foo)
The #: notation works for read as well:
(setq a '#:foo)
==> #:foo
(symbol-name a)
==> "foo"
Note the ' on '#:foo--the #: notation is a symbol-literal. Without the ', the uninterned symbol is evaluated:
(symbol-name '#:foo)
==> "foo"
(symbol-name #:foo)
==> (void-variable #:foo)

Elisp: How to delete an element from an association list with string key

Now this works just fine:
(setq al '((a . "1") (b . "2")))
(assq-delete-all 'a al)
But I'm using strings as keys in my app:
(setq al '(("a" . "foo") ("b" . "bar")))
And this fails to do anything:
(assq-delete-all "a" al)
I think that's because the string object instance is different (?)
So how should I delete an element with a string key from an association list? Or should I give up and use symbols as keys instead, and convert them to strings when needed?
If you know there can only be a single matching entry in your list, you can also use the following form:
(setq al (delq (assoc <string> al) al)
Notice that the setq (which was missing from your sample code) is very important for `delete' operations on lists, otherwise the operation fails when the deleted element happens to be the first on the list.
The q in assq traditionally means eq equality is used for the objects.
In other words, assq is an eq flavored assoc.
Strings don't follow eq equality. Two strings which are equivalent character sequences might not be eq. The assoc in Emacs Lisp uses equal equality which works with strings.
So what you need here is an assoc-delete-all for your equal-based association list, but that function doesn't exist.
All I can find when I search for assoc-delete-all is this mailing list thread:
http://lists.gnu.org/archive/html/emacs-devel/2005-07/msg00169.html
Roll your own. It's fairly trivial: you march down the list, and collect all those entries into a new list whose car does not match the given key under equal.
One useful thing to look at might be the Common Lisp compatibility library. http://www.gnu.org/software/emacs/manual/html_node/cl/index.html
There are some useful functions there, like remove*, with which you can delete from a list with a custom predicate function for testing the elements. With that you can do something like this:
;; remove "a" from al, using equal as the test, applied to the car of each element
(setq al (remove* "a" al :test 'equal :key 'car))
The destructive variant is delete*.
Emacs 27+ includes assoc-delete-all which will work for string keys, and can also be used with arbitrary test functions.
(assoc-delete-all KEY ALIST &optional TEST)
Delete from ALIST all elements whose car is KEY.
Compare keys with TEST. Defaults to ‘equal’.
Return the modified alist.
Elements of ALIST that are not conses are ignored.
e.g.:
(setf ALIST (assoc-delete-all KEY ALIST))
In earlier versions of Emacs, cl-delete provides an alternative:
(setf ALIST (cl-delete KEY ALIST :key #'car :test #'equal))
Which equivalently says to delete items from ALIST where the car of the list item is equal to KEY.
n.b. The answer by Kaz mentions this latter option already, but using the older (require 'cl) names of delete* and remove*, whereas you would now (for supporting Emacs 24+) use cl-delete or cl-remove (which are auto-loaded).
If using emacs 25 or newer you can use alist-get
(setf (alist-get "a" al t t 'equal) t)