9

Emacs has repeat and repeat-complex-command, that draw different commands from command history and are bound to different keys. How do you repeat any last command - whether it was complex or not - with a single key? In other words, such a repeating command would behave like repeat-complex-command if the last command required input, otherwise it would behave like repeat.

EDIT: In other words, I am looking for a way to read the last command, complex or not, and then call either repeat-complex-command or repeat on it, whichever is appropriate. For instance, let's say that such a new command is bound to <f8>. Then:

  • (mimicking C-x M-: (repeat-complex-command) with M-z (zap-to-char)): C-u M-z a <f8> <f8> will be equivalent to C-u M-z a C-x M-: RET C-x M-: RET

  • (mimicking C-x z (repeat) with C-f (forward-char)): C-u C-f <f8> <f8> will be equivalent to C-u C-f C-x z z

Now, repeat-complex-command requires you to confirm the Lisp form that will be executed. To allow for repeating a complex command without confirmation, I have written an alternative version of repeat-complex-command, called repeat-complex-command-no-confirm (see below for the implementation). The problem is that I can't understand how to determine whether I should call repeat or repeat-complex-command-no-confirm when pressing <f8>.

--

(defun repeat-complex-command-no-confirm (arg)
  "Like `repeat-complex-command' but does not require confirmation."
  ;; Adapted from `repeat-complex-command' of Emacs 24.5.1.
  (interactive "p")
  (let ((elt (nth (1- arg) command-history))
        newcmd)
    (if elt
        (progn
          (setq newcmd elt)

          ;; If command to be redone does not match front of history,
          ;; add it to the history.
          (or (equal newcmd (car command-history))
              (setq command-history (cons newcmd command-history)))
          (unwind-protect
              (progn
                ;; Trick called-interactively-p into thinking that `newcmd' is
                ;; an interactive call (bug#14136).
                (add-hook 'called-interactively-p-functions
                          #'repeat-complex-command--called-interactively-skip)
                (eval newcmd))
            (remove-hook 'called-interactively-p-functions
                         #'repeat-complex-command--called-interactively-skip)))
      (if command-history
          (error "Argument %d is beyond length of command history" arg)
        (error "There are no previous complex commands to repeat")))))

1 Answer 1

5

Others will no doubt provide different solutions. Here's mine, from library misc-cmds.el.

(defun repeat-command (command)
  "Repeat COMMAND."
  (let ((repeat-message-function  'ignore))
    (setq last-repeatable-command  command)
    (repeat nil)))

Then just define a new, repeating command for any non-repeating command, and remap the keys from the non-repeater to the repeater. For example:

(defun next-buffer-repeat ()
  "Switch to the next buffer in the selected window.
You can repeat this by hitting the last key again..."
  (interactive)
  (require 'repeat)
  (repeat-command 'next-buffer))

(global-set-key [remap next-buffer] 'next-buffer-repeat)

In particular, you can use this to repeat a command that is on a prefix key. For example remapping next-buffer to next-buffer-repeat means that you can use C-x <right> <right>.... The key it is bound to, C-x <right>, need not be a repeating key (one that you can just hold down. All you need is to use C-x once and then hold down <right>.


Sorry, I just realized that you also want to repeat a "complex command". Actually (IMHO), repeating a complex command is a misnomer. It just means repeating a command with (by default) the same arguments. It purposefully lets you edit the Lisp sexp that will do that, so you can, for example, change the arguments.

In sum, command repeat-complex-command (bound to C-x ESC ESC, for example) does something special and quite different from just repeat the last command (i.e., from the kind of thing I showed above). It's not clear what repeatedly repeating a "complex command" might mean or what use it would be. IOW, the notion of repeating a command, e.g. by holding down a key that it is bound to, is quite different from using repeat-complex-command, which initiates a dialog that lets you edit and then invoke a command specifying particular argument values.

So unless you can better describe what you have in mind by somehow combining command repetition in the usual sense with what repeat-complex-command does, I'm afraid I can't help with that part of your question.


Update after your clarification.

So this is essentially what you have, to repeat the last "complex" command, meaning the last command that read input from the minibuffer. (Note that you need to remove repeat-complex-command-no-confirm from the history.)

(defun repeat-complex-command-no-confirm ()
  "..."
  (interactive)
  (let* ((hist  command-history)
         newcmd)
    (while (eq 'repeat-complex-command-no-confirm (caar hist))
      (setq hist  (cdr hist)))
    (setq newcmd  (car hist))
    (if newcmd
        (apply #'funcall-interactively (car newcmd)
               (mapcar (lambda (ee) (eval ee t)) (cdr newcmd)))
      (error "There are no previous complex commands to repeat"))))

You can bind that to a repeatable key (e.g. C-o'). Or you can define a repeatable command usingrepeat-command(i.e., passrepeat-complex-command-no-confirmto it), to be able to have it work when bound to a repeatable key that is on a prefix key (e.g.C-x o`).

But when you use such a key, invoking repeat-complex-command-no-confirm, you will repeat the last command that used the minibuffer, not necessarily the last command.

Anyway, you can use something like the following to get what you say you want. The last line prevents my-repeat from being the last command, so that using it again does not try to repeat my-repeat but repeats the last repeated command.

(defun my-repeat ()
  "..."
  (interactive)
  (if (eq last-command (caar command-history))
      (repeat-complex-command-no-confirm)
    (call-interactively last-command))
  (setq this-command  last-command))

(global-set-key "\C-o" 'my-repeat) ; Bind it to a repeatable key
4
  • This question has responses that explain differences between repeat and repeat-complex-command.
    – Emacs User
    Jun 11, 2015 at 17:18
  • @EmacsUser: Yes, well as you can see, that question you linked is all over the map - the question was unclear, so the answers are far-ranging. They are all pertinent to some interpretation of the question, but they are a mixed bag. (See my comment to this answer there.)
    – Drew
    Jun 11, 2015 at 17:27
  • yes, thanks for clarifying. That response certainly helps anyone digging deeper.
    – Emacs User
    Jun 11, 2015 at 17:32
  • @Drew Thanks for your detailed answer. I have expanded my question and, hopefully, now it is clearer.
    – Eleno
    Jun 11, 2015 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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