generated at
again.el
Emacs上の操作を再実行するシステム by 増井俊之
again.el
;; ;; again.el - Emacs上の操作を再実行するシステム ;; Dynamic Macro (ndmacro.el) と併用して使う ;; ;; 増井俊之 ;; masui@pitecan.com ;; 2022/7/14 ;; https://github.com/masui/Again ;; ;; ;; ~/.emacsで以下を設定 ;; (require 'again) ;; (require 'ndmacro) ;; これも必要 ;; (defconst *again-key* "\C-t" "再実行キー") ;; (global-set-key *again-key* 'exec-again) ;; (provide 'again) (defvar *again-macro* [] "繰り返し文字列") (defvar *old-history* [] "ちょっと前のrecent-keys") (defvar *recent-history* [] "最新のrecent-keys") (defvar *dmacro-is-running* nil "dmacro実行中") (defun clear-kbd-macro () (setq *again-macro* []) (setq *old-history* (recent-keys)) ) ;; ;; 再実行シーケンスをリセットするための待ち時間 ;; (run-with-idle-timer 2 t 'clear-kbd-macro) ;; ;; Ctrl-Lを入力するとagain動作をリセットするようにする ;; (Ctr-Lを入力してから*again-key*を入力するまでの操作が繰り返し実行の対象になる) ;; (defun again-reset () (interactive) (recenter-top-bottom) (clear-kbd-macro) ) (global-set-key "\C-l" 'again-reset) ;; ;; "xyzabcdefg" と "abcdefghij" から "hij" を得る ;; (defun get-postfix (s1 s2) (let ( (len1 (length s1)) (len2 (length s2)) (found nil) (i 0) (res []) ) (while (and (< i len2) (not found)) (let* ((s (substring s2 0 (- len2 i))) (p (substring s1 (- (min len1 (length s)))))) (setq found (equal s p)) (if found (setq res (substring s2 (- i)))) ) (incf i) ) res ) ) (defun chomp (s) ; 文字列の最後の文字を除く (let ((len (length s))) (if (= len 0) [] (substring s 0 (1- len))) ) ) ;; ;; exec-again の動作 ;; * は時間待ち ;; ;; キー操作 123456789* 時間待ちしたところ ;; *old-history* 123456789 時間待ちで設定 ;; *recent-history* ;; *again-macro* ;; ;; キー操作 123456789*abcL ;; *old-history* 123456789 時間待ちで設定されたまま ;; *recent-history* 6789 abcL Lで設定 ;; *again-macro* abc 引算計算 + 実行 ;; ;; キー操作 123456789*abcLL ;; *old-history* 123456789 ;; *recent-history* 789 abcLL ;; *again-macro* abc LLなので*again-macro*を実行 ;; ;; キー操作 123456789*abcLLL ;; *old-history* 123456789 ;; *recent-history* 89 abcLLL ;; *again-macro* abc LLなので*again-macro*を実行 ;; ;; キー操作 123456789*abcLLLd ;; *old-history* 123456789 ;; *recent-history* 89 abcLLL 変化せず ;; *again-macro* abc 実行せず / 実行しない ;; ;; キー操作 123456789*abcLLLde ;; *old-history* 123456789 変化せず ;; *recent-history* 89 abcLLL 変化せず ;; *again-macro* abc 変化せず / 実行しない ;; ;; キー操作 123456789*abcLLLdeL ;; *old-history* 89 abcLLL 前の*recent-history*をコピー ;; *recent-history* abcLLLdeL ;; *again-macro* de 引算+実行 (defun exec-again () ;;; *again-key* で呼ばれる (interactive) (let* ((recent (recent-keys)) (len (length recent)) (again-key-repeated ;; *again-key* が連打されたかどうか (and (= (aref recent (- len 1)) (aref *again-key* 0)) (= (aref recent (- len 2)) (aref *again-key* 0)))) ) ;; ;; 繰り返しがあるか、dmacro実行中に連打なら (ndmacro) を呼ぶ ;; (if (or (and *dmacro-is-running* again-key-repeated) (and (> (key-repeated?) 1) (not again-key-repeated))) (progn (ndmacro) ;; dmacro実行 (setq *dmacro-is-running* t) ) (setq *dmacro-is-running* nil) (if (not again-key-repeated) (progn (if (not (equal *again-macro* [])) ; 新規作成じゃない場合 (setq *old-history* *recent-history*) ) (setq *again-macro* (chomp (get-postfix *old-history* recent))) (setq last-kbd-macro *again-macro*) ;; Ctrl-E で呼ばれるもの ) ) (setq *recent-history* recent) (execute-kbd-macro *again-macro*) ) ) ) (defun key-repeated? () ;; *again-key* が押される前にキー操作の繰り返しがあるか (let* ((a (recent-keys)) (b (copy-sequence a)) (i 0) ) (while (< i (1- (length a))) (aset b (1+ i) (aref a i)) (incf i) ) (array-end-repeated? b) ) ) (defun array-end-repeated? (array) ;; 配列の末尾に繰り返しがあるか (let ( (a (reverse array)) (alen (length array)) (i 1) (replen 0) ) (let ((i 0)) (while (< i (length a)) (if (and (>= (aref a i) 48) (<= (aref a i) 57)) ;; 数字はみな同じと扱う (ndmacroの連番機能のため) (aset a i 48) ) (incf i) ) ) (while (<= (* 2 i) alen) (let ((matched t) (j 0) ) (while (and matched (< j i)) (if (not (= (aref a j) (aref a (+ i j)))) (setq matched nil)) (incf j) ) (if matched (setq replen i)) ) (incf i) ) replen ) )