tmux tips
 tennashi
tennashiいきなり tmux 直接関係ない話題...
OSC52
tmux の wiki を眺めてたら OSC 52 なる単語が出てきたのでなんじゃろなと思って調べた
ANSI escape sequences にはいくつかのカテゴリが存在するらしい
$ echo -en "\e[41mhoge\e[mfuga"
例えば、よく使う色付けをするためのシーケンスは SGR (Select Graphic Rendition) parameters と呼ばれている
\e[ から始まるシーケンスはよく見かけると思うが、この \e[ 自体に名前が付いている
これは CSI (Control Sequence Introducer) と呼ばれており、これから始まるシーケンスを CSI sequences と先に挙げた wikipedia では分類している
SGR を CSI の定義を使って書くと CSI n m (n は数字) という形をしたシーケンスであると表現できる
今回話題に挙げた OSC は not CSI なシーケンスである
ESC ] (つまり \e] (括弧の向きに注目)) を OSC (Operating System Command) と定めており、これから始まるシーケンスを OSC sequences と呼んでいる
つまり OSC 52 とは \e]52 で定義されたシーケンスによる処理のことである
具体的な使い方から書く
$ echo -en "\e]52;c;ZnVnYWZ1Z2E=\a"`
これを実行後クリップボードの中身を見ると fugafuga という文字列が入っているはずである
つまり OSC 52 とはクリップボード操作のためのシーケンスのことである
もちろん端末エミュレータがこのシーケンスを処理できなければ使えないが少なくとも Linux の Alacritty では動作することを確認した
このシーケンスの仕様は Operating System Commands の Ps = 5 2 以下の記述を参照してほしい
c は X11 における CLIPBOARD 領域への保存を意味しており、他に p (PRIMARY 領域) q (SECONDARY 領域(s ではない)) s (CLIPBOARD && PRIMARY) などが指定できる
ZnVnYWZ1Z2E= の部分はお察しの通り Base64 エンコードされたクリップボードに保存したい文字列である
ここを ? にすると (つまり \e]52;c;?;\a) (端末側が対応していれば) クリップボードから読み込みができる
ここを空文字にすると(つまり \e]52;c;;\a) クリップボードを空にする
で、\a (BEL 文字) で終端する
OSC sequences は歴史的経緯により BEL または ST (String Terminator、ESC \ で定義される) で終端されるらしい
手頃な SSH 先が無くて localhost でしか試していないので間違っているかもしれないが、これを SSH 先で実行すれば、最終的にシーケンスは手元の端末で処理されて、リモートで表示している文字列をローカルの PC のクリップボードに入れることができるはずである
 tennashi
tennashi tennashi
tennashitmux とクリップボード連携
ついでなのでこの内容をまとめておく
tmux のクリップボード連携設定は 2種類ある
- OSC 52 を使う
- 
copy-pipe機能を使う
OSC 52 を使ったクリップボード連携
この動作は set-clipboard オプションにより制御される
値は on external off の三種類あり、tmux 2.6 以降のデフォルト値は external だ
on と external の違いは tmux 上で動作するアプリケーションに tmux の paste buffer の操作を許可するかどうか、と書かれているが、その差異が実際どのような場面で表れるのかは読み取れなかった
最低限の動作確認では external で十分動いているので、この機能によるクリップボード連携を利用したければデフォルト値のままでよいだろう
OSC 52 を利用できることの確認
tmux 上で OSC 52 によるクリップボード連携を利用するためには以下のことを確認する
- 
set-clipboardオプションがonまたはexternalであること
- 
TERM環境変数で指定したターミナルの terminfo にMscapability が表れること
- 利用しているターミナルエミュレータ自身が OSC 52 に対応していること
3 について、少なくとも alacritty ではデフォルトで利用可能である
iTerm2 はデフォルトで無効だが、設定により有効化できる
// 有効化の方法も tmux の wiki に記載されている
残念ながら gnome-terminal (つまり VTE なターミナルエミュレータ) では実装されていないためこの方法は利用できない
2 については TERM 環境変数が xterm から始まるものであればデフォルトで Ms capability は有効化されている
以下のコマンドで確認できる
$ tmux info | grep Ms
 180: Ms: (string) \033]52;%p1%s;%p2%s\a
ここで [missing] と表示される場合は terminal-overrides または terminal-features オプションで有効化しておく
# 例えば urxvt の場合
## terminal-features を利用した方法(tmux 3.2 以降)
set -as terminal-features ',rxvt-unicode-256color:clipboard'
## terminal-overrides を利用した方法(それ以前の tmux)
set -as terminal-overrides ',rxvt-unicode-256color:Ms=\E]52;%p1%s;%p2%s\007'
tmux 内で tmux を動作させている場合
恐らくローカルと SSH 先で tmux を入れ子にしているパターンのことだと思うが、ちゃんと動作は確認していない
この場合は微妙に設定値の注意が増えて
- SSH 先の tmux の TERM環境変数はscreenscreen-256colortmuxtmux-256colorのいずれかでなければならない(もちろんset-clipboardおよびMscapability も有効であること)
- ローカルの tmux の set-clipboardオプションはon(externalではなく) にすること
という条件が付く
と、ここまでの内容が確認できれば、すでにクリップボード連携は有効になっている
例えば alacritty 上で tmux を動かしているとすれば、何も設定を変更することなくクリップボード連携は有効になっている
ただし、どうやら文字数制限があるようなので、大量の文字をクリップボードに入れようとしても動作しないときがあるのでそれだけ注意しておくこと
 copy-pipe を利用した
こちらの方法の方が有名で、いたるところで紹介されているので、設定方法について詳しくは触れない
よく紹介されているのはデフォルトの copy-selection* なコマンドを実行するキーバインドを copy-pipe* に書き換えていく方法だ
bind-key -T copy-mode-vi C-j send -X copy-pipe-and-cancel 'xsel -i'
bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel 'xsel -i'
bind-key -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel 'xsel -i'
tmux 3.2 からは便利はオプション copy-command が追加されているようで、これを使うと上の 3行の代わりに
set-option -s copy-command 'xsel -i'
の1行で済むようになったらしい
// 手元は残念ながら 3.1 だったので動作は確認していない
どの設定方法にしろ set-clipboard オプションが有効になっている場合はコンフリクトするので copy-pipe を利用したクリップボード連携を使う場合は以下のように設定しておく
set -s set-clipboard off
 tennashi
tennashi
 EDITOR/VISUAL 環境変数と mode-keys status-keys
EDITOR 環境変数または VISUAL 環境変数が指定されており、設定値に vi という文字列が含まれる場合は mode-keys status-keys オプションが vi で上書きされる
 tennashi
tennashikeybinding 周り
bind-key のオプションが気になったので man から適当に
bind-key [-nr] [-N note] [-T key-table] key command [arguments]
 key table(-T/-n オプション)
先のクリップボードの話題にも出てきた bind-key の -T オプション
これで指定している copy-mode-vi が key table と呼ばれているものだ
list-keys コマンドで設定されている全 key table のキーバインドを表示できる
これを見ると、デフォルトで定義されている key table は以下である
- 
prefix: プレフィックスキーを入力した後
- 
root: 事前条件なし
- 
copy-mode:copy-modeコマンド実行後(mode-keysオプションがemacsのとき
- 
copy-mode-vi:copy-modeコマンド実行後(mode-keysオプションがviのとき
bind-key コマンドの -T オプションを省略したときの挙動は -T prefix (root ではない) となっている
デフォルトで定義されている、と書いたが自前の key table を作ることも可能である
bind-key -T hoge j select-pane -D
これで hoge という key table に j を入力すると select-pane -D が実行されるというキーバインドが設定された
定義した hoge key table へは以下コマンドで切り替えられる
switch-client -T hoge
つまり例えば以下のようにキーバインドを設定しておけば、第2のプレフィックスキーを作ることもできる
bind-key -T hoge j select-pane -D
bind-key -T root C-a swtich-client -T hoge
ちなみに本当に第2のプレフィックスキーが欲しい(つまり prefix key table を開く2つ目のキー) 場合は prefix2 というオプションがあるのでそちらを設定する
また -n オプションは -T root の alias である
 -r オプション
例えばペインサイズの変更時、同じキーを連打してリサイズを連続して行ないたいときはないだろうか
bind-key -r H resize-pane -L 5
のように -r オプションを付けておけばそのような挙動を実現できる
つまり、例えば 3 回ペインサイズを左に広げたい場合に
<prefix> H <prefix> H <prefix> H
と入力せずとも
<prefix> H H H
で動くようにするためのオプションだ
このときの H の入力待ち受け時間は repeat-time オプションで設定できる
// デフォルトは 500ms
また、例えば以下のように設定した場合でも -r が有効なのはその直前に入力されたキーのみである
bind-key -r H resize-pane -L 5
bind-key -r L resize-pane -R 5
と設定された状態で
<prefix> H L
と入力してもペインサイズは元に戻らない
あくまで各々がリピートされるのを受け付けるというオプションである
 -N オプション
list-keys コマンドはそのまま実行すると、bind-key で実行したコマンドそのものを表示するが、list-keys -N で実行すると (デフォルトでは <prefix> ? にキーバインドが設定されている) キーバインドとそれを入力したときに実行される動作の説明が一覧される
この説明書きを設定するのが bind-key の -N オプションだ

