Open5

tmux tips

いきなり tmux 直接関係ない話題...

OSC52

tmux の wiki を眺めてたら OSC 52 なる単語が出てきたのでなんじゃろなと思って調べた

https://www.reddit.com/r/vim/comments/k1ydpn/a_guide_on_how_to_copy_text_from_anywhere/

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 CommandsPs = 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 とクリップボード連携

https://github.com/tmux/tmux/wiki/Clipboard

ついでなのでこの内容をまとめておく

tmux のクリップボード連携設定は 2種類ある

  • OSC 52 を使う
  • copy-pipe 機能を使う

OSC 52 を使ったクリップボード連携

この動作は set-clipboard オプションにより制御される
値は on external off の三種類あり、tmux 2.6 以降のデフォルト値は external
onexternal の違いは tmux 上で動作するアプリケーションに tmux の paste buffer の操作を許可するかどうか、と書かれているが、その差異が実際どのような場面で表れるのかは読み取れなかった
最低限の動作確認では external で十分動いているので、この機能によるクリップボード連携を利用したければデフォルト値のままでよいだろう

OSC 52 を利用できることの確認

tmux 上で OSC 52 によるクリップボード連携を利用するためには以下のことを確認する

  1. set-clipboard オプションが on または external であること
  2. TERM 環境変数で指定したターミナルの terminfo に Ms capability が表れること
  3. 利用しているターミナルエミュレータ自身が 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

https://man.openbsd.org/tmux.1#ENVIRONMENT

EDITOR 環境変数または VISUAL 環境変数が指定されており、設定値に vi という文字列が含まれる場合は mode-keys status-keys オプションが vi で上書きされる

keybinding 周り

https://man.openbsd.org/tmux.1#KEY_BINDINGS

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 オプションだ

ログインするとコメントできます