dmacro.elをvimスクリプトで再現する
dmacro.el
http://pitecan.com/papers/JSSSTDmacro/dmacro.el
ギブアップ。
できたのは、ここまで。
" 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 IMDmacro()<CR> let b:imdmacro_register = "" function! IMDmacro() " 入力が無い場合は前回の入力を使用する。 " これはimapで一時的に入力を抜けてしまうので、 " @.レジスタがクリアされてしまうためだ。 if @. != "" let b:imdmacro_register = @. endif " [CASE A] " [CASE C] " 正規表現による繰り返しの単純検出。 let l:matched = match(b:imdmacro_register, '\(..*\)\(\1\)$') if l:matched > -1 let l:token = substitute(b:imdmacro_register, '.*\(..*\)\(\1\)$', '\1', "") let b:imdmacro_register = b:imdmacro_register . l:token silent execute ":normal a" . l:token " @.レジスタをクリア。 " 入力が残ったり残らなかったりするため、挙動を統一させる。 " @.は読み取り専用なので、データを残す方での統一は無理。 silent execute ":normal a" return endif " [CASE D] " 直前に繰り返しがあり、その一部である場合はそれの補足を優先する。 " しかし、この定義は大抵、[CASE A]で拾われてしまう。 let l:matched = match(b:imdmacro_register, '\(\(..*\).*\)\1\2$') if l:matched > -1 let l:token = substitute(b:imdmacro_register, '.*\(\(..*\)\(.*\)\)\1\2$', '\3', "") let b:imdmacro_register = b:imdmacro_register . l:token silent execute ":normal a" . l:token " @.レジスタをクリア。 silent execute ":normal a" return endif " [CASE B] " 並びをひっくり返した後、正規表現で不完全な繰り返しを検出する。 " reverseするのは、より長い文字列を最後の入力とマッチさせるため。 let l:reversed = join(reverse(split(b:imdmacro_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 b:imdmacro_register = b:imdmacro_register . l:token silent execute ":normal a" . l:token " @.レジスタをクリア。 silent execute ":normal a" return endif echohl WarningMsg | echo "Repeated Input is not found." | echohl None endfunction " バッファを切り替えた時は入力が途切れたと判断し、入力情報をクリアする。 augroup IMDMacro autocmd! autocmd BufNewFile,BufRead **/* let b:imdmacro_register = "" augroup END let &cpo = s:save_cpo finish
結局、入力モードでの繰り返し検出が精一杯でした。
この程度の機能だったら、.(ピリオド)による繰り返しがあれば十分なんだよなー。
vim -W とかも試したけど、これはちょっと無理無理。
emacs風味ではなく、vim風なやり方も考えてみたけど、いい案は浮かばなかった。
ところで、vimスクリプトのローカライズメッセージとかどうすればいいんだ。
どうしようもないのか?基本はメッセージ英語で作るのか?
この点はそのうち調査。