Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Vimに関する個人的なメモのようなもの

NeoBundleのインサートモード時遅延読み込みの注意点

NeoBundleでインサートモード時に遅延読み込みすると、インサートモード時に
ステータスラインの色を変更するというよくある設定が うまくいかないということを
Twitterで呟いたところ、暗黒美夢王さんから返答がきたので、そのことについて
書いてみようかと。

挿入モードでステータスラインの色を変更する

まず、当初、私が.vimrcに書いていたのは、以下のような設定である。
例として、neocompleteをインサートモード時に遅延読み込みするようにしてある。

let $DOTVIM = $HOME . '/.vim'
if has('vim_starting')
  set runtimepath+=$DOTVIM/bundle/neobundle.vim
endif
call neobundle#rc(expand('$DOTVIM/bundle/'))
NeoBundle 'Shougo/neobundle.vim'
NeoBundleLazy 'Shougo/neocomplete.vim',
      \  {'autoload' : {'insert' : 1}
      \}


" ====================================================================
" インサートモードでステータスバーの色を変更する
" NeoBundleでインサートモード時に読み込むプラグインが1つでもあると、
" うまく動作しなくなる。
" ====================================================================
set laststatus=2
set statusline=%<%f\ %m\ %r%h%w%{'[fenc='.(&fenc!=#''?&fenc:&enc).']\ [ff='.&ff.']\ [ft='.(&ft==#''?'null':&ft).']\ [ascii=0x'}%B]%=\ (%v,%l)/%L%8P

let g:hi_insert = 'highlight StatusLine guifg=darkblue guibg=darkyellow gui=none ctermfg=blue ctermbg=yellow cterm=none'

if has('syntax')
  augroup InsertHook
    autocmd!
    autocmd InsertEnter * call s:StatusLine('Enter')
    autocmd InsertLeave * call s:StatusLine('Leave')
  augroup END
endif

let s:slhlcmd = ''
function! s:StatusLine(mode)
  if a:mode ==# 'Enter'
    silent! let s:slhlcmd = 'highlight ' . s:GetHighlight('StatusLine')
    silent exec g:hi_insert
  else
    highlight clear StatusLine
    silent exec s:slhlcmd
  endif
endfunction

function! s:GetHighlight(hi)
  redir => hl
  exec 'highlight ' . a:hi
  redir END
  let hl = substitute(hl, '[\r\n]', '', 'g')
  let hl = substitute(hl, 'xxx', '', '')
  return hl
endfunction

colorscheme default

これは最小構成であるが、うまくいかないということが確認できると思う。
暗黒美夢王さんによると、NeoBundleはインサートモード時に遅延読み込みを行うときに、
InsertEnterのautocmdを発行しているらしい。
つまり、最初にインサートモードに入ったときに、InsertEnterが2回呼ばれているというになり、
上記コードのs:slhlcmdという変数が、ハイライトコマンドをうまく保存できないということになる。

これは、NeoBundleの仕様であり、複数回InsertEnterが発行されても大丈夫なように、
autocmdを書くべきとのこと。

上記のインサートモード時にステータスラインの色を変更するという設定は、InsertEnterの後に
InsertLeaveが発行されると仮定しているから起こる問題なので、それを解消すればよい。
あと、個人的に気に入らないところ(関数や変数のスコープ、命名規則など)があるので、
その部分も修正したコードを、以下に記す。

augroup MyAutoCmd
  autocmd!
augroup END
let $DOTVIM = $HOME . '/.vim'
if has('vim_starting')
  set runtimepath+=$DOTVIM/bundle/neobundle.vim
endif
call neobundle#rc(expand('$DOTVIM/bundle/'))
NeoBundle 'Shougo/neobundle.vim'
NeoBundleLazy 'Shougo/neocomplete.vim',
      \  {'autoload' : {'insert' : 1}
      \}


" Show status line at the second line from the last line.
set laststatus=2
set statusline=%<%f\ %m\ %r%h%w%{'[fenc='.(&fenc!=#''?&fenc:&enc).']\ [ff='.&ff.']\ [ft='.(&ft==#''?'null':&ft).']\ [ascii=0x'}%B]%=\ (%v,%l)/%L%8P

" Change color of status line depending on mode.
if has('syntax')
  augroup MyAutoCmd
    au InsertEnter * call s:statusLine(1)
    au InsertLeave * call s:statusLine(0)
    au ColorScheme * silent! let s:slhlcmd = 'highlight ' . s:getHighlight('StatusLine')
  augroup END
endif

function! s:statusLine(mode)
  if a:mode == 1
    highlight StatusLine guifg=white guibg=MediumOrchid gui=none ctermfg=white ctermbg=DarkRed cterm=none
  else
    highlight clear StatusLine
    silent exec s:slhlcmd
  endif
endfunction

function! s:getHighlight(hi)
  let l:hl = ''
  redir => l:hl
  exec 'highlight ' . a:hi
  redir END
  let l:hl = substitute(l:hl, '[\r\n]', '', 'g')
  let l:hl = substitute(l:hl, 'xxx', '', '')
  return l:hl
endfunction

colorscheme default

ステータスラインの色は、カラースキームの変更時に取得するようにしておけば、
ステータスラインの色を変更するだけの処理をしない限りは問題ないだろう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.