本文へ移動
vast-cowのブログ
前のページへ戻る

tmuxの中からOSC 52で外側ターミナルのクリップボードへ文字列を送る

この記事を編集

tmux の中で動いているプログラムから、tmux を表示している外側のターミナルエミュレータへ文字列を送り、そのターミナルのクリップボードを書き換えたいことがあります。

この用途には OSC 52 が使えます。

ただし tmux を挟む場合、単に OSC 52 を出力すれば常に外側へ届くわけではありません。大きく分けて、次の2通りがあります。

  1. tmux 自身に OSC 52 を処理させる
  2. tmux の passthrough を使って OSC 52 をそのまま外へ通す

通常は、まず1つ目の set-clipboard を使う方法を検討するのがよいです。

OSC 52とは

OSC 52 は、端末エミュレータに対してクリップボードの読み書きを指示する escape sequence です。

クリップボードへ文字列を書き込む場合、概念的には次の形式になります。

OSC 52 ; c ; BASE64_ENCODED_TEXT BEL

実際の制御文字で書くと、例えば hello を送る場合は次のようになります。

printf '\033]52;c;%s\a' "$(printf %s hello | base64 | tr -d '\n')"

OSC 52 のデータ部分は Base64 で渡します。

外側のターミナルエミュレータが OSC 52 に対応し、かつクリップボード書き込みを許可していれば、これだけでクリップボードへ hello が入ります。

問題は tmux の中にいる場合です。

方法1: tmuxの set-clipboard を使う

tmux には、内側のアプリケーションが送った OSC 52 を受け取り、外側のターミナルへ適切に転送する仕組みがあります。

設定は次の通りです。

set -s set-clipboard on

この設定なら、tmux の中のプログラムは特別なラッピングをせず、普通の OSC 52 を送れます。

printf '\033]52;c;%s\a' "$(printf %s hello | base64 | tr -d '\n')"

tmux がこの OSC 52 を認識し、自身の paste buffer を更新したうえで、外側のターミナルへクリップボード設定用のシーケンスを送ります。

つまり、

アプリ
  ↓ OSC 52
tmux
  ↓ OSC 52
外側ターミナル
  ↓
OSのクリップボード

という流れです。

Ms capabilityを確認する

tmux が外側ターミナルへクリップボード設定シーケンスを送るには、term capability の Ms が使われます。

確認できます。

tmux info | grep 'Ms:'

例えば次のような出力なら、OSC 52 用 capability が認識されています。

Ms: (string) \033]52;%p1%s;%p2%s\a

もし認識されていない場合、tmux 3.2 以降では terminal-features で clipboard capability を明示できます。

例えば xterm 系なら、

set -as terminal-features ',xterm*:clipboard'

のように設定できます。

実際には使用している $TERM やターミナルエミュレータに応じて対象を調整します。

set-clipboard on と external

tmux の set-clipboard には複数のモードがあります。

on の場合、tmux 自身の copy-mode だけでなく、tmux 内部のアプリケーションから送られた OSC 52 も受け付けます。

そのため、

set -s set-clipboard on

としておけば、Neovim や Emacs、自作ツールなどが普通の OSC 52 を出力するだけで、外側のターミナルのクリップボードへ届く構成にできます。

「tmux 内の任意アプリから OSC 52 を送りたい」という用途では、この方法が最も自然です。

方法2: tmux passthroughでOSC 52を直接外へ通す

もう1つは、tmux に OSC 52 を解釈させず、escape sequence そのものを外側のターミナルへ通す方法です。

tmux 3.3 以降では、まず passthrough を許可します。

set -g allow-passthrough on

または、

set -g allow-passthrough all

とします。

そのうえで、外側へ送りたい OSC 52 を tmux 用 DCS sequence で包みます。

例えば hello をクリップボードへ送る場合です。

data=$(printf %s 'hello' | base64 | tr -d '\n')
printf '\033Ptmux;\033\033]52;c;%s\007\033\\' "$data"

構造としては、

ESC P tmux;
    ESC ESC ]52;c;BASE64 BEL
ESC \

となっています。

ポイントは、passthrough 内部に含まれる ESC を ESC ESC と2個重ねることです。

つまり、本来外側のターミナルへ送りたい

ESC ] 52 ; c ; ... BEL

を、

ESC P tmux;
ESC ESC ] 52 ; c ; ... BEL
ESC \

で包んでいます。

この方法では tmux は OSC 52 の意味を処理せず、内側の escape sequence を外側のターミナルへ通します。

シェル関数にする

毎回 escape sequence を書くのは面倒なので、関数にすると便利です。

引数版なら次のようにできます。

osc52_copy() {
    local b64
    b64=$(printf %s "$1" | base64 | tr -d '\n')
    printf '\033Ptmux;\033\033]52;c;%s\007\033\\' "$b64"
}

使い方は、

osc52_copy 'clipboard text'

です。

stdin から受け取りたい場合は、

osc52_copy() {
    local b64
    b64=$(base64 | tr -d '\n')
    printf '\033Ptmux;\033\033]52;c;%s\007\033\\' "$b64"
}

として、

printf 'clipboard text' | osc52_copy

のように使えます。

tmuxのbufferを経由する方法

OSC 52 を自分で組み立てず、tmux の buffer を使う方法もあります。

例えば、

printf %s hello | tmux load-buffer -

で tmux の paste buffer に文字列を読み込めます。

tmux の clipboard integration を有効にしている構成では、copy-mode や buffer 操作と組み合わせて、外側のクリップボードへ送信できます。

tmux 自身の copy-mode からシステムクリップボードへコピーしたいだけなら、この系統の機能を使うほうが自然です。

どの方法を使うべきか

整理すると次のようになります。

方法tmux内から送るものallow-passthrough
set-clipboard on通常の OSC 52不要
DCS passthroughtmux DCSで包んだ OSC 52必要
tmux bufferload-buffer 等不要

一般的には、

set -s set-clipboard on

を設定し、アプリケーション側から普通の OSC 52 を出す方法が扱いやすいです。

printf '\033]52;c;%s\a' "$(printf %s hello | base64 | tr -d '\n')"

一方、

といった場合は、allow-passthrough と DCS wrapping を使う方法が向いています。

printf '\033Ptmux;\033\033]52;c;%s\007\033\\' "$base64_data"

注意点

どちらの方法でも、最終的には 外側のターミナルエミュレータ自身が OSC 52 に対応している必要があります。

また、セキュリティ上の理由から OSC 52 によるクリップボード書き込みを無効化していたり、確認を要求したりするターミナルもあります。

したがって動かない場合は、

  1. 外側ターミナルが OSC 52 に対応しているか
  2. OSC 52 clipboard write が許可されているか
  3. tmux の set-clipboard が有効か
  4. tmux info で Ms が認識されているか
  5. passthrough を使う場合は allow-passthrough が有効か

を順に確認すると切り分けやすくなります。

まとめ

tmux 内から外側のターミナルのクリップボードへ文字列を送りたい場合、第一候補はこれです。

set -s set-clipboard on

そして tmux 内から普通の OSC 52 を送ります。

printf '\033]52;c;%s\a' "$(printf %s hello | base64 | tr -d '\n')"

tmux を完全に素通ししたい場合は、

set -g allow-passthrough on

として、

printf '\033Ptmux;\033\033]52;c;%s\007\033\\' "$base64_data"

のように DCS passthrough を使います。

「tmux が OSC 52 を仲介する」のか、「OSC 52 自体を tmux の外へ貫通させる」のか。この違いを押さえておくと、tmux 越しのクリップボード連携を整理しやすくなります。


この記事を編集
この記事を共有:

コメント


前の記事
Windowsエクスプローラーで画像・動画を効率よく検索する方法|`*.jpg` と `kind:` の使い方
次の記事
Chrome DevToolsで覚えておきたい実践テクニック集