Mengulang perintah terakhir apa pun (kompleks atau tidak)

8

Emacs memiliki repeatdan repeat-complex-command, yang menarik perintah yang berbeda dari sejarah perintah dan terikat pada kunci yang berbeda. Bagaimana Anda mengulangi setiap perintah terakhir - apakah itu kompleks atau tidak - dengan tombol tunggal? Dengan kata lain, perintah berulang seperti itu akan berperilaku seperti repeat-complex-commandjika perintah terakhir membutuhkan input, jika tidak maka akan berperilaku seperti repeat.

EDIT : Dengan kata lain, saya mencari cara untuk membaca perintah terakhir, kompleks atau tidak, dan kemudian memanggil salah satu repeat-complex-commandatau repeatdi atasnya, mana yang sesuai. Sebagai contoh, katakanlah bahwa perintah baru itu terikat <f8>. Kemudian:

  • (meniru C-x M-: (repeat-complex-command)dengan M-z (zap-to-char)): C-u M-z a <f8> <f8>akan setara denganC-u M-z a C-x M-: RET C-x M-: RET

  • (meniru C-x z (repeat)dengan C-f (forward-char)): C-u C-f <f8> <f8>akan setara denganC-u C-f C-x z z

Sekarang, repeat-complex-commandmengharuskan Anda untuk mengkonfirmasi formulir Lisp yang akan dieksekusi. Untuk memungkinkan pengulangan perintah yang kompleks tanpa konfirmasi, saya telah menulis versi alternatif dari repeat-complex-command, yang disebut repeat-complex-command-no-confirm(lihat di bawah untuk implementasinya). Masalahnya adalah saya tidak mengerti bagaimana menentukan apakah saya harus menelepon repeatatau repeat-complex-command-no-confirmketika menekan <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
sumber

Jawaban:

5

Orang lain pasti akan memberikan solusi yang berbeda. Ini milik saya, dari perpustakaan misc-cmds.el.

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

Kemudian tentukan saja perintah baru yang berulang untuk setiap perintah yang tidak berulang, dan remap kunci dari non-repeater ke repeater. Sebagai contoh:

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

Secara khusus, Anda dapat menggunakan ini untuk mengulangi perintah yang ada pada kunci awalan. Misalnya remapping next-bufferuntuk next-buffer-repeatsarana yang dapat Anda gunakan C-x <right> <right>.... Kunci itu terikat,, C-x <right>tidak perlu menjadi kunci berulang (salah satu yang Anda bisa tahan. Yang Anda butuhkan adalah menggunakan C-xsekali dan kemudian tahan <right>.


Maaf, saya baru sadar bahwa Anda juga ingin mengulangi "perintah kompleks". Sebenarnya (IMHO), mengulangi perintah kompleks adalah keliru. Itu hanya berarti mengulangi perintah dengan (secara default) argumen yang sama. Dengan sengaja Anda dapat mengedit Lisp sexp yang akan melakukan itu, sehingga Anda dapat, misalnya, mengubah argumen.

Singkatnya, perintah repeat-complex-command(terikat untuk C-x ESC ESC, misalnya) melakukan sesuatu yang istimewa dan sangat berbeda dari hanya mengulangi perintah terakhir (yaitu, dari jenis hal yang saya tunjukkan di atas). Tidak jelas apa yang berulang kali mengulangi "perintah kompleks" mungkin berarti atau apa gunanya itu. TKI, gagasan mengulang perintah, misalnya dengan menahan kunci yang terikat, sangat berbeda dari menggunakan repeat-complex-command, yang memulai dialog yang memungkinkan Anda mengedit dan kemudian memanggil perintah yang menentukan nilai argumen tertentu.

Jadi, kecuali Anda dapat dengan lebih baik menggambarkan apa yang ada dalam pikiran Anda dengan cara menggabungkan pengulangan perintah dalam arti yang biasa dengan apa yang repeat-complex-commandada, saya khawatir saya tidak dapat membantu dengan bagian dari pertanyaan Anda.


Perbarui setelah klarifikasi Anda.

Jadi ini pada dasarnya adalah apa yang Anda miliki, untuk mengulangi perintah "kompleks" terakhir, yang berarti perintah terakhir yang membaca input dari minibuffer. (Perhatikan bahwa Anda perlu menghapus repeat-complex-command-no-confirmdari riwayat.)

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

Anda dapat mengikatnya ke kunci yang dapat diulang (mis. C-o'). Or you can define a repeatable command usingRepeat-command (i.e., passrepeat-complex-command-no-confirm to 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`).

Tetapi ketika Anda menggunakan kunci seperti itu, memanggil repeat-complex-command-no-confirm, Anda akan mengulangi perintah terakhir yang menggunakan minibuffer, belum tentu perintah terakhir.

Bagaimanapun, Anda dapat menggunakan sesuatu seperti berikut ini untuk mendapatkan apa yang Anda inginkan. Baris terakhir mencegah my-repeatdari menjadi perintah terakhir, sehingga menggunakannya lagi tidak mencoba untuk mengulang my-repeattetapi mengulangi perintah yang terakhir diulang.

(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
Drew
sumber
Pertanyaan ini memiliki tanggapan yang menjelaskan perbedaan antara repeat dan repeat-complex-command .
Pengguna Emacs
@EmacsUser: Ya, seperti yang Anda lihat, pertanyaan yang Anda tautkan ada di peta - pertanyaannya tidak jelas, jadi jawabannya sangat luas. Mereka semua berkaitan dengan beberapa interpretasi dari pertanyaan, tetapi mereka adalah tas campuran. (Lihat komentar saya untuk jawaban ini di sana.)
Drew
ya, terima kasih sudah menjelaskan. Respons itu tentu saja membantu siapa pun menggali lebih dalam.
Pengguna Emacs
@Drew, Terima kasih atas jawaban terperinci Anda. Saya telah memperluas pertanyaan saya dan, semoga, sekarang lebih jelas.
Elena