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)
Related
I'm just learning emacs and came across a configuration that demonstrates quite a bit of the functionality I want in my own configuration. It uses init.el as an entry point to an org file that handles the bulk of the configuration with extensive documentation. I am confused by the following function:
(put 'after-save-hook 'safe-local-variable
(lambda (value) (equal value '(org-babel-tangle t))))
What I think I understand is that this puts the value of the lambda expression into the property list of after-save-hook under the property name safe-local-variable, and that a value is safe if, when passed to the safe-local-variable-p function it returns a non-nil value. This lambda then appears to do an equality comparison between value and the list (org-babel-tangle t), so presumably this means that value is safe only when it's equal to the list (org-babel-tangle t)?
What I am having trouble understanding is twofold. First, where is the lambda getting value from? Second, what is this all actually doing? Neither the documentation I could find on after-save-hook nor org-babel-tangle clarified this for me. The author's comments say "Mark safe variables early so that tangling won't break," but I still don't get it.
The anonymous function with argument value gets its arg from the value of after-save-hook.
after-save-hook is a variable. Its value is a list of hooks.
This code puts the anonymous function as the safe-local-variable property value of symbol after-save-hook, so that when after-save-hook is processed as to see if it is a safe local variable, that function is called. The function is called on the current value of the variable, after-save-hook.
See the Elisp manual, node File Local Variables.
The reason for this is that the file DESKTOP.org starts with this line:
# -*- after-save-hook: (org-babel-tangle t); -*-
That is, when you open that file in Emacs, the local value of after-save-hook becomes (org-babel-tangle t). So whenever you save that file, it's going to call the function org-babel-tangle without any arguments, in order to generate a few shell scripts, e.g. scripts/screenshot.region.sh. The value t in a hook variable means that after calling all the functions in the local value of the hook variable, run-hooks is going to look at the global value of after-save-hook and call any functions listed there as well.
Obviously, allowing any file to specify arbitrary Lisp code to be run would be a security hole equaled only by Microsoft Word macros, so by default file-local settings for risky variables are ignored. Since we know this particular value is safe,* we use the safe-local-variable trick you're asking about. As per the documentation:
You can specify safe values for a variable with a
‘safe-local-variable’ property. The property has to be a function of
one argument; any value is safe if the function returns non-‘nil’ given
that value.
So that's what we have here:
(lambda (value) (equal value '(org-babel-tangle t)))
It is a function that takes one argument, and checks that the argument is equal to the specific value we want to allow. safe-local-variable-p is going to call this function on the specified file-local value, and only allow it if the function returns non-nil. Thus, value is going to be the value that is about to be assigned to after-save-hook. We can see that in action in M-x ielm:
*** Welcome to IELM *** Type (describe-mode) for help.
ELISP> (setq my-function (lambda (value) (equal value '(org-babel-tangle t))))
(lambda
(value)
(equal value
'(org-babel-tangle t)))
ELISP> (funcall my-function '(org-babel-tangle t))
t
ELISP> (funcall my-function 'something-else)
nil
* Is this safe, though?... If an attacker can get you to download a specially crafted file and run org-babel-tangle on it, they can overwrite arbitrary files in the file system using the privileges of your user. It's not what's happening in this case, just something to be aware of.
(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))))
*Note: Despite having frequented StackOverflow for a long time, this is the first question that I have posted myself. Apologies if it's a bit verbose. Constructive criticism appreciated.
When I define a struct in Common Lisp using defstruct, a predicate function is automatically generated that tests whether its argument is of the type defined by the defstruct. Eg:
(defstruct book
title
author)
(let ((huck-finn (make-book :title "The Adventures of Huckleberry Finn" :author "Mark Twain")))
(book-p huck-finn))
=> True
However, when defining a class using defclass, such functions are seemingly not generated by default (is there a way to specify this?), so I'm trying to add this functionality myself, because I'd like a) for this syntax to be consistent between structs and classes, b) to have an abbreviation of (typep obj 'classname), which I need to write very often and is visually noisy,
and c) as a programming exercise, since I'm still relatively new to Lisp.
I could write a macro that defines a predicate function given the name of a class:
(defclass book ()
((title :initarg :title
:accessor title)
(author :initarg :author
:accessor author)))
;This...
(defmacro gen-predicate (classname)
...)
;...should expand to this...
(defun book-p (obj)
(typep obj 'book))
;...when called like this:
(gen-predicate 'book)
The name that I need to pass to defun must be of the form 'classname-p. Here's where I have difficulty. To create such a symbol, I could use the "symb" function from Paul Graham's On Lisp (p. 58). When it is run on the REPL:
(symb 'book '-p)
=> BOOK-P
My gen-predicate macro looks like this so far:
(defmacro gen-predicate (classname)
`(defun ,(symb classname '-p) (obj)
(typep obj ,classname)))
(macroexpand `(gen-predicate 'book))
=>
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN '|'BOOK-P| 'NIL T))
(SB-IMPL::%DEFUN '|'BOOK-P|
(SB-INT:NAMED-LAMBDA |'BOOK-P|
(OBJ)
(BLOCK |'BOOK-P| (TYPEP OBJ 'BOOK)))
NIL 'NIL (SB-C:SOURCE-LOCATION)))
T
It would seem that the symbol created by (symb 'book '-p) is actually considered |'BOOK-P| by the implementation (SBCL), not BOOK-P. Sure enough, this now works:
(let ((huck-finn (make-instance 'book)))
(|'BOOK-P| huck-finn))
=> True
Why is the symbol created by symb interned as |'BOOK-P|? In On Lisp (same page as above) Graham says: "Any string can be the print-name of a symbol, even a string containing lowercase letters or macro characters like parentheses. When a symbol's name contains such oddities, it is printed within vertical bars." No such oddities exist in this case, do they? And am I correct in thinking that the "print-name" of a symbol is what is actually displayed on the standard output when the symbol is printed, and is, in the case of such oddities, distinct from the form of the symbol itself?
To be able to write function-defining macros like gen-predicate - whose defined functions are named based on the arguments passed to the macro - seems to me like something that Lisp hackers have probably been doing for ages. User Kaz says here (Merging symbols in common lisp) that the "mashing-up" of symbols can often be avoided, but that would defeat the purpose of this macro.
Finally, assuming I could get gen-predicate to work how I want, what would be the best way of ensuring that it be called for each new class as they are defined? Much in the same way as initialize-instance can be customized to perform certain actions upon instantiation of a class, is there a generic function called by defclass that can perform actions upon definition of a class?
Thank you.
That's a usual problem: what gets passed to a Macro?
Compare calls like this:
(symb 'book '-p)
and
(symb ''book '-p)
Your macro form is this:
(gen-predicate 'book)
GEN-PREDICATE is a macro. classname is a parameter for this macro.
Now what is the value of classname inside the macro during code expansion? Is it book or 'book?
Actually it is the latter, because you wrote (gen-predicate 'book). Remember: macros see source code and the argument source gets passed to the macro function - not the value. The argument is 'book. Thus this gets passed. (QUOTE BOOK) is the same, only printed differently. So it is a two element list. The first element is the symbol QUOTE and the second element is the symbol BOOK.
Thus the macro now calls the function SYMB with the argument value (QUOTE BOOK) or, shorter, 'BOOK.
If you want to generate the predicate without the quote character, you need to write:
(gen-predicate book)
Alternatively you can also change the macro:
(symb classname '-p)
would be:
(symbol (if (and (consp classname)
(eq (first classname) 'quote))
(second classname)
classname))
Compare
We write
(defun foo () 'bar)
and not
(defun 'foo () 'bar) ; note the quoted FOO
DEFUN is a macro and the first argument is the function name. It's a similar problem then...
Second part of the question
I don't really know any good answer to that. I can't remember any easy way to run code (for example to define a function) after a class definition.
Maybe use the MOP, but that's ugly.
write a custom macro DEFINE-CLASS which does what you want: expands into DEFCLASS and the DEFUN.
iterate over all symbols in a package, find the classes and define the corresponding predicates
To address the second part of the question, classes are themselves objects, thanks to the MOP, so it might be possible to write an :after method on initialize-instance specialized on STANDARD-CLASS. But you should check the MOP to see whether defining such a method is allowed or not.
If it's possible, then yes, you can run code in response to the creation of a class; however, since you don't know the name of the class being created until runtime, you cannot spell it textually in the source, so you cannot use your macro (unless you use eval). You'd rather use something like
(let ((classname (class-name class)))
(compile (generate-my-predicate-symbol classname)
(lambda (x) (typep x classname))))
I think Rainer's suggestion to write your own DEFINE-CLASS macro is the way to go, I mean, the way a seasoned Lisper most likely would do it, if there aren't any other considerations at play. But I'm not really a seasoned Lisper, so I might be wrong ;)
I have implemented this function. It is supposed to check the input that we have given to it, and if it is found in the list, a "True" will be shown on the screen. However, it just works for the numbers and if I give it a character I receive an error.
(defun element (x lst)
(dolist (item lst)
(if (= item x) (return t))))
How can I modify it so that it can also look for any characters given to it?
Thanks in advance.
There are several comparison operators. The general ones are eq, eql, equal and equalp. Look them up in the hyperspec.
For objects of specific types, there are often specialized comparators, e.g. string= and char=.
Finally, for list operations, there are functions like member, which can free you from writing loops by hand. They take an optional test parameter, through which you can pass the comparison function.
As you discovered, the = function only works with numbers.
If you try basing your function on find instead, you'll likely find that its default use of the eql function as its test provides the behavior you seek:
(defun element (needle haystack)
(not (null (find needle haystack))))
As alternates to find, you should also study its siblings member and position. In your case, since you only want to distinguish between the item having been found or not, you should choose the function that does the least work. My guess is that position loses here, and that member and find are equivalent; member returns the list from which it extracted the car, whereas find returns the car. In both functions, it's necessary to extract the car.
Easy, use #'eq instead of #'=, thus the 3rd line becomes: (if (eq item x) ...
Alternatively, you could use the built-in #'intersection to check if any of the given items are in the list, thus: (if (not (eq (intersection lst '(x)) nil)))
Consider this piece of code:
(defvar lst '(1 1))
(defmacro get-x (x lst)
`(nth ,x ,lst))
(defun get-y (y lst)
(nth y lst))
Now let us assume that I want to change the value of the elements of the list called lst, the car with get-x and the cdr with get-y.
As I try to change the value with get-x (with setf) everything goes fine but if I try it with get-y it signals an error (shortened):
; caught STYLE-WARNING:
; undefined function: (SETF GET-STUFF)
Why does this happen?
I myself suspect that this happens because the macro simply expands and the function nth simply returns a reference to the value of an element in the list and the function on the other hand evaluates the function-call to nth and returns the value of the referenced value (sounds confusing).
Am I correct in my suspicions?
If I am correct then how will one know what is simply a reference to a value and an actual value?
The error does not happen with the macro version, because, as you assumed, the expression (setf (get-x some-x some-list) some-value) will be expanded (at compile-time) into something like (setf (nth some-x some-list) some-value) (not really, but the details of setf-expansion are complex), and the compiler knows, how to deal with that (i.e., there is a suitable setf expander defined for function nth).
However, in the case of get-y, the compiler has no setf expander, unless you provide one. The easiest way to do so would be
(defun (setf get-y) (new-value x ls) ; Note the function's name: setf get-y
(setf (nth x ls) new-value))
Note, that there are a few conventions regarding setf-expanders:
The new value is always provided as the first argument to the setf function
All setf functions are supposed to return the new value as their result (as this is, what the entire setf form is supposed to return)
There is, BTW, no such concept as a "reference" in Common Lisp (at least not in the C++ sense), though there once were Lisp dialects which had locatives. Generalized place forms (ie., setf and its machinery) work very differently from plain C++ style references. See the CLHS, if you are curious about the details.
SETF is a macro.
The idea is that to set and read elements from data structures are two operations, but usually require two different names (or maybe even something more complex). SETF now enables you to use just one name for both:
(get-something x)
Above reads a datastructure. The inverse then simply is:
(setf (get-something x) :foobar)
Above sets the datastructure at X with :FOOBAR.
SETF does not treat (get-something x) as a reference or something like that. It just has a database of inverse operations for each operation. If you use GET-SOMETHING, it knows what the inverse operation is.
How does SETF know it? Simple: you have to tell it.
For The NTH operation, SETF knows how to set the nth element. That's builtin into Common Lisp.
For your own GET-Y operation SETF does not have that information. You have to tell it. See the Common Lisp HyperSpec for examples. One example is to use DEFUN and (SETF GET-Y) as a function name.
Also note following style problems with your example:
lst is not a good name for a DEFVAR variable. Use *list* as a name to make clear that it is a special variable declared by DEFVAR (or similar).
'(1 2) is a literal constant. If you write a Common Lisp program, the effects of changing it are undefined. If you want to change a list later, you should cons it with LIST or something like COPY-LIST.