koturnの日記

普通の人です.ブログ上のコードはコピペ自由です.

Vimのタブ番号,ウィンドウ番号,ウィンドウID,バッファ番号の一覧情報を表示する

はじめに

先日の記事Vimで既に対象バッファを開いているウィンドウがあるとき,そのウィンドウに移動するでは,「タブ開きすぎると,どのタブでどのバッファ開いているかわからなくなるから,同じバッファを複数のウィンドウで開いてしまう」というIQ1的な事柄を問題にし,それを解決するコマンドを提示した. しかし,そもそも全てのタブ配下の全てのウィンドウが,どのバッファに関連付けられているかの情報をパパッと見ることができれば,そういう問題も少しは減るはずだ. この記事では,全てのタブが管理している情報を表示するコマンドを提案する.

実装

何はともあれ実装である.このような実装を考えた. tabpagewinnr(タブ番号, '$') で対象タブにおけるウィンドウの個数が得られるので,あとは個数分イテレーションを行い, win_getid(ウィンドウ番号, タブ番号) とすることで,ウィンドウIDが得られる寸法だ. Window IDは一意であるため,そこからバッファ番号を得るとよい. ただし,Window IDからバッファ番号を得る関数は無く,その逆の win_findbuf() という関数があるため,逆引き辞書を作る.

" Window IDからバッファ番号を引く逆引き辞書を作成
function! s:create_winid2bufnr_dict() abort " {{{
  let winid2bufnr_dict = {}
  for bnr in filter(range(1, bufnr('$')), 'v:val')
    for wid in win_findbuf(bnr)
      let winid2bufnr_dict[wid] = bnr
    endfor
  endfor
  return winid2bufnr_dict
endfunction " }}}

function! s:show_tab_info() abort " {{{
  echo "====== Tab Page Info ======"
  let current_tnr = tabpagenr()
  let winid2bufnr_dict = s:create_winid2bufnr_dict()
  for tnr in range(1, tabpagenr('$'))
    let current_winnr = tabpagewinnr(tnr)
    echo (tnr == current_tnr ? '>' : ' ') 'Tab:' tnr
    echo '    Buffer number | Window Number | Window ID | Buffer Name'
    for wininfo in map(map(range(1, tabpagewinnr(tnr, '$')), '{"wnr": v:val, "wid": win_getid(v:val, tnr)}'), 'extend(v:val, {"bnr": winid2bufnr_dict[v:val.wid]})')
      echo '   ' (wininfo.wnr == current_winnr ? '*' : ' ') printf('%11d | %13d | %9d | %s', wininfo.bnr, wininfo.wnr, wininfo.wid, bufname(wininfo.bnr))
    endfor
  endfor
endfunction " }}}
command! -bar TabInfo call s:show_tab_info()

表示イメージとしては以下の通り. カレントタブの左に > を表示し,それぞれのタブにおけるカレントウィンドウの左には * を表示している.

f:id:koturn:20180212141845p:plain

カレントタブに関する情報欄に :echohl で色を付けるなどすると,見やすさが向上するかもしれない.

NG実装

これはNG実装なので,真似してはいけない. 問題点としては,各タブの情報収集において,対象タブへの移動を伴っている点であり,行数の多いバッファと関連付いたウィンドウをカレントウィンドウに持つタブに移動したときに,数秒固まってしまう.

function! s:show_tab_info() abort " {{{
  echo "====== Tab Page Info ======"
  let current_tnr = tabpagenr()
  for tnr in range(1, tabpagenr('$'))
    execute 'tabnext' tnr
    echo (tnr == current_tnr ? '>' : ' ') 'Tab:' tnr
    echo '    Buffer number | Window Number | Window ID | Buffer Name'
    let current_winnr = winnr()
    for wnr in range(1, winnr('$'))
      echo '   ' (wnr == current_winnr ? '*' : ' ') printf('%11d | %13d | %9d | %s', winbufnr(wnr), wnr, win_getid(wnr), bufname(winbufnr(wnr)))
    endfor
  endfor
  execute 'tabnext' current_tnr
endfunction " }}}
command! -bar TabInfo call s:show_tab_info()

まとめ

全てのタブが管理している全てのウィンドウの番号とID,およびそれらのウィンドウに関連付けられているバッファの番号とバッファ名を表示するコマンドを提案した. それらの情報を見ることができれば,無駄に同じバッファを複数のウィンドウ(特に異なるタブ間において)開き直すことは無くなるだろう.