vimのscrolloffをwindowの高さに合わせて割合設定する


vimrcにscrolloffという設定があるのを知りました。
いろんなパソコンでvimを利用していると固定値で設定するより割合で設定した方が便利なことが多いですよね。
初めて設定値を動的に入れられるようにしてみたので、記録してみます。

目次

  • 最終的な設定
  • 動き.gif
  • 簡易解説
  • 後書き

最終的な設定

早速ですが、最終的に作成した設定になります。

" windowの20%をscrolloffに設定
autocmd BufRead,BufNewFile,WinEnter * execute "setlocal scrolloff=" . str2nr(string(floor((line('w$') - line('w0')) * 0.20)))

20%に設定しているのは 0.20 の部分です。
お好みに合わせて数値を変えてください。

動き.gif

この記事をピンポイントで探している方は動きを理解しているとは思いますが、せっかくなのでscrolloff設定の有無を動きで見てみます!

scrolloffがない場合

通常通り、カーソルがファイルの最下部を超えると画面がスクロールします。

scrolloffがある場合

この場合scrolloffで設定した位置をカーソルが超えるとスクロールします。
コードを読むときなどに、こちらの方が個人的には使いやすいです。

簡易解説

今回はautocmdで特定タイミングで自動でコマンドを実行するようにして設定をしました。
autocmdは以下のような構文です。

autocmd <イベント> <ファイルパターン> <実行コマンド>

イベント: BufRead,BufNewFile

ここでコマンドを実行するタイミングを指定しています。
これはそれぞれ以下のようなタイミングで実行されます。

BufNewFile: 存在しないファイルの編集を始めたとき。新しいファイルを作成したときなど
BufRead: 新しいバッファの編集を始めたとき。
WinEnter: 既に開いているウィンドウにカーソルが入ったとき。

参照: イベント一覧

WinEnterは頻繁に発生するイベントなので重い処理は入れない方が良いと思います。
今回は以下のようなケースに対応するために追加しました。

  1. ウィンドウ幅を超えたファイルを開く
  2. ウィンドウ幅以下の行数のファイルを開く
  3. scrolloffが小さく設定されてしまう。

画面上に写っている行の開始と終了から計算しているため、ウィンドウの行数以下のファイルを開くとscrolloffが変わってしまうんですよね...
そこへ対処するためのWinEnterです。
もっと良いやり方があれば教えてください!

ファイルパターン: *

これはそのままですね。全てのファイルを対象にしています。

実行コマンド: execute "setlocal scrolloff=" . str2nr(string(floor((line('w$') - line('w0')) * 0.20)))

ここは最初以下のようにしていたのですが、うまく動作しませんでした。
setlocal scrolloff=str2nr(string(floor((line('w$') - line('w0')) * 0.20)))

どうも=の右側が全て文字列として渡っていたようで、処理が実行できていませんでした。
そのため今回は execute コマンドを利用することで処理を実行できるようにしています。

line() 部分は行数の取得です。
w0でカレントウィンドウの最上行、w$でカレントウィンドウの最下行を取得して計算しています。
割合を掛けたあとは floor で端数を切り捨てています。

scrolloffにはintしか値が渡せないようだったので、その後にstr2nr(string()) で float型になっている値を無理やりintに変換しています。
もっとシンプルなキャスト方法ないのでしょうか??

試行錯誤しましたが、こんな感じで機能を実現できました!!

後書き

vimは自分でカスタマイズしていけるのが楽しいですね。
今回たまたまscrolloff設定などを見つけたので、定期的に設定一覧を眺めてみるとどんどん便利な機能が発見できそうな気がしました。