グローバル変数の汚染に注意

Vim プラグインを書く際、使用する変数は可能な限りスクリプトローカルを使い、グローバル変数プラグインの設定のみに使用するのが望ましい。スコープをなるべく小さくするした方が良いと言うのはVimスクリプトに限った話ではないだろう。
が、Vimスクリプトのカオスな仕様の宿命なのか、守られていないプラグインもちらほら。
そんなに経質になることもないんだろうけど、残念ながら私は経質だったので、今回は私が普段使用している環境の中で見つけた明らかにミスったと思われるグローバル変数を晒してみることにする。

グローバル変数一覧の見方

その前に一応グローバル変数の一覧の出し方から。

:echo join(sort(keys(g:)), "\n")

これで見れる。恐らく大量にあるので、空のバッファで

:put =join(sort(keys(g:)), \"\n\")

とでもやればゆっくり見られるよ。

どこで設定されているかは、オプションのよう*1には見れないので、grepで探した。頑張った。

save_cpo

  • color/candycode.vim

これは明らかにアレをやろうとした跡。痛々しい。

cpo_save

  • $VIMRUNTIME/ftplugin/hamster.vim
  • $VIMRUNTIME/ftplugin/vim.vim
  • $VIMRUNTIME/plugin/matchparen.vim

これもアレ。もしかしたら古いVimの名残り?とも思ったけど、最終更新が2008とかになってるし。

m

以下の部分。

augroup FuzzyfinderGlobal
  autocmd!
  autocmd BufEnter     * for m in s:GetAvailableModes() | call m.extend_options() | call m.on_buf_enter() | endfor
  autocmd BufWritePost * for m in s:GetAvailableModes() | call m.extend_options() | call m.on_buf_write_post() | endfor
augroup END

for の変数は意外とやりがち。トップレベルに書くとちゃっかりグローバル変数が使われる。この場合s:mを使っておけば問題なし。
これの下に定義してある :FuzzyFinderRemoveCache のforも同様。

user_options

これにだけ g: が付いていないところを見ると、スクリプトローカルのつもりで書いたっぽい。
確か、昔の fuzzyfinder.vim は初期化を専用関数内でやっていたので、その頃の名残りが出てしまったと思われる。

st et cd

  • after/ftplugin/*_snippets.vim

3つともsnippetsEmu.vim が各ファイルタイプに対するデフォルトの設定を行うために配置するファイル内で使用されている。
ちなみに元々ある g:snip_start_tag g:snip_end_tag g:snip_elem_delim の短縮形として使われている模様。
気持ちはわかるが s: を使ってくれ。

def_file

これも先ほどの fuzzyfinder.vim と同様 for のミス。

思うに

Vim スクリプト内では明示的にg:を付けない限りスクリプトローカル(s:)になるような仕様だったらこんなことにはならなかったのではないだろうか。ああ、後方互換性ですね、わかります。

*1::verbose set option?