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スクリプトローカライズメッセージとかどうすればいいんだ。
どうしようもないのか?基本はメッセージ英語で作るのか?


この点はそのうち調査。