その他
    ホーム 技術発信 DoRuby Vim のタブをそこそこ活用する

    Vim のタブをそこそこ活用する

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    Vim のタブ機能について書きます。

    空白文字のほうのタブではなくて、インターフェイスのほうのタブです。

    目次

    1. タブは何なのか
    2. タブ基本
    3. タブを少し扱いやすくしてみる
    4. タブの表示を少しわかりやすくしてみる

    1. タブは何なのか

    Vim のタブ

    Vim のタブはタブブラウザのタブと同じようなインターフェイスで、使われかたもだいたい同じです。

    だいたい同じ、というのを補足すると、

    • タブブラウザなどでは一般的に、ひとつのタブにひとつのウェブページが表示される
    • Vim のタブでは、ひとつのタブに複数のウィンドウ(バッファ)が表示され、ウィンドウの配置など画面の表示を管理できる

    というところが少し違います。

    Vim のタブがあると、なにがうれしいのか

    バッファ切り替えだけでも複数ファイルを編集できるし、ウィンドウもひとつの画面で複数開けるし、そこに加えてなんでタブが必要なのか?と思うかもしれませんが、あったらやっぱり便利です。

    考えられるうれしいかもしれないケース:

    • 違うプロジェクトのファイルを同じ画面で開いてると混乱するので、タブで分けて作業すると少しわかりやすくてうれしい
    • Rails でファイルを編集しているとき、モデルベースでタブを開いておき、作業する画面を分けると少しわかりやすくてうれしい
    • diffsplit している画面はのこしておいて、新しいタブで別のファイルを編集すると、diff 画面と行ったり来たりして参照できてうれしい

    などなど、実際のところうれしいかどうかちょっと微妙なところですが、とりあえずうれしいということにしておきます。

    2. タブ基本

    Vim のタブは vim, gvim 問わず使えます。

    ざっくりと、以下のコマンドがタブを扱うコマンドとして用意されています。

    割とよく使う(と思う)コマンド
    コマンドうごき
    :tabe (:tabedit)新しいタブで引数のファイルを開く。引数がなければ新規ファイルを開く
    :tabn (:tabnext)右隣のタブに移る。引数(数値)があれば、その番号のタブを開く(:tabn 1 とか)
    :tabN (:tabNext), :tabp (:tabprevious)左隣のタブに移る。引数があればその数値分先の左のタブに移動
    :tabr (:tabrewind), :tabfirst左端のタブに移る
    :tabl (:tablast)右端のタブに移る
    :tabc (:tabclose)今いるタブを閉じる
    :tabo (:tabonly)今いるタブ以外を閉じる
    :tabs開いているタブとそこに含まれるバッファ一覧を表示する
    gt (ノーマルモード)右隣のタブに移る。Ngt(1gt とか) で N番目のタブに移る
    gT (ノーマルモード)左隣のタブに移る。NgT(1gT とか) で 左にN個先のタブに移動する
    CTRL-W gf (ノーマルモード)カーソル位置の単語から推測されるファイルを開く
    そこそこ使う(と思う)コマンド
    コマンドうごき
    :tabf (:tabfind)引数で find して新規タブで開く
    :tabm (:tabmove)引数(数値)+1番目にタブを移動させる
    :tabd (:tabdo):bufdo のタブ版、後戻りのできない系のコマンドなので勇気が必要
    :tab XXXXXX というウィンドウが開かれる系のコマンドを、新規タブで開くようにする

    最後の :tab XXX というのは、例えば、:tab help などとすれば新規タブでヘルプが開かれ、:tab sp とすれば、今いるバッファを新規タブで開く、などということができます。

    XXX の場所には diffsplit など一部のコマンド以外ならたいてい使えるので :tab copen とか :tab helpgrep xxx とかもできます。

    その他、詳細は :help tabpage で確認してみてください。

    3. タブを少し扱いやすくしてみる

    ながくなってきたのでさっくりいきます。

    上記のよく使うコマンドなどはキーマッピングしておくと便利なので、ついでにやっておきましょう。

    " 一例
    nnoremap <silent> <leader>tf :<c-u>tabfirst<cr>
    nnoremap <silent> <leader>tl :<c-u>tablast<cr>
    nnoremap <silent> <leader>tn :<c-u>tabnext<cr>
    nnoremap <silent> <leader>tN :<c-u>tabNext<cr>
    nnoremap <silent> <leader>tp :<c-u>tabprevious<cr>
    nnoremap <silent> <leader>te :<c-u>tabedit<cr>
    nnoremap <silent> <leader>tc :<c-u>tabclose<cr>
    nnoremap <silent> <leader>to :<c-u>tabonly<cr>
    nnoremap <silent> <leader>ts :<c-u>tabs<cr>
    

    なんとなく似たようなマッピングなので共通部分を抽象化しておくなどしてみます。

    " 一例
    nnoremap [TABCMD]  <nop>
    nmap     <leader>t [TABCMD]
    
    nnoremap <silent> [TABCMD]f :<c-u>tabfirst<cr>
    nnoremap <silent> [TABCMD]l :<c-u>tablast<cr>
    nnoremap <silent> [TABCMD]n :<c-u>tabnext<cr>
    nnoremap <silent> [TABCMD]N :<c-u>tabNext<cr>
    nnoremap <silent> [TABCMD]p :<c-u>tabprevious<cr>
    nnoremap <silent> [TABCMD]e :<c-u>tabedit<cr>
    nnoremap <silent> [TABCMD]c :<c-u>tabclose<cr>
    nnoremap <silent> [TABCMD]o :<c-u>tabonly<cr>
    nnoremap <silent> [TABCMD]s :<c-u>tabs<cr>
    

    タブ操作関連のマッピングという強い意思があらわれてよかったです。

    プレフィクス・サフィックスで分離できたので変更も容易になってよかったです。

    参考:キーマッピングのプレフィックスキーについての覚書 – くふんとなく(旧)

    長くなってきていますが、もうすこし便利にしたいです。

    たまにですが、さっきまでいたタブに戻りたいが、今どこにいるかわからないので gtgtgtgt などとやる羽目になることがあります。

    そういう事態を回避するために tabrecent.vim を活用しましょう。

    参考:tabrecent.vimを書いてみた – 永遠に未完成

    使いかたはとてもわかりやすく、:TabRecent コマンドで直前までいたタブに戻れます。引数に数値を指定すればその数値ぶん前にいたタブに戻れます。

    ということでこれもマッピングしておきます。

    nnoremap <silent> [TABCMD]r :<c-u>TabRecent<cr>
    

    4. タブの表示を少しわかりやすくしてみる

    長くなってきていますが、まだもうすこし便利にしたいです。

    直接タブ番号を指定して移動したいというケースはやはり頻繁にあります。なのにデフォルトではタブ番号が表示されておらず不親切です。

    なので番号をふりましょう。

    以下では gvim でのタブ表示の例です。ぱっと見のわかりやすさの都合で GUI のほうのタブ表示について書いています。

    タブの表示は guitablabel を設定から設定できます。

    見たほうが早いと思うので以下に書いてみます。

    " 個別のタブの表示設定をします
    function! GuiTabLabel()
      " タブで表示する文字列の初期化をします
      let l:label = ''
    
      " タブに含まれるバッファ(ウィンドウ)についての情報をとっておきます。
      let l:bufnrlist = tabpagebuflist(v:lnum)
    
      " 表示文字列にバッファ名を追加します
      " パスを全部表示させると長いのでファイル名だけを使います 詳しくは help fnamemodify()
      let l:bufname = fnamemodify(bufname(l:bufnrlist[tabpagewinnr(v:lnum) - 1]), ':t')
      " バッファ名がなければ No title としておきます。ここではマルチバイト文字を使わないほうが無難です
      let l:label .= l:bufname == '' ? 'No title' : l:bufname
    
      " タブ内にウィンドウが複数あるときにはその数を追加します(デフォルトで一応あるので)
      let l:wincount = tabpagewinnr(v:lnum, '$')
      if l:wincount > 1
        let l:label .= '[' . l:wincount . ']'
      endif
    
      " このタブページに変更のあるバッファがるときには '[+]' を追加します(デフォルトで一応あるので)
      for bufnr in l:bufnrlist
        if getbufvar(bufnr, "&modified")
          let l:label .= '[+]'
          break
        endif
      endfor
    
      " 表示文字列を返します
      return l:label
    endfunction
    
    " guitablabel に上の関数を設定します
    " その表示の前に %N というところでタブ番号を表示させています
    set guitablabel=%N:\ %{GuiTabLabel()}
    

    設定完了です。これを $MYGVIMRC に記述して :source $MYGVIMRC などとすると反映されますが、gvim を再起動したほうが安心です。

    詳しくは :help setting-guitablabel で確認してみてください。

    長いわりに実のないかんじですが、Vim のタブを活用して便利に暮らしましょう!