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