Repetindo qualquer último comando (complexo ou não)

8

O Emacs possui repeate repeat-complex-command, que desenham comandos diferentes do histórico de comandos e estão vinculados a chaves diferentes. Como você repete qualquer último comando - complexo ou não - com uma única tecla? Em outras palavras, esse comando de repetição se comportaria como repeat-complex-commandse o último comando exigisse entrada, caso contrário, se comportaria como repeat.

EDIT : Em outras palavras, estou procurando uma maneira de ler o último comando, complexo ou não, e depois chamá -lo repeat-complex-commandou repeatnele, o que for apropriado. Por exemplo, digamos que esse novo comando esteja vinculado <f8>. Então:

  • (imitando C-x M-: (repeat-complex-command)com M-z (zap-to-char)): C-u M-z a <f8> <f8>será equivalente aC-u M-z a C-x M-: RET C-x M-: RET

  • (imitando C-x z (repeat)com C-f (forward-char)): C-u C-f <f8> <f8>será equivalente aC-u C-f C-x z z

Agora, repeat-complex-commandvocê precisa confirmar o formulário Lisp que será executado. Para permitir a repetição de um comando complexo sem confirmação, escrevi uma versão alternativa do repeat-complex-commandchamado repeat-complex-command-no-confirm(veja abaixo para a implementação). O problema é que não consigo entender como determinar se devo ligar repeatou repeat-complex-command-no-confirmpressionar <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")))))
Elena
fonte

Respostas:

5

Outros, sem dúvida, fornecerão soluções diferentes. Aqui está o meu, da biblioteca misc-cmds.el.

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

Em seguida, basta definir um novo comando repetido para qualquer comando não repetitivo e remapear as chaves do não repetidor para o repetidor. Por exemplo:

(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)

Em particular, você pode usar isso para repetir um comando que está em uma chave de prefixo. Por exemplo, remapear next-bufferpara next-buffer-repeatsignifica que você pode usar C-x <right> <right>.... A chave à qual está vinculada, C-x <right>não precisa ser uma tecla repetida (uma que você pode apenas manter pressionada. Tudo o que você precisa é usar C-xuma vez e depois pressionar <right>.


Desculpe, acabei de perceber que você também deseja repetir um "comando complexo". Na verdade (IMHO), repetir um comando complexo é um nome impróprio. Significa apenas repetir um comando com (por padrão) os mesmos argumentos. Ele intencionalmente permite editar o Lisp sexp que fará isso, para que você possa, por exemplo, alterar os argumentos.

Em suma, o comando repeat-complex-command(vinculado a C-x ESC ESC, por exemplo) faz algo especial e bem diferente de apenas repetir o último comando (ou seja, do tipo de coisa que mostrei acima). Não está claro o que repetir repetidamente um "comando complexo" pode significar ou que utilidade ele teria. IOW, a noção de repetir um comando, por exemplo, mantendo pressionada uma tecla à qual ele está vinculado, é bem diferente de usar repeat-complex-command, que inicia uma caixa de diálogo que permite editar e depois chamar um comando especificando valores específicos de argumentos.

Portanto, a menos que você possa descrever melhor o que tem em mente, combinando de alguma forma a repetição de comandos no sentido usual com o que repeat-complex-commandfaz, receio que não possa ajudar com essa parte da sua pergunta.


Atualize após seu esclarecimento.

Portanto, é basicamente isso que você tem, para repetir o último comando "complexo", significando o último comando que lê a entrada do minibuffer. (Observe que você precisa remover repeat-complex-command-no-confirmdo histórico.)

(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"))))

Você pode vincular isso a uma tecla repetível (por exemplo, C-x o` C-o'). Or you can define a repeatable command usingrepetir-comando (i.e., passrepetir-complexo-comando-não-confirmar to it), to be able to have it work when bound to a repeatable key that is on a prefix key (e.g.).

Mas quando você usa essa chave, invocando repeat-complex-command-no-confirm, repetirá o último comando que usou o minibuffer, não necessariamente o último comando.

De qualquer forma, você pode usar algo como o seguinte para obter o que deseja. A última linha impede que my-repeatseja o último comando, para que usá-lo novamente não tente repetir, my-repeatmas repita o último comando repetido.

(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
Desenhou
fonte
Esta pergunta tem respostas que explicam as diferenças entre repeat e repeat-complex-command .
Emacs usuário
@EmacsUser: Sim, como você pode ver, essa pergunta que você vinculou está em todo o mapa - a pergunta não era clara, portanto as respostas são variadas. Todos eles são pertinentes a alguma interpretação da questão, mas são uma mistura. (Ver o meu comentário para esta resposta lá.)
de Drew
sim, obrigado por esclarecer. Essa resposta certamente ajuda qualquer um a se aprofundar.
Emacs usuário
@ Drew Obrigado pela sua resposta detalhada. Eu ampliei minha pergunta e, espero, agora seja mais clara.
Elena