読者です 読者をやめる 読者になる 読者になる

pockestrap

Web Programmer's memo

ruby_hl_lvar.vim をShougo ware と仲良くつかう

ruby_hl_lvar.vim とは

todesking/ruby_hl_lvar.vim · GitHub

ruby のローカル変数をハイライトするプラグインです。 たいぽの発見に割と便利だと思います。

詳しくは、

Rubyのローカル変数をシンタクスハイライトするVimプラグインを書いた - TODESKING

を読むと良いと思います。

Shougo ware とは

Shougo ware とは、その名の通り暗黒美夢王ことShougo氏が作成したVimプラグイン郡です。 代表的なものは、以下のようなものがあります。

今回は、この中のNeoBundleとNeoSnippetについて取り上げます。

NeoBundle

NeoBundleとは、vimプラグイン管理プラグインです。 また、その中にはプラグインの遅延読み込みを実現するNeoBundleLazyというコマンドがあります。

NeoBundleLazy に関しては、こちらが詳しいでしょう。

neobundle.vim の遅延処理で Vim の起動を高速化する - C++でゲームプログラミング

さて、ruby_hl_lvar.vimRubyの時にだけ使用したいプラグインですね。 NeoBundle にはそのようなプラグインのために、「特定のFileTypeの時にプラグインを読み込む」機能があります。

NeoBundleLazy 'todesking/ruby_hl_lvar.vim', {
\   'autoload': {
\     'filetypes': ['ruby']
\   }   
\ }

このように書いてやると、Rubyの時にだけプラグインが読み込まれます。

しかし、ruby_hl_lvar の場合これだけだと若干問題が発生します。 最初に開いたバッファにおいて、ruby_hl_lvar が有効になりません。

なぜかと言うと、NeoBundleLazyでFileTypeを指定した場合はautocmdFileTypeイベントが呼ばれないからのようです。 FileTypeイベントは ここで呼ばれています。

augroup ruby_hl_lvar
  autocmd!
  autocmd! Filetype * call Ruby_hl_lvar_filetype()
augroup END

ここで呼んでいる関数Ruby_hl_lvar_filetype()で初期化がされています。 そのため、FileTypeイベントが発生しないと ruby_hl_lvar が有効になりません。

それには、NeoBundle の on_post_source hook を利用します。

let s:bundle = neobundle#get('ruby_hl_lvar.vim')
function! s:bundle.hooks.on_post_source(bundle)
  silent! execute 'doautocmd FileType' &filetype
endfunction
unlet s:bundle

vimrcに上の様に記述します。そうすると、 ruby_hl_lvar が読み込まれた後に、FileType イベントが発生し正常に動作する様になります。

NeoSnippet

NeoSnippet とは、コードスニペットを展開するプラグインです。めっちゃべんり

しかし、NeoSnippetとruby_hl_lvarを併用すると、NeoSnippetが正常に動作しません。

vim には、 exprマップの中でnormalコマンドを使用できないという仕様があります。 そして、NeoSnippetがSnippetを展開する時がexprマップであり、それに反応して ruby_hl_lvar が作動し、その中でnormalコマンドが使用されているためNeoSnippetが正常に動作しなくなっています。

これを改善するには、normalコマンドを呼ばないようにしなければなりません。 スニペット展開の時に呼ばれるイベントがTextChangedなので、そのイベントをそのまま無効にすればよいです。その代わり、xなどでバッファを操作した時に変更が反映されなくなりますが…

先ほどのhookにコードを継ぎ足しましょう。

let s:bundle = neobundle#get('ruby_hl_lvar.vim')
function! s:bundle.hooks.on_post_source(bundle)
  function! Ruby_hl_lvar_filetype()
    let groupname = 'vim_hl_lvar_'.bufnr('%')
    execute 'augroup '.groupname
      autocmd!
      if &filetype ==# 'ruby'
        if g:ruby_hl_lvar_auto_enable
          call ruby_hl_lvar#refresh(1)
          "autocmd TextChanged <buffer> call ruby_hl_lvar#refresh(0)
          autocmd InsertEnter <buffer> call ruby_hl_lvar#disable(0)
          autocmd InsertLeave <buffer> call ruby_hl_lvar#refresh(0)
        else
          call ruby_hl_lvar#disable(1)
        endif
      endif
    augroup END
  endfunction

  silent! execute 'doautocmd FileType' &filetype
endfunction
unlet s:bundle

このようにして、Ruby_hl_lvar_filetype()を上書きします。 そして、TextChangedイベントへの hook をなくします。 そうすることで、NeoSnippetが正常に動作するようになります。