rcmdnk's blog
Last update

Gnu Screen

GNU screenでクリップボードの履歴を使えるようにする の所で紹介したツールをアップデートしてよりscreenコマンドの様に 使える様にしてみました。

multi_clipboard

multi_clipboard はGNU screenのpaste bufferを複数記録しておいて、 後から使える様にするツールです。

詳細は以下を参照。

GNU screenでクリップボードの履歴を使えるようにする

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'"

まず、bufferfilemulti_clipboardと共有するために、 最初に.bashrcで指定したものを設定します。

次の3つはコピーモード時のSpaceYWに、 今コピーしたものを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内だけで閉じられないかな、と思って、 registersetenvについてちょっと試してみました。

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を作ってそこで操作するように すればなんとかなる?かも。

追記ここまで

追記: 2013/12/09

windowlist的な選択画面を作ってみました:

GNU screenでクリップボードの履歴を使えるようにする 3

追記ここまで

Sponsored Links
  1. これをEnterにしたくて\012(asciiコード8進法でEnter)を使ってみたんですが、 通常のbindだと\012を使って

    bind \012 only
    

    の様なことは出来るのですが、-m mcとコマンドを加えるとどうしても bindで来ないのでとりあえず諦めてます。

Sponsored Links

« Vimでハイライト表示を調べる HomebrewでError: GitHub API rate limit exceededを回避する »

}