dmacro.elのvimスクリプトでの再現に挑戦
前日からの続きでやってみた。
;; 例えばユーザが
;; abcabc
;; と入力した後「繰返しキー」を押すと、dmacro.el は "abc" の入力操作の
;; 繰返しを検出してそれを実行し、その結果テキストは
;; abcabcabc
;; となります。また、
;; abcdefab
;; と入力した後「繰返しキー」を押すと、dmacro.el はこれを "abcdef" の
;; 入力の繰返しと判断し、繰返しの残りの部分を予測実行して "cdef" を入力し、
;; テキストは
;; abcdefabcdef
;; となります。ここでもう一度「繰返しキー」を押すと、"abcdef" の入力
;; が繰り返されて、テキストは
;; abcdefabcdefabcdef
;; となります。
dmacro.el - キー操作の繰返し検出 & 実行
http://pitecan.com/papers/JSSSTDmacro/dmacro.el
いろいろ試したらdmacro.elの↑の説明の機能は、↓のようなスクリプトを組んだらできるようになった。
下のソースをdmacro.vimという名前で保存、vimエディタのpluginディレクトリに入れておくと、
入力中にCtrl-Bで繰り返しを検出、補完できる。
" vim:set et ff=unix fenc=cp932 : scriptencoding cp932 " [CASE A] " 例えばユーザが " abcabc " と入力した後「繰返しキー」を押すと、dmacro.el は "abc" の入力操作の " 繰返しを検出してそれを実行し、その結果テキストは " abcabcabc " となります。 " " [CASE B] " また、 " abcdefab " と入力した後「繰返しキー」を押すと、dmacro.el はこれを "abcdef" の " 入力の繰返しと判断し、繰返しの残りの部分を予測実行して "cdef" を入力し、 " テキストは " abcdefabcdef " となります。 " " [CASE C] " ここでもう一度「繰返しキー」を押すと、"abcdef" の入力 " が繰り返されて、テキストは " abcdefabcdefabcdef " となります。 if exists("g:loaded_dmacro") finish endif let g:loaded_dmacro = 1 let s:save_cpo = &cpo set cpo&vim " 入力中に<Ctrl-B>で機能を呼び出します。 imap <C-B> <C-O>:call Dmacro()<CR> let g:dmacro_register = "" function! Dmacro() " 入力が無い場合は前回の入力を使用する。 " これはimapで一時的に入力を抜けてしまうので、 " @.レジスタがクリアされてしまうためだ。 " echo "@. [". @. ."], dr [". g:dmacro_register ."]" " sleep 2 if @. != "" let g:dmacro_register = @. endif " [CASE A] " [CASE C] " 正規表現による繰り返しの単純検出。 let l:matched = match(g:dmacro_register, '\(..*\)\(\1\)$') if l:matched > -1 let l:token = substitute(g:dmacro_register, '.*\(..*\)\(\1\)$', '\1', "") let g:dmacro_register = g:dmacro_register . l:token silent execute ":normal a" . l:token " @.レジスタをクリア。 " 入力が残ったり残らなかったりするため、挙動を統一させる。 " @.は読み取り専用なので、データを残す方での統一は無理。 silent execute ":normal a" return endif " [CASE B] " 並びをひっくり返した後、正規表現で不完全な繰り返しを検出する。 " reverseするのは、より長い文字列を最後の入力とマッチさせるため。 let l:reversed = join(reverse(split(g:dmacro_register, '\zs')), "") let l:matched = match(l:reversed, '^\(..*\)\(.\{-\}\)\1') if l:matched > -1 let l:token = substitute(l:reversed, '^\(..*\)\(.\{-\}\)\1.*', '\2', "") let l:token = join(reverse(split(l:token, '\zs')), "") let g:dmacro_register = g:dmacro_register . l:token silent execute ":normal a" . l:token " @.レジスタをクリア。 silent execute ":normal a" return endif :echohl WarningMsg | echo "操作の繰返しが見つかりません" | echohl None endfunction let &cpo = s:save_cpo finish
しかし、dmacro.elの繰り返し機能はもうちょっとすごくて、
検索操作とかも含めた繰り返しの検出までできるらしい。
;; ・文字列置換
;;
;; テキスト中の全ての「abc」を「def]に修正する場合を考えてみます。
;; 「abc」を検索するキー操作は "Ctrl-S a b c ESC" で、これは
;; "DEL DEL DEL d e f" で「def」に修正することができます。
;; 引き続き次の「abc」を検索する "Ctrl-S a b c ESC" を入力した後で
;; 「繰返しキー」を押すと "DEL DEL DEL d e f" が予測実行され、新たに
;; 検索された「abc」が「def」に修正されます。ここでまた「繰返しキー」
;; を押すと次の「abc」が「def」に修正されます。
;; このように「繰返しキー」を押していくことにより順々に文字列を
;; 置換していくことができます。
dmacro.el - キー操作の繰返し検出 & 実行
http://pitecan.com/papers/JSSSTDmacro/dmacro.el
この機能の再現は難しいな。。