はじめに
僕はVimのタブ機能をそこそこ活用する方である. だが,「このバッファは既に開いている」ということを忘れることが多々あり,複数のタブで同じバッファを開くことがある.
Vim8.0になり, win_gotoid()
というVim scriptの関数が追加された.
これは,指定したIDのウィンドウにフォーマスを当てるという関数であり,まさに「Vimで既に対象バッファを開いているウィンドウがあるとき,そのウィンドウに移動する」という機能に持ってこいである.
そこで,そういった機能を実現するコマンドを考えてみた.
実装
何はともあれ,実装は以下のようになる.
win_gotoid()
はVim8.0からの機能であるため,Vim7.3, Vim7.4向けの実装も用意しておく.
if exists('*win_gotoid') function! s:buf_open_existing(qmods, bname) abort " {{{ let bnr = bufnr(a:bname) if bnr == -1 echoerr 'Buffer not found:' a:bname return endif let wids = win_findbuf(bnr) if empty(wids) execute a:qmods 'new' execute 'buffer' bnr else call win_gotoid(wids[0]) endif endfunction " }}} command! -bar -nargs=1 -complete=buffer Buffer call s:buf_open_existing(<q-mods>, <f-args>) else function! s:buf_open_existing(bname) abort " {{{ let bnr = bufnr(a:bname) if bnr == -1 echoerr 'Buffer not found:' a:bname return endif let tindice = map(filter(map(range(1, tabpagenr('$')), '{"tindex": v:val, "blist": tabpagebuflist(v:val)}'), 'index(v:val.blist, bnr) != -1'), 'v:val.tindex') if empty(tindice) new execute 'buffer' bnr else execute 'tabnext' tindice[0] execute bufwinnr(bnr) 'wincmd w' endif endfunction " }}} command! -bar -nargs=1 -complete=buffer Buffer call s:buf_open_existing(<f-args>) endif
コマンドとしては,以下のように使用する.
<バッファ名>
はTabキーで補完可能である.
:Buffer <バッファ名>
バッファが :hide
等で隠れている場合は,新たにウィンドウを作成して,開き直す.
Vim8.0からは,Exコマンド定義において <mod>
が利用できるようになったため, :topleft
や :botright
と併用することも可能になっている.
ターミナルへの応用
Vim8.0からは :terminal
が実装された.
この :terminal
についても,複数タブを開いている場合,必要ないのに新たにターミナルを立ち上げてしまうかもしれない.
そこで,前述と同様,ターミナルが既に起動していれば,そこにフォーカスを当てるコマンドを考えた.
実は,バンビちゃん氏のVim で :terminal の使い勝手をよくしたという記事に影響を受けている.
if has('terminal') function! s:complete_term_bufname(arglead, cmdline, cursorpos) abort " {{{ let arglead = tolower(a:arglead) return filter(map(term_list(), 'bufname(v:val)'), '!stridx(tolower(v:val), arglead)') endfunction " }}} function! s:term_open_existing(qmods, ...) abort " {{{ if a:0 == 0 let bnrs = term_list() if empty(bnrs) execute a:qmods 'terminal' else let wids = win_findbuf(bnrs[0]) if empty(wids) terminal else call win_gotoid(wids[0]) endif endif else let bnr = bufnr(a:1) if bnr == -1 throw 'E94: No matching buffer for ' . a:1 elseif index(term_list(), bnr) == -1 throw a:1 . ' is not a terminal buffer' endif let wids = win_findbuf(bnr) if empty(wids) execute a:qmods term_getsize(bnr)[0] 'new' execute 'buffer' bnr else call win_gotoid(wids[0]) endif endif endfunction " }}} command! -bar -nargs=? -complete=customlist,s:complete_term_bufname Terminal call s:term_open_existing(<q-mods>, <f-args>) endif
このコマンドはターミナルバッファ名を引数に取り,ターミナルであるバッファのみをTab補完候補に出す.
:Terminal <ターミナルバッファ名>
まとめ
「既に開いているバッファがあるなら,そこに移動する」という機能は win_gotoid()
を利用すれば簡単に実装できる.