如果你连着三次用了同一个命令,帮你自动重复它

有时候想重复一个命令,比如

  • 一直向下滚屏,或者说执行 C-n N 次;
  • 输入 --------------------------- 这样的重复序列。

需要一直按着 C-n- 会比较烦人。我刚写了一个 repeater-mode 自动帮用户重复。比如说你连按 3 次 C-n,它就会帮你一直按着 C-n,直到你按任意一个按键终止。


最初的代码
(defvar repeater-commands (make-ring 2))

(defvar repeater-timeout 1 "决定是否重复的等待时间.")
(defvar repeater-interval 0.1 "重复间隔.")

(defun repeater-post-command ()
  (ring-insert repeater-commands (list last-repeatable-command
                                       last-command-event))
  (when (= (ring-length repeater-commands) 2)
    (let ((last (ring-ref repeater-commands 0))
          (penult (ring-ref repeater-commands 1)))
      (when (equal last penult)
        (let ((this (cons this-command (append (this-command-keys-vector) nil))))
          (when (equal this last)
            (unwind-protect
                (let ((message-log-max nil)
                      (name (propertize (symbol-name this-command)
                                        'face font-lock-function-name-face)))
                  
                  (message "About to repeating %s... (Hit any key to quit)" name)
                  (when (sit-for repeater-timeout)
                    (let ((count 0))
                      (while (and (sit-for repeater-interval)
                                  (condition-case err
                                      (prog1 t (call-interactively this-command))
                                    (error
                                     (message "%s" (error-message-string err))
                                     nil)))
                        (setq count (1+ count))
                        (message "Repeating %s [%d times] (Hit any key to quit)"
                                 name count)))))
              (dotimes (_ (ring-length repeater-commands))
                (ring-remove repeater-commands)))))))))

(define-minor-mode repeater-mode
  "如果你连着三次用了同一个命令,帮你自动重复它."
  :global t
  :lighter " Repeater"
  (if repeater-mode
      (add-hook 'post-command-hook #'repeater-post-command)
    (remove-hook 'post-command-hook #'repeater-post-command)))
3 个赞

三个可能有点少?比如JavaScript里的三个等号。markdown的三个backtick,python 的三个引号,等等。

1 个赞

3 作为重复的门槛正好,不多不少。当然如果有精力的话,也应该考虑你说的这些情况,当作特例,不重复它们。

我把你提到的三个特例给排除掉了,谢谢你的意见。

1 个赞

很好用,我加到自己的配置里了 :smile:

第一个例子举的不是太好。Emacs 不是有滚半屏的按键绑定么?

这段代码可能会惯坏那些使用习惯不好的用户 :joy:

谢谢,我也已经申请加入 Melpa 了

确实不是好操作,但我没想到好的例子,用 C-n 是因为大家都很熟悉。我觉得重复 C-M-f (paredit-forward) 或 C-M-f (forward-sexp) 更有用,对于常编辑 Lisp 代码的用户。