ターミナルを開いたら勝手にtmuxに入る、という運用に慣れてしまった。Ghosttyなら設定一行だ。
command = tmux new-session -A -s 0セッションが常に1つあって、ウィンドウを閉じても生きている。快適。ただこれに慣れると、SSH先でもtmuxを使った瞬間に地獄が始まる。
症状:内側にキーが届かない
リモートのGPU鯖で腰を据えて作業するとき、当然あっちでもtmuxを立てたい。切断耐性が欲しいからだ。で ssh -t gpubox 'tmux new -A -s main' すると、ローカル(外側)tmuxと、SSH先(内側)tmuxが入れ子になる。
問題は両方がprefix C-b を待ち受けていること。内側でペイン分割しようと C-b % を押しても、外側が先に食うので内側には届かない。内側のtmuxはほぼ操作不能になる。
他の人はどうしてるのか
調べると、はっきり2派に分かれていた。
派閥1:ローカルはターミナルのネイティブ分割、tmuxはリモート専用。 ローカルでtmuxを使わなければそもそもネストしない。GhosttyやWezTermのネイティブ分割はprefix不要でクリップボードも共有できる。「ローカルの分割はあくまで画面上の手軽さ、tmuxは作業を支える土台」という住み分けだ。
派閥2:ローカル自動tmuxを維持して、ネストを飼い慣らす。 F12トグルやデュアルprefixで対処する。
最初は派閥1に惹かれた。でも自分はGhosttyだけでなく別マシンでAlacrittyも使う。Alacrittyは設計思想として分割もタブも持たない(multiplexingはtmuxに委ねる、が公式の立場)。つまり派閥1だとAlacritty機だけ運用が崩れて、指が混乱する。
全機で指の慣れを揃えたいなら、答えは逆に明確になった。全機でローカルtmuxを使い、ネストだけ飼い慣らす。dotfilesは一つ書けば全機に配られるんだから。
F12は押しづらい
派閥2の定番はSamoshkinのF12トグルだ。F12を押すと外側tmuxがprefixとキーテーブルを丸ごと「お休み」にして、全キーが内側に素通りする。もう一度押すと戻る。prefix不要の単独キーで往復できるのが売り。
書いて試したら、ちゃんと動く。動くのだが、F12が遠い。ファンクション列まで手を伸ばして、しかも頻繁にトグルするキーがそこにあるのは指に優しくない。普段の指の位置で打ちたい。
prefixはどうせ常に指の下にある(C-b)。だったらトグルもprefix経由に寄せればいい。
prefix+Tに落ち着いた
最終形はこう。C-b T で外側を黙らせ、素の T で戻る。
# C-b T で外側tmuxを黙らせ、全キーを内側(SSH先)へ素通りbind T \ set prefix None \;\ set key-table off \;\ set status off \;\ refresh-client -S# 黙らせている間はprefixが無効なので、戻りキーはoffテーブルに直キーで置くbind -T off T \ set -u prefix \;\ set -u key-table \;\ set -u status \;\ refresh-client -Sハマりどころが一つ。「入る」と「戻る」を同じ操作にはできない。 外側を黙らせた後はprefix(C-b)が無効になっているので、prefix+キーの入口がもう押せない。だから戻りは bind -T off で、prefix無しの素の T に割り当てる。off キーテーブルにいる間はこれが拾われる。
F12が単独キーで往復トグルにできたのは「prefix無しだから黙らせても押せる」からで、prefixに寄せた瞬間に入口と出口を分ける必要が出てくる、というわけだ。
「今どっちにいるか」を可視化する
最初は外側オフ中に赤い●をステータス左に出していた。でもよく考えたら、もっと素直な手がある。外側のステータスバーごと消せばいい(set status off)。
そうすると外側オフの間は外側のバーが消えて、内側tmuxのバーだけが見える。二重バーも解消されるし、「今は内側を操作している」が一目で分かる。戻れば外側バーが復活する。上のconfigが既にこれになっている。
テーマがcatppuccinなら、色を直書きせず @thm_red のようなテーマ変数を参照しておくと、flavorを変えても勝手に追従する。バナーを出す方式にするならこれが効く。
合わせ技:再ログインとポータビリティ
ネストを解いたうえで、二つ仕込んでおくと快適だった。
ペイン分割ごとの再ログインを消す。 そもそもの不満は「ローカルtmuxでペインを割るたびにSSHし直すのが遅い」だった。SSHのControlMasterで一本の接続を使い回せば、新ペインのsshが一瞬で繋がる。
Host gpubox HostName 192.168.1.50 User myuser ControlMaster auto ControlPath ~/.ssh/cm-%r@%h:%p ControlPersist 10m一本目が master を張り、二本目以降は認証もハンドシェイクも無しで相乗りする。手元では二本目が0.03秒で繋がった。
configをポータブルにする。 自分の鯖はNixOSなのだが、tmux.confに default-shell /bin/bash と書いていたら鯖側で壊れた。NixOSには /bin/bash が存在しない(/bin/sh はあるが)。ハードコードをやめてPATH経由の bash にすれば、ArchでもNixOSでも動く。
# /bin/bash 決め打ちをやめる。PATHのbashなら両対応set-option -g default-command 'bash -i'まとめ
- ローカル自動tmux × リモートtmuxはネストする。外側がprefixを食って内側に届かない。
- ローカルをネイティブ分割に寄せる主流解もあるが、分割を持たないAlacrittyを併用するなら全機tmuxで揃える方が指が楽。
C-b Tで外側を黙らせ、素のTで戻る。F12でも動くが、頻繁に押すなら指の届くprefix側が楽。入口と出口でキーの置き場所(prefixテーブル vs off テーブル)が変わるのがミソ。- 外側のステータスバーを消すと「今は内側」が可視化される。
- ControlMasterで再ログインを消し、
/bin/bashハードコードをやめてポータブルにすると、全マシンで同じ体験になる。
この記事の tmux.conf は dotfilesリポジトリ に置いてある(SSH configは実ホスト名が入るので置いていない)。