問題
Vim には 'cursorline' というオプションがある。これを有効にすると、現在カーソルがある行がハイライト表示される。カーソルの位置を見失いにくくなるので便利なオプションだ。
しかし、デメリットがないわけではない。
- 微妙に重い。
- 背景色や一部の色が上書きされるので、カーソルのある行の背景色が見えなくなる。例えば、コメント内の TODO や 'list' で表示される文字など。
そもそも 'cursorline' は常に必要だろうか。編集中にカーソルを見失うことはそうそうないはず。見失うのはちょっと席を外したり別の作業に移って、戻ってきた時だ。必要な時だけ有効にすることはできないだろうか。
解決方法
以下のような設定を行うと、しばらく手を離した時だけ 'cursorline' が有効になる。
augroup vimrc-auto-cursorline autocmd! autocmd CursorMoved,CursorMovedI,WinLeave * setlocal nocursorline autocmd CursorHold,CursorHoldI * setlocal cursorline augroup END
解説
しばらく操作をしないでいると CursorHold が発動して 'cursorline' が有効になる。作業を再開してカーソルを動かすと CursorMoved などが発動して 'cursorline' が無効になる。
好みにより 'cursorcolumn' を設定してもいい。
CursorHold イベントは 'updatetime' オプションで発生するまでの時間を調節できる。ただし、'updatetime' は本来スワップファイルが更新されるまでの時間なので、設定する際は注意。
発展
ここまで来るとウィンドウ間を移動した直後もハイライトして欲しい。ウィンドウの移動直後もカーソルを見失いがちだからだ。
単に有効にする条件に WinEnter を入れればよさそうだが、これではうまくいかない。
augroup vimrc-auto-cursorline autocmd! autocmd CursorMoved,CursorMovedI,WinLeave * setlocal nocursorline " ↓思惑通りに動かない! autocmd CursorHold,CursorHoldI,WinEnter * setlocal cursorline augroup END
どうも、ウィンドウに入った直後に CursorMoved イベントが発生しているらしい。しかし、移動したウィンドウ間でのカーソルの位置(行、桁)が同じだった場合には発生しない。Vim のバグのような気がするが、とにかくこのままでは動かない。
この問題を回避するには、少々強引な方法だが、移動直後の 1 回だけ CursorMoved を無視するようにしてしまえば良い。
augroup vimrc-auto-cursorline autocmd! autocmd CursorMoved,CursorMovedI * call s:auto_cursorline('CursorMoved') autocmd CursorHold,CursorHoldI * call s:auto_cursorline('CursorHold') autocmd WinEnter * call s:auto_cursorline('WinEnter') autocmd WinLeave * call s:auto_cursorline('WinLeave') let s:cursorline_lock = 0 function! s:auto_cursorline(event) if a:event ==# 'WinEnter' setlocal cursorline let s:cursorline_lock = 2 elseif a:event ==# 'WinLeave' setlocal nocursorline elseif a:event ==# 'CursorMoved' if s:cursorline_lock if 1 < s:cursorline_lock let s:cursorline_lock = 1 else setlocal nocursorline let s:cursorline_lock = 0 endif endif elseif a:event ==# 'CursorHold' setlocal cursorline let s:cursorline_lock = 1 endif endfunction augroup END
この方法であるとまったく同じ場所同士で移動した場合、最初の 1 回の移動は 'cursorline' が有効になったままになるが、元々レアケースであるし特に問題はない。
また、ついでに変数の値を調節することで :set を呼ぶ回数を減らしてある。これで多少早くなるはずだ。