この記事は Vim Advent Calendar 2011 の 28 日目の代打です。
急遽代打をやることになった*1けどネタが浮かばなかったので、適当に vimrc の中から便利かもしれない関数を晒すことにします。
スクリプトローカルな関数を呼び出したい
Vim script を書いてると、スクリプトローカルな関数をコマンドラインモードから直接呼び出して挙動を確認したくなること、ないですか?
- デバッグで呼び出したい
- 既存プラグインを拡張したくなった
- 中身覗くの大好き
- なんか知らんけど急に呼び出したくなった
まあそれなりにシチュエーションはあるかと思います。あることにします。
Vim script ではがんばればスクリプトローカルな関数を呼び出せますが、正直いちいちがんばりたくないです。
スクリプトローカルな関数を呼び出す関数
私の vimrc から抜粋した以下の関数を vimrc に書いておきます。
" Call a script local function. " Usage: " - S('local_func') " -> call s:local_func() in current file. " - S('plugin/hoge.vim:local_func', 'string', 10) " -> call s:local_func('string', 10) in *plugin/hoge.vim. " - S('plugin/hoge:local_func("string", 10)') " -> call s:local_func("string", 10) in *plugin/hoge(.vim)?. function! S(f, ...) let [file, func] =a:f =~# ':' ? split(a:f, ':') : [expand('%:p'), a:f] let fname = matchstr(func, '^\w*') " Get sourced scripts. redir =>slist silent scriptnames redir END let filepat = '\V' . substitute(file, '\\', '/', 'g') . '\v%(\.vim)?$' for s in split(slist, "\n") let p = matchlist(s, '^\s*\(\d\+\):\s*\(.*\)$') if empty(p) continue endif let [nr, sfile] = p[1 : 2] let sfile = fnamemodify(sfile, ':p:gs?\\?/?') if sfile =~# filepat && \ exists(printf("*\<SNR>%d_%s", nr, fname)) let cfunc = printf("\<SNR>%d_%s", nr, func) break endif endfor if !exists('nr') echoerr 'Not sourced: ' . file return elseif !exists('cfunc') let file = fnamemodify(file, ':p') echoerr printf( \ 'File found, but function is not defined: %s: %s()', file, fname) return endif return 0 <= match(func, '^\w*\s*(.*)\s*$') \ ? eval(cfunc) : call(cfunc, a:000) endfunction
追記: 一部外部の関数に依存していたのを修正
追記: scriptnames に silent し忘れてたのを修正
使い方
コメントにある通りですが、まず、
call S('local_func')
これで、現在編集しているバッファで定義されている s:local_func() を引数なしで呼び出します。
引数を与えたい場合は素直にこう。
call S('local_func', 1, 2, 3)
こういうことも可能です。
call S('local_func(1, 2, 3)')
ただし、この場合 eval() を使うため変数は渡せないので注意。
特定の名前のスクリプトのローカル関数を呼び出したい場合はこう。
call S('plugin/my_plugin.vim:local_func', 1, 2, 3)
この場合、"plugin/my_plugin.vim" で終わるスクリプトを探して、最初に見付かったもののローカル関数を呼び出します。
最後の .vim は省略可能です。
call S('plugin/my_plugin:local_func', 1, 2, 3)
以上
これでスクリプトローカル関数を呼び出し放題ですね!
私は実際にこれを使って vimrc 内で S('twitvim:post_twitter', message) みたいな感じで使ってます。
明日は @potix2 さんです。
*1:と思ったらすでに kaoriya さんが代打してたけど気にしてはいけない