tmux tips
いきなり 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 のクリップボードに入れることができるはずである
tmux とクリップボード連携
ついでなのでこの内容をまとめておく
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 にMs
capability が表れること - 利用しているターミナルエミュレータ自身が 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
環境変数はscreen
screen-256color
tmux
tmux-256color
のいずれかでなければならない(もちろんset-clipboard
およびMs
capability も有効であること) - ローカルの 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
EDITOR
/VISUAL
環境変数と mode-keys
status-keys
EDITOR
環境変数または VISUAL
環境変数が指定されており、設定値に vi
という文字列が含まれる場合は mode-keys
status-keys
オプションが vi
で上書きされる
keybinding 周り
bind-key
のオプションが気になったので man から適当に
bind-key [-nr] [-N note] [-T key-table] key command [arguments]
-T
/-n
オプション)
key table(先のクリップボードの話題にも出てきた 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
オプションだ