Emacs Lisp: Get universal-argument

By Xah Lee. Date: . Last updated: .

This page shows you how to make your emacs lisp command accept universal-argumentCtrl+u】 given by user.

Problem

You have written a emacs command. You want the command's behavior to be different if user presses 【Ctrl+u】 before calling your command.

Detail

Emacs has a mechanism for a command to have variant behavior if user calls universal-argumentCtrl+u】.

The universal argument has many uses. It can let user repeat a command n times. For example, type 【Ctrl+u 20 -】 and it'll type out --------------------.

For some commands, the universal argument is useful for variant behavior of the command. For example, in dired, typing w will copy the file name (dired-copy-filename-as-kill), but if you type 【Ctrl+u 0 w】, the copied name will be file full path.

Solution

To make your command aware of universal argument, there are 3 simple ways:

Example:

(defun f (x)
  "print argument received"
  (interactive "P")
  (message "%s" x)
  ;; value of x is from universal argument, or nil if universal-argument isn't called
)

Possible Values of Universal Argument

The following table shows the possible values of current-prefix-arg.

Key InputValue of current-prefix-argNumerical Value
No universal arg called.nil1
Ctrl+u -Symbol --1
Ctrl+u - 2Number -2-2
Ctrl+u 1Number 11
Ctrl+u 4Number 44
Ctrl+uList '(4)4
Ctrl+u Ctrl+uList '(16)16

(info "(elisp) Prefix Command Arguments")

Complex Example

Sometimes you do not want your function's parameter spec to explicitly contain universal argument, because it is not relevant to the function. So, (interactive "P") is not appropriate. For example, suppose you are writing this command:

(defun wrap-html-tag (tagName &optional className id)
  "Add a HTML tag to beginning and ending of current word or text selection."
)

Your command will create a HTML tag like this:

cat
   ↓
<div>cat</div>
or
<div class="xyz">cat</div>
or
<div id="id8295" class="xyz">cat</div>

When called interactively, it can prompt user to enter “class” and “id” values. If user just press Enter ↵ without giving them any value, then don't add these attributes to the tag.

However, often, the prompting for “class” and “id” are annoying, because, in practice, many tags don't need them. For example: {<b>bold</b>, <i>italic</i>}.

So, you want your command to do extra prompt only when preceded by universal-argument.

Here's solution:

(defun wrap-html-tag (tagName &optional className ξid)
  "Add a HTML tag to beginning and ending of current word or text selection.

When preceded with `universal-argument',
no arg = prompt for tag, class.
2 = prompt for tag, id.
any = prompt for tag, id, class.

When called interactively,
Default id value is 「id‹random number›」.
Default class value is 「xyz」.

When called in lisp program, if className is nil or empty string, don't add the attribute. Same for ξid."
  (interactive
   (cond
    ((equal current-prefix-arg nil)     ; universal-argument not called
     (list
      (read-string "Tag (span):" nil nil "span") ))
    ((equal current-prefix-arg '(4))    ; C-u
     (list
      (read-string "Tag (span):" nil nil "span")
      (read-string "Class (xyz):" nil nil "xyz") ))
    ((equal current-prefix-arg 2)       ; C-u 2
     (list
      (read-string "Tag (span):" nil nil "span")
      (read-string "id:" nil nil (format "id%d" (random (expt 2 28 ))))
      ))
    (t                                  ; all other cases
     (list
      (read-string "Tag (span):" nil nil "span")
      (read-string "Class (xyz):" nil nil "xyz")
      (read-string "id:" nil nil (format "id%d" (random (expt 2 28 )))) )) ) )

  ;; now, all the parameters of your function is filled.
  ;; code body here
  )

The (interactive …) is used to fill out the parameters, when your function is called by user interactively (as opposed to from a lisp program).

One way to use the interactive function is for it to return a list. This list's element will be fed to the function as arguments.

In our code, we use a conditional (cond …) to check the values of current-prefix-arg. If it's nil, then that means universal-argument is not called. So, we simply prompt for the tag name. But if the value is other, then we prompt for more.

The weird ξ you see in my elisp code is Greek x. I use Unicode char in symbol name for easy distinction from builtin symbols. You can just ignore it. 〔►see Programing Style: Variable Naming: English Words Considered Harmful

Like it? Buy Xah Emacs Tutorial. Thanks.

or, buy something from Best Keyboard for Emacs