7

Many Emacs commands alter their behavior when called with one or more C-u prefixes. In some cases the default behavior of a command is less useful to me than the behavior I get when prefixing it with C-u. At the same time, I do not want to get rid of the default behavior completely.

To give a concrete example, the quit-window command (bound to q in help-mode) quits the current window and buries the buffer displayed in it by default. When called with C-u it kills the buffer instead. I would like the command to kill the buffer by default and bury it when called with a C-u prefix.

Q: How can I tell Emacs to make a command behave as if it was called with a C-u prefix by default while moving the default behavior to the C-u prefix?

I know that I could address this by redefining the original command or wrapping it in a custom command that passes prefix args according to my preferences. But I'd rather do something like this:

(swap-args 'quit-window)
4

Something like this:

(defun swap-args (fun)
  (if (not (equal (interactive-form fun)
                  '(interactive "P")))
      (error "Unexpected")
    (advice-add
     fun
     :around
     (lambda (x &rest args)
       "Swap the meaning the universal prefix argument"
       (if (called-interactively-p 'any)
           (apply x (cons (not (car args)) (cdr args)))
         (apply x args))))))

Obviously, only works for (interactive "P"). For other types of interactive it may not make sense to negate the first argument.

  • 1
    Could be a bit simpler using :filter-args instead of :around, I think. – npostavs May 26 '15 at 15:32
  • Thanks, swap-args works in that it makes C-u behavior the default when applying it to a command. However, when I call the command with C-u, I don't get the original behavior. Maybe called-interactively-p is to blame? My understanding is that with an arg of 'any, this function will only return nil if the containing command is called from Lisp, so when invoking the advised command via a key binding, the else branch can't be reached. – itsjeyd May 27 '15 at 7:58
  • 'any was fine, I used funcall instead of apply by mistake. – abo-abo May 27 '15 at 10:54
  • 2
    You should add something to the docstring as well, otherwise this is bound to be confusing. – Gilles 'SO- stop being evil' May 27 '15 at 12:02
  • 1
    Annoyingly some functions (eg. org-insert-subheading) check literally for the raw universal argument (apparently (4)) instead of a truth coercing check. – olejorgenb Jan 15 '17 at 12:43
1

Another method based on the fact that an interactive-form property in the function's plist overrides the form specified in code: (ref)

(put 'org-insert-subheading
     'interactive-form
     '(interactive (progn (if current-prefix-arg
                              '(nil)
                            '((4))))))

Using (interactive-form 'function) to get the current spec, it's possible to handle more complex specs too.

I think the best solution (if possible) is to wrap the function with (let ((prefix-arg (not current-prefix-arg))) though

0

Not that easy as thought. However, as it's trivial to have the swapped command:

(defun my-quit-window-args-swapped (&optional bury window)
"Adapted docstring blah, blah "
  (interactive "P")
  (quit-restore-window window (if bury 'bury 'kill)))
  • Thanks, but as I mentioned in my question, I am looking for a generic solution that I can apply to different commands, not a wrapper that is specific to the quit-window command. – itsjeyd May 27 '15 at 12:02
  • @itsjeyd There is no finite restriction WRT to result and employment of an argument. It's not about "(swap-args ..." but about use and meaning of args - which is free finally. – Andreas Röhler May 27 '15 at 12:55
  • 1
    I should have chosen my words more carefully. I didn't mean to suggest that your solution can't be adapted to work for other commands. It's a perfectly good solution for swapping default and C-u behavior, and I am sure others who come across your post will be helped by it! Personally, I am not going to use it because I have multiple commands whose behavior I want to change, and would like to avoid having to define multiple wrappers. – itsjeyd May 27 '15 at 15:30
  • @itsjeyd AFAIU the only thing defined here is the way the body receives C-u. There is no standard at which point in body the arg is used, also there are many ways to make use of it - in a boolean sense here. Sure, you could employ some kind of AI to cover and deal with all these possibilities. :) – Andreas Röhler May 28 '15 at 6:00

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.