5

I have made the following function to count how many C-u prefixes a command was given (assuming it is called interactively), but I feel this is a common-enough problem that there should be a built-in function (or a package that solves this problem more robustly). Is there a better way to do this?

(defun tmp:how-many (arg)
  ;; Return zero if `arg' is 1 or nil
  (if (or (null arg) (equal arg 1)) 0
    ;; If `arg' is a list (as it is when called interactively), extract
    ;; the number.
    (when (listp arg)
      (setq arg (car arg)))
    ;; Recurse
    (if arg
        (1+ (tmp:how-many (/ arg 4)))
      0)))

(defun tmp:test (arg)
  (interactive "P")
  (message "%S" (tmp:how-many arg)))
  • 1
    I simply use a cl-case statement of 4,16,64,.., t. In absence of prefix, the 't' case will be evaluated. – Kaushal Modi Dec 6 '14 at 18:59
  • If you are asking about practical uses then I think it makes little sense to look for handling an arbitrary number of C-us. If you are expecting users to use more than, say, five C-us then you are probably really stretching it. In practice, from zero to three is plenty. And in any case you need to distinguish the cases, whether you test 1, 2, 3 or 4, 16, 64. – Drew Dec 9 '14 at 4:57
  • @Drew Absolutely agree on all counts. As with a lot of my questions (here and elsewhere), this one arises from sheer curiosity – not necessarily any overtly practical application. Still, I think the answers below are generally useful :) – Sean Allred Dec 9 '14 at 5:12
5

I will assume that you want to distinguish only uses of a plain prefix arg, e.g., C-u, C-u C-u, C-u C-u C-u, etc., and not uses of a numeric prefix arg, e.g., C-u 23, C-9, C-- 5.

Test both, in order:

  1. Whether the value of current-prefix-arg is a cons, using consp. If not, then a plain prefix arg was not used.

  2. The prefix-numeric-value of current-prefix-arg, to see which power of 4 it is.

For example:

(if (consp current-prefix-arg)
    (case (prefix-numeric-value current-prefix-arg)
      (4   (do-C-u-stuff))
      (16  (do-C-u-C-u-stuff))
      (64  (do-C-u-C-u-C-u-stuff))
      ...)
  ...) ; Do something for absent prefix arg or non-plain prefix arg

case is a macro from the CL libraries. Use (eval-when-compile '(require 'cl)). (Or you can use cl-case, if your Emacs version has it.)

  • Is there an alternative for case from cl-lib? – Sean Allred Dec 7 '14 at 15:09
  • Yes, cl-case is the same thing. – Drew Dec 7 '14 at 15:56
  • @Sean The hyperlink in my comment to your question takes you to an example of cl-case use. – Kaushal Modi Dec 8 '14 at 0:29
  • I'm going to accept this answer because it more fully addresses how one would handle prefix args, but I think it should be used in conjunction with my logarithm trick for clarity of code :) thanks! – Sean Allred Dec 9 '14 at 4:01
  • 1
    Note that an absent prefix argument (nil) is returned as 1 by prefix-argument-numeric-value – Sean Allred Dec 9 '14 at 4:03
6

Assuming you only want to understand arguments given using only C-u, you can use a base-four logarithm:

(defun tmp:how-many (arg)
  (when (consp arg)
    (truncate
     (log (car arg) 4))))

Note that such a function is doomed to fail if a sequence like C-3 M-x tmp:test is used; the only appropriate response to such usage is to signal an error or return nil, which was what I do here. (Returning arg would imply ambiguous results between, e.g., C-3 M-x tmp:test and C-u C-u C-u M-x tmp:test.)

  • 2
    +1 for a logarithm with base 4! I wish I could give a +2 for extreme cleverness. Only minor suggestion would be to wrap the log in a truncate, since log returns a float and you probably want an integer. – Dan Dec 6 '14 at 22:14
  • @Dan ah, yes! Good idea :) – Sean Allred Dec 6 '14 at 22:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.