A question that popped some time ago on one of the Emacs-related mailing lists was how to “simulate” interactive
code P
(that is, capital “P”), in a more complicated, s-expression form of interactive
.
Recall that P
as an interactive
code yields the raw prefix argument. This may be nil (if no prefix argument was given), an integer (when there was a regular, numeric prefix argument), the symbol -
(that is, a minus), in case of C-u -
etc., or a list with one element, which is always a power of four, and its four-base log is then the number if times C-u
was pressed. (The “raw” prefix argument can be converted to a regular number with the prefix-numeric-value
function, quite surprisingly written in C and not Elisp.)
Now the interactive
form argument can be also an s-expression; it is then evaluated to obtain the list of arguments for the interactive command being called.
There are a few nifty tricks with interactive
. (One of them is a simple way to detect whether a function was called interactively or not.)
But what if you need an s-expression, but you also want to get the raw prefix argument as one of the arguments? (Say you want your command to read some argument using read-string
, but also to detect things like C-u C-u
as opposed to C-u 16
.) The answer is simple: you just consult the variable current-prefix-arg
.
But that’s not the whole story. There are two more variables like this one: prefix-arg
and last-prefix-arg
. The meaning of the latter is clear: it is the value of prefix argument for the previous command. (I am not sure why it may be useful, but in case you need it, it is there. It doesn’t seem to be used anywhere in Emacs sources.) The former is probably something you should never touch: if set, it will become the prefix argument for the next command. In case you are wondering, why on earth anyone would want to override what C-u
does, the answer is: C-u
is actually bound to universal-argument
, which works exactly by setting prefix-argument
. And looking at the implementation of universal-argument
, which is – perhaps surprisingly – implemented in Elisp, not C, one wonders what would break if we changed the behavior of C-u
, so that e.g. pressing it twice would yield (9)
instead of (16)
etc. (Spoiler: probably a lot of things.) For extra fun, look up universal-argument
(and a few of its sister commands) in the Elisp reference. When introducing them, it says: The following commands exist to set up prefix arguments for the following command. Do not call them for any other reason. Of course, the only thing you want to do after reading that is trying them out in your own code. Also, reading through simple.el
where these and related commands (also, the universal-argument-map
keymap!) are defined is a fun experience.
I am not sure whether all this machinery is good design. It is clever for sure. I would not be able to come up with anything better, either. But it makes my head spin.