GNU screenでクリップボードの履歴を使えるようにする の所で紹介したツールをアップデートしてよりscreenコマンドの様に 使える様にしてみました。
multi_clipboard
multi_clipboard はGNU screenのpaste bufferを複数記録しておいて、 後から使える様にするツールです。
詳細は以下を参照。
Message lineでクリップボードを選択する
新しく出来るようになったことはMessage lineでクリップボードを選択することです。 これによって、Vim等、他のプログラムを立ち上げ中にも クリップボードを引き出すことが可能になります。
新しい設定として引数-S
で使う関数が加えられています。
基本的にこれらの関数を呼ぶコマンドは
GNU screenでキーにbindして使うように考えられています。
使い方は、まず、上のレポジトリのREADMEを参照してmulti_clipboard
を
PATHの通ったディレクトリに入れます。
次に、.bashrc
に最低限
export SCREENEXCHANGE=$HOME/.screen-exchange
と、screenのバッファファイルを指定します。
.screenrc
には以下の設定が必要です。
bufferfile "$SCREENEXCHANGE" # SCREENEXCHANGE must be set in .bashrc !!!
bindkey -m ' ' eval 'stuff \040' 'writebuf' 'exec !!! multi_clipboard -I'
bindkey -m Y eval 'stuff Y' 'writebuf' 'exec !!! multi_clipboard -I'
bindkey -m W eval 'stuff W' 'writebuf' 'exec !!! multi_clipboard -I'
bind a eval 'command -c mc' "!bash -c 'multi_clipboard -S'"
bind ^a eval 'command -c mc' "!bash -c 'multi_clipboard -S'"
bind -c mc n eval 'command -c mc' "!bash -c 'multi_clipboard -S -n'"
bind -c mc p eval 'command -c mc' "!bash -c 'multi_clipboard -S -p'"
bind -c mc q eval "!bash -c 'multi_clipboard -S -q'"
bind -c mc ' ' eval "!bash -c 'multi_clipboard -S -s'"
まず、bufferfile
をmulti_clipboard
と共有するために、
最初に.bashrc
で指定したものを設定します。
次の3つはコピーモード時のSpace、Y、Wに、 今コピーしたものをmulti_clipboardに記憶させるコマンドを追加しています。
これらのclipbaordsはコマンドラインから
$ multi_clipboard
と引数なしで直接呼んであげると選択出来、選択物をscreenの ペーストバッファに入れることが出来ます。
残りのbind a
からが選択モード用で、C-a a
またはC-a C-a
で選択モードに入り、
n/p
で次/前を選択
、q
で選択せずに終了、スペース1
で表示中の物を選択しscreenのペーストバッファに入れます。
選択モードに入ると、screenのMessage lineに
0: current_clipboard
こんな感じで番号とその内容が表示されます。 複数行の物が入ってる場合には表示は改行が消されてつなげて表示されます (実際にペーストバッファにはきちんと改行入りで入れられる)。
Windowに何も表示しないので、Vimを表示中にも使ったり出来ます。
使用例はこんな感じ。
追記: 2013/12/05
文字数が多いと表示が崩れるバグを直しました。
どうもGNU screenのecho
でMessage lineに表示出来るのは
512文字という制限があるようです。(環境により違うのかもしれませんが)
これより多い文字列を渡すとバグってMessage lineには表示されず(アップデートされず) 512文字をオーバーした分の文字がwindowに出てきたりします。 ので、とりあえず単純に最初の100文字程だけ表示させる様に変更してあります。
また、コマンドラインから表示して選択する方も、長い文面があると
見れなくなるので、3行以上の物は3行目を...
として以降を短縮するようにしました。
追記ここまで
その他の可能性
現在の設定ではclipboardsをためておくファイルを別途用意して、 毎回そこへ書き込み、読み取る作業を行っています。
これをもっとscreen内だけで閉じられないかな、と思って、
register
とsetenv
についてちょっと試してみました。
register
screenでは
:register p string
とすると、p
レジスタにstring
を保存することが出来る機能があります。
通常のペーストバッファは.
レジスタに割り当てられています。
これを貼り付けるには
:paste p
とpaste
コマンドを使ます。
初期値ではC-a ]
が:paste .
に割り当てられて居るので
ペーストバッファの貼付けになっているわけです。
また、screenにはscreen -X command
とすることで、
コマンドラインからscreenにコマンドを送る事が出来るので、
$ clipboard_p=$(screen -X paste p)
みたいなことをすればp
レジスタの値を取ってこれるのでは?と思ったのですが、
実際にこれを実行すると、
$ screen -X register p string
$ screen -X register p string
$ clipboard_p=$(screen -X paste p 2>&1)
string$ string
bash: string: command not found
$ echo $clipboard_p
$
こんな感じでscreen -X paste
コマンドの出力が
プロンプトの前に一回(これは消せない)、通常入力としてさらにもう一回出力され、
また、clipboard_p
には何も入っていません。
manをよく見ると、paste
コマンドは
paste [registers [dest_reg]]
Write the (concatenated) contents of the specified registers to the
stdin queue of the current window.
となっていてこの貼り付けられるときには標準入力に入れる形で行われているようです。
従って、上の2回めのstring
の文字が貼り付けられたものですが、
標準入力として残っています。
(1回目の方は良く分からない。。。)
差し当たり、簡単に直接レジスタの値を受け取るには、
$ screen -X eval 'paste p .' writebuf
$ clipboard_p=`cat $SCREENEXCHANGE`
の様に、一旦paste p .
でペーストバッファにp
レジスタの内容をコピーして、
そこからさらにbufferfileに書き出し、外から読み取る、
の様な形なら出来ますが、これだと毎回書き出し読み書きを行うので
結局今行ってる方法よりもファイルへの読み書きが増えてしまいます。
setenv
setenvを使うことでscreen全体の環境変数を設定できて、
$ screen -X setenv clipboard_1 string
とすれば
$ screen -X echo '$clipboard_1'
とすると、Message lineでstring
を見ることが出来ます。
(screenのecho
に$clipbaords
という文字列をそのまま渡すため必ず
シングルクォートで囲う。)
さらに、screenaでは-Q
オプションを使うといくつかのコマンドに関しては
Message lineの代わりに現在のWindowの標準出力として結果を出力してくれます。
従って、
$ clipboard_1=$(screen -Q echo '$clipboard_1')
$ echo $clipboard_1
string
の様に現在のシェルに持ってくることが可能です。
ただし、この場合扱えるのは1行のみで、改行はすべて潰されてしまいます。
$ string="aaa
bbb
ccc"
$ echo "$string"
aaa
bbb
ccc
$ screen -X setenv clipboard_1 $string
$ clipboard_1=$(screen -Q echo '$clipboard_1')
$ echo $clipboard_1
aaabbbccc
なので、コピーするものがすべて1行である、というのであれば screenにsetenvで渡しておいてそこから引き出す、 ということも可能ですが、流石に複数行はよく使うのでこれも駄目。
まとめ
なんとなく出来そうな感じもあるところもありますが、 どうしても上手くいかない部分があるので、素直に 外部ファイルにリストをためておく状態にするのが今のところは最善な感じです。
本当は、さらに、windowlist
の様に、一旦windowを乗っ取って
そこで一覧を表示させて選択できるようにする、
みたいなことをしてみたいのですが、流石にそれを外側からやるのは無理そう。
GNU screenのソースコードはほとんど見たことないですが、
レジストリを使ってwindowlist
を表示させるコマンドを真似して
ゴニョゴニョすれば簡単に出来そうな気がしないでもないですが、
そのうちやる気になったらやるかも、というくらいで。
追記: 2013/12/05
一時的にscreenコマンドでテンポラリーなwindowを作ってそこで操作するように すればなんとかなる?かも。
追記ここまで
-
これをEnterにしたくて
\012
(asciiコード8進法でEnter)を使ってみたんですが、 通常のbind
だと\012
を使ってbind \012 only
の様なことは出来るのですが、
-m mc
とコマンドを加えるとどうしても bindで来ないのでとりあえず諦めてます。 ↩