Vim (CUI) にASCIIベースのスクロールバーを追加する


概要

  • 長いファイルを編集していると迷子になりやすいので、現在どの辺を編集しているのか一目で分かるようにした。
    • 折畳みで多少は改善するのだが。
  • やったことは基本的に https://superuser.com/a/445233 の改変と解説。
  • 表示範囲を - で、カーソル位置を @ で表示する。

解説不要。使えればいい!

これを vimrc に貼り付けます。以上。

func! STL()
  let barWidth = &columns / 6
  let barWidth = barWidth < 3 ? 3 : barWidth
  let n = line('$') > 1 ? line('$') - 1 : line('$')
  let buf_top    = (line('w0') - 1) * (barWidth - 1) / n
  let buf_bottom = (line('w$')    ) * (barWidth - 1) / n
  let cursor     = (line('.')  - 1) * (barWidth - 1) / n
  let n1 = buf_top
  let n2 = cursor - n1
  let n2 = n1 + n2 >= barWidth ? barWidth - n1 - 1 : n2
  let n3 = buf_bottom - cursor
  let n3 = n1 + n2 + n3 >= barWidth ? barWidth - n1 - n2 - 1 : n3
  let n4 = barWidth - n1 - n2 - n3 - 1
  let bar = '['.repeat(' ', n1).repeat('-', n2).'@'.repeat('-', n3).repeat(' ', n4).']'
  let stl_left = ' '
  let stl_right = ' %<%F %m%r%h%w%=[%{&fenc},%{&ff},%Y] (%03l/%03L,%03v) '
  return stl_left.bar.stl_right
endfunc
set laststatus=2
set statusline=%!STL()

解説

スクロールバーの長さを決める

  let barWidth = &columns / 6
  let barWidth = barWidth < 3 ? 3 : barWidth

私は1行の1/6にした。お好みで。2行目は例外処理。

バッファ(画面に表示されている範囲)とカーソル位置を取得

  let n = line('$') > 1 ? line('$') - 1 : line('$')
  let buf_top    = (line('w0') - 1) * (barWidth - 1) / n
  let buf_bottom = (line('w$')    ) * (barWidth - 1) / n
  let cursor     = (line('.')  - 1) * (barWidth - 1) / n

4行目を例に取ると、カーソル行を line('.') で取得してスクロールバーの長さ barWidth を掛けて、ファイル行数 line('$') のようなもので割っている。

スクロールバー各部分の長さを決める

  let n1 = buf_top
  let n2 = cursor - n1
  let n2 = n1 + n2 >= barWidth ? barWidth - n1 - 1 : n2
  let n3 = buf_bottom - cursor
  let n3 = n1 + n2 + n3 >= barWidth ? barWidth - n1 - n2 - 1 : n3
  let n4 = barWidth - n1 - n2 - n3 - 1

n1, n2, n3, n4 はそれぞれ以下の部分。三項演算子を使っているのは和が barWidth を超えないための例外処理。

スクロールバーを作る

  let bar = '['.repeat(' ', n1).repeat('-', n2).'@'.repeat('-', n3).repeat(' ', n4).']'

各部分を repeat 関数で作って . で文字列連結。

残り処理

  let stl_left = ' '
  let stl_right = ' %<%F %m%r%h%w%=[%{&fenc},%{&ff},%Y] (%03l/%03L,%03v) '
  return stl_left.bar.stl_right
(中略)
set laststatus=2
set statusline=%!STL()

statusline に代入したいもののうち、stl_leftstl_right はスクロールバーの左右に置きたい要素をお好みで。.で文字列連結。

set laststatus=2statusline を独立行に表示する。set statusline=%!STL() で上記関数の戻り値を statusline にリアルタイム表示すれば完了!