問題: 以下のVim scriptを実行すると何が表示されるか。
command! -nargs=+ MyEcho echo <args> let g:var = 'global' function s:f() let l:var = 'local' MyEcho var endfunction call s:f()
答え: "local"
そう。ユーザ定義コマンドは関数内で実行された場合そのローカル変数にアクセスできる。
では、以下の2つのVim scriptがあった場合、b.vim を実行すると何が表示されるか。
" a.vim let s:var = 'A' command! -nargs=+ MyEcho echo <args>
" b.vim source a.vim let s:var = 'B' MyEcho s:var
答え: "A"
スクリプトローカルな変数に関しては、コマンドが定義されたスコープが参照される。
一見不可解な気もするが、通常はこれは便利な挙動だ。
function s:command() echo 'hello' endfunction command! Command call s:command()
これはどのスコープにいても、コマンドラインからでも正常に動作する。
で、大抵の場合は便利なんだけど、場合によっては制約になりうる。具体例としては prettyprint.vim がそうだ。
prettyprint.vim の :PP コマンドは渡された式の内容を表示するが、この制約によってスクリプトローカルな変数や関数を含む式は受け付けない。
これはどうしようもないので、helpに注意書きをすることにした。ここに書いた通り、この場合は代わりに PP() 関数を使えば表示できる。
この一見気持ち悪いスコープの問題は、単にVimがスクリプトローカル変数も実行時のスコープを見るようにしてくれればいいとかそういうことではなくて、てかそれをやられると現状の多くのプラグインが詰むので、まあどうしようもないのかなぁって感じだ。
今回の例だとプラグインの用途自体が限定的だし、PP() と言う逃げ道もあったのでまだいいけど、どうしようもなく困ってしまった例ってのもある。その話はまた今度。