🪟

tmux がなければ vim を使えばいいじゃない

2024/10/20に公開

tmux がない環境で暮らすには

ターミナルでの快適な暮らしに tmux は欠かせません。
しかしながら世の中には tmux が使えない環境というものがあります。
そんな環境で暮らしていくには、どうすればよいでしょうか。

vim を使いましょう。
vim はターミナルを開けます。
画面の分割もできます。
タブだってあります。

目標はシェルをたくさん開くこと

目標は端末上でシェルをたくさん開くことです。
セッションのことは考えません。

作ったもの

いきなりですが、こちらが作ったものです。
細かな解説は省略します。

作ったもの (長いので折りたたんでいます)
"----------------------------------------
"  一般
"----------------------------------------

set encoding=utf-8
set visualbell t_vb=
set clipboard=unnamed,unnamedplus

"----------------------------------------
"  見た目の調整
"----------------------------------------

set showtabline=2
set laststatus=0

" ウィンドウ分割線をシンプルにする
set statusline=set fillchars+=stl:,stlnc:set fillchars+=vert:highlight! link StatusLineTerm Comment
highlight! link StatusLineTermNC Comment
highlight! link VertSplit Comment
highlight! link TabLineFill ToolbarButton

" タブラインをシンプルにする
function! MyTabLine()
  let s = ''
  for i in range(tabpagenr('$'))
    " タブ番号の設定
    let tabnr = i + 1
    " アクティブなタブの強調表示
    let s ..= (tabnr == tabpagenr() ? '%#TabLineSel#' : '%#TabLine#')
    let s ..= '%' .. tabnr .. 'T'
    " タブ番号の表示
    let s ..= ' ' .. tabnr .. ' '
  endfor
  " タブページ後の空白を埋める
  let s ..= '%T%#TabLineFill#%='
  return s
endfunction

set tabline=%!MyTabLine()

"----------------------------------------
"  キーバインディング
"----------------------------------------

" INFO: alt を認識してくれない問題への対処
"   https://vi.stackexchange.com/questions/2350/how-to-map-alt-key
"   :help :set-termcap
for i in range(97,122)
  let c = nr2char(i)
  exec "set <M-" .. c .. ">=\e" .. c
  exec "nno <M-" .. c .. "> " .. c
endfor

let g:mapleader="\<C-q>"
set termwinkey=<C-@>

" タブの作成
tno <silent> <Leader>c <C-\><C-n>:tab terminal<CR>
tno <silent> <M-m> <C-\><C-n>:tab terminal<CR>

" タブの移動
tno <expr><silent> <Leader>n tabpagenr('$') > 1 ? '<C-\><C-n>:tabnext<CR>' : ''
tno <expr><silent> <Leader>p tabpagenr('$') > 1 ? '<C-\><C-n>:tabprevious<CR>' : ''

" 画面分割
tno <silent> <Leader>" <C-\><C-n>:bel term<CR>
tno <silent> <Leader>% <C-\><C-n>:bel vert term<CR>
tno <silent> <M-n> <C-\><C-n>:call SplitWindow()<CR>

" ウィンドウが横長なら垂直分割、縦長なら水平分割
function! SplitWindow()
  if winwidth(0) < winheight(0) * 2
    bel term
  else
    bel vert term
  endif
endfunction

" コピー/貼り付け
tno <silent> <Leader>[ <C-\><C-n>
tno <silent> <Leader>] <C-@>"+

" ウィンドウ間を移動
tno <silent> <M-h> <C-@>h
tno <silent> <M-j> <C-@>j
tno <silent> <M-k> <C-@>k
tno <silent> <M-l> <C-@>l

" ウィンドウのサイズ変更 (tmux の resize-pane 風)
function! ResizeVert(c)
  if winnr('h') != winnr('l')
    let l:c = winnr() == winnr('l') ? -a:c : a:c
    exe 'vert resize ' .. printf('%+d', l:c)
  endif
  if mode() == 'n'
    norm! i
  endif
endfunction

function! ResizeHori(c)
  if winnr('j') != winnr('k')
    let l:c = winnr() == winnr('j') ? -a:c : a:c
    exe 'resize ' .. printf('%+d', l:c)
  endif
  if mode() == 'n'
    norm! i
  endif
endfunction

tno <silent> <M-a> <C-\><C-n>:call ResizeVert(-1)<CR>
tno <silent> <M-s> <C-\><C-n>:call ResizeHori(+1)<CR>
tno <silent> <M-w> <C-\><C-n>:call ResizeHori(-1)<CR>
tno <silent> <M-d> <C-\><C-n>:call ResizeVert(+1)<CR>

" ウィンドウのキル
tno <silent> <Leader>x <C-@><C-c>

"----------------------------------------
" その他挙動の調整
"----------------------------------------

" Vim 起動時にターミナルを開く
autocmd VimEnter * term ++curwin

" タブ切り替え時に insert モードに入る
autocmd BufEnter * if &buftype ==# 'terminal' && mode() ==# 'n' | exe "norm! i" | endif

" Yank したら insert mode に移行
autocmd TextYankPost * if &buftype ==# 'terminal' && mode() ==# 'n' | exe "norm! i" | endif

この設定では次のことができます。
(<Leader><C-q> です。)

キー 動作
<Leader>c または <M-m> タブを新規作成
<Leader>n 次のタブへ
<Leader>p 前のタブへ
<Leader>" 画面を水平分割
<Leader>% 画面を垂直分割
<M-n> アクティブなウィンドウが縦長なら水平分割、横長なら垂直分割
<Leader>[ ノーマルモードへ移行
<Leader>] 貼り付け
<M-h/j/k/l> 指定方向のウィンドウに移動
<M-w/a/s/d> アクティブウィンドウのサイズを変更

このコードを .vimrc-tmux として保存して、 vim -Nu .vimrc-tmux で読み込んで起動します。 .bashrc などにエイリアスを作っておくと便利です。

alias vmux='vim -Nu ~/.vimrc-tmux'

見た目

コマンドラインがあるので一番下の行は使えません。

課題

この設定にはまだまだ課題もあります。

プレフィックスの挙動が怪しい

プレフィックス (<Leader>) を <C-q> に設定していますが、一部の環境[1]ではこれが正しく動きません。

Meta キーの挙動が怪しい

<M-xx> の形をしたキーバインドがいくつかあります。
こちらも環境によって動いたり動かなかったりするので注意が必要です。
本当は <M-H/J/K/L> なども活用したかったのですが、手元の環境ではうまく動かせませんでした。

おわりに

ライトなユースケースには十分耐えうるかと思います。
ただ機能不足感は否めないので、改善案等ありましたらコメントいただけると嬉しいです。

脚注
  1. Windows 上の mintty で動く Git Bash で問題が起きました。マルチプレクサ上で vim を開いた状態 (vim が入れ子になっている状態) で <C-q> を押すと、入力がマルチプレクサではなく内側の vim に吸われます。原因は分かっていませんが、 mintty の代わりに conhost.exe を使うことで回避できます。 ↩︎

Discussion