最近 vim でターミナルでもタブが使えることを知りました。まあ使えれば便利だろうということで、タブの活用法を考えてみました的なエントリ。
基本的に私は vim はさておき vimperator に毒されているので、vimperator が提供するブラウザのタブの感覚で、vim のタブも使えたらいいなあ、ということを前提にしています。
タブの移動
まず、vimperator においてはタブの移動は <C-n> および <C-p> です。ということで、vim もそうします。
nnoremap <C-n> gt
nnoremap <C-p> gT
プレフィックス
次に、タブ関連の操作はプレフィックスとして t を使用することにします。デフォルトの t はあまり使っている人がいない気がしますが(使うとしても f かな)、一応 t も t; として使えるように定義しましょう。そして t のマッピングは解除しておきます。
nnoremap t; t
nnoremap t <Nop>
新しいバッファを開く
vimperator においては、現在のタブでページを開くときは o、新しいタブでページを開くときは t です。vim でもそれをまねてみます。
nnoremap to :<C-u>edit<Space>
nnoremap tt :<C-u>tabnew<Space>
カレントバッファのディレクトリを元に新しいバッファを開く
次に、vimperator で現在の URL を初期値として新しいページを開くのは O と T です。vim でもそれをまねてみますが、完全に現在のファイル名を初期値とするのではなく、現在のファイルが存在するディレクトリを初期値にしてみます。これはファイル名補完を活用するためです。現在開いているファイル存在するディレクトリ内の、別のファイルを参照したいときに便利です。
nnoremap <expr> tO ':<C-u>edit ' . GetRelativePath()
nnoremap <expr> tT ':<C-u>tabnew ' . GetRelativePath()
function! GetRelativePath()
let path = expand('%:~:.:h')
if path == '.'
return ""
else
return path . '/'
endif
endfunction
画面分割
タブとは関係ないですが、画面分割に対して同じようなマッピングを定義してもよいでしょう。「タブの中の画面を分割する」と思えば、プレフィックスは t で良いと思います。
nnoremap ts :<C-u>split<Space>
nnoremap <expr> tS ':<C-u>split ' . GetRelativePath()
nnoremap tv :<C-u>vsplit<Space>
nnoremap <expr> tV ':<C-u>vsplit ' . GetRelativePath()
タブを閉じる
そして、vimperator ではタブを閉じるのは d です。ということで、以下のように。
nnoremap <silent> td :<C-u>tabclose<CR>
新しいタブで help を開く
また、ここからは vimperator から離れますが、help を開く場合に新しいタブで開くマッピングを用意してみましょう。これは vimperator の 'newtab' を意識していますが、vim には同様のオプションはないようです。
nnoremap th :<C-u>tab help<Space>
ウィンドウ・バッファをタブに移動する
さらに、例えば新しいタブで開きたかったのについつい :e と入力してしまったり、:h と打ってしまった場合に、あとからバッファを新しいタブに分離できるマッピングがあると便利でしょう。
nnoremap <silent> tm :<C-u>call MoveToNewTab()<CR>
function! MoveToNewTab()
tab split
tabprevious
if winnr('$') > 1
close
elseif bufnr('$') > 1
buffer #
endif
tabnext
endfunction
'tabline' とかは適当に設定しておきましょう。個人的には close ボタンは不要で、カレントディレクトリが表示されていたりなんかするといいかなぁ、という気がします。タブが増えてきたらカレントディレクトリ表示のあたりから潰します。
set tabline=%!MakeTabLine()
function! MakeTabLine()
let s = ''
for n in range(1, tabpagenr('$'))
if n == tabpagenr()
let s .= '%#TabLineSel#'
else
let s .= '%#TabLine#'
endif
let s .= '%' . n . 'T'
let s .= ' %{MakeTabLabel(' . n . ')} '
let s .= '%#TabLineFill#%T'
let s .= '|'
endfor
let s .= '%#TabLineFill#%T'
let s .= '%=%#TabLine#'
let s .= '%{fnamemodify(getcwd(), ":~:h")}%<'
return s
endfunction
function! MakeTabLabel(n)
let bufnrs = tabpagebuflist(a:n)
let bufnr = bufnrs[tabpagewinnr(a:n) - 1]
let bufname = bufname(bufnr)
if bufname == ''
let bufname = '[No Name]'
else
let bufname = fnamemodify(bufname, ":t")
endif
let no = len(bufnrs)
if no == 1
let no = ''
endif
let mod = len(filter(bufnrs, 'getbufvar(v:val, "&modified")')) ? '+' : ''
let sp = (no . mod) == '' ? '' : ' '
let s = no . mod . sp . bufname
return s
endfunction
その他のマッピング
最後に、どれだけ使うかどうかはわかりませんが、一応いろいろ定義してみます。
nnoremap <silent> t] :buffer<CR>
nnoremap <silent> tn :bnext<CR>
nnoremap <silent> tp :bprevious<CR>
nnoremap <silent> tD :<C-u>bdelete<CR>
nnoremap <silent> tl :<C-u>buffers<CR>
nnoremap tgf <C-w>gf
nnoremap tgF <C-w>gF
for n in range(1, 9)
exe 'nnoremap <silent> t' . n ' :<C-u>tabnext ' . n . '<CR>'
endfor
まとめ
たぶん、fuzzyfinder とか ku とかを使う人にとっては、この辺のマッピングはいらない気がします。ポップアップが出ると気が散るとか、vimperator のスタイルが好きな人にとっては、これくらい定義してあると便利なのかと思います。
まあ、その場合には wildmenu は有効になっていた方が良い気はしますが。
set wildmenu
set wildmode=list:longest,full
Tracked: 1月 26, 15:12