GNU screenのスクロールバッファをvimで開いて、コピーモードのかわりに使う方法

GNU screenのコピーモードは、vi風操作が可能ですが、以下の動作がvimと違って使いにくいので、
スクロールバッファを一時ファイルに保存してvimで編集するための方法です。
(vim以外のエディタでも同様の方法が可能)

+ 日本語上での`w`等による単語単位移動の動作が異なる
+ 矩形選択方法が異なる(右端マーク操作)
+ `i"`等のtext-objectは未対応(`W`による単語選択がある程度)
+ `)`による文単位の移動等は未対応

(ふと、MS-DOSでVz Editorを常駐させてコンソール出力をコピーしていたのと同様のことができないかと思いついたので。)

また、複数の離れた場所からコピーする必要がある場合、
「コピーモード開始、コピー対象文字列の場所に移動、コピー対象文字列を選択、ペースト」
を繰り返す手間がかかるのに対し、vimで編集する方法であれば、
コピーモード開始は1回ですみ、ペーストしたい文字列を編集して作ってから、1回だけペースト操作をすれば良くなります。

```:.screenrc
minmsgwait 0
defscrollback 1000
bufferfile $HOME/tmp/screen-xchg
bind V eval 'msgwait 0' copy 'stuff "g G$>"' screen 'stuff "vim +$ $HOME/tmp/screen-xchg;exit^M"' 'msgwait 1' 'echo ""'
```

備考:

+ `msgwait 0`で、邪魔になるメッセージ表示を抑制。
+ `g G$>`で、スクロールバッファを最初から最後までコピーしてbufferfileに書き出し。
+ `screen 'stuff "vim ..."'`で、新しくwindowを作ってそこでvimを起動。vimが終了されたらシェルをexitしてwindowを閉じる。
+ `vim +$`で、起動後に`:$`を実行して最終行に移動。
+ `echo ""`で、`msgwait 1`実行によって表示されるメッセージを即時消去。

## vimからscreenのコピーバッファへのコピー

vimからscreenのコピーバッファへのコピーは、[fakeclip.vim](https://github.com/kana/vim-fakeclip)参照。
(もしくは、以下の記事のYankToScreen()参照。
http://qiita.com/deton/items/61466d630edbac6734ae#3-5 )
また、vimを直接呼ぶかわりに、一時ファイルを編集・保存したら、
その内容をscreenのコピーバッファに反映する以下のスクリプトを呼ぶ形でも可。

```sh:vsbuf
#!/bin/sh
# edit file and copy to screen's buffer
vim +$ $HOME/tmp/screen-xchg
screen -X eval 'msgwait 0' readbuf 'msgwait 1'
```

## bashのedit-and-execute-command(`C-xC-e`)との組み合わせ
エディタ起動後、vimで画面分割してscreenのコピーバッファを開いて、コマンドライン編集の参考用に使えるようにする。
(やっぱりコマンドライン実行したくなくなった場合はvimを`:cq`で終了)

```:.screenrc
bind E eval 'msgwait 0' copy 'stuff "g G$>"' 'stuff "^X^E:sp ~/tmp/screen-xchg^MG"' 'msgwait 1' 'echo ""'
```

## 複数行を`,`付きで連結してのコピー
screenのコピー機能の、複数行を`,`付きで連結してのコピー等は、vim側で適当に編集すればいいかと思っています。
めったに使わないので。
(`{dir1,dir2,dir3}/*.html`のように指定したい場合くらいしか使ったことが無いです。)

## スクロールバッファに対してスクリプトを実行
vim起動以外にも、適当なスクリプトを作って、
直前のコマンドの出力結果のみを抽出したり等も可能。

(主にコマンドを実行した後になって何かしたい場合用。
コマンド実行前ならパイプを使えばいいので。)

直前のコマンドの出力結果を抽出してコピーする例:

```:.screenrc
bind P eval 'msgwait 0' copy 'stuff "g G$>"' screen 'stuff "picklastout.sh;exit^M"' 'msgwait 1' 'echo ""'
# 以下では動かない模様。
#bind P eval copy 'stuff "?deton@colinux:^Mnj /deton@colinux:^Mk$ "'
```

### 例: 直前の出力結果抽出スクリプト(vim(あるいはed)をバッチモードで使用)

```sh:picklastout.sh
#!/bin/sh
cp ~/tmp/screen-xchg ~/tmp/picklastout
vim -e -s ~/tmp/picklastout < ~/bin/picklastout.ed
#ed -s ~/tmp/picklastout < ~/bin/picklastout.ed > /dev/null 2>&1
# remove last "\n"
head -c -1 ~/tmp/picklastout > ~/tmp/screen-xchg
screen -X eval 'msgwait 0' readbuf 'msgwait 1'
```

```ed:picklastout.ed
$
?^deton@colinux:
1,.d
/^deton@colinux:/d
w
```

備考: 

+ `deton@colinux:`はプロンプト文字列。要変更。
+ シェルのコマンド引数としてペーストして使いやすいように、最後の改行を削除

### 例: 直前の出力結果抽出スクリプト(awk版)

```sh:picklastout.sh
#!/bin/sh
cat $HOME/tmp/screen-xchg | picklastout.awk >$HOME/tmp/picklastout
mv $HOME/tmp/picklastout $HOME/tmp/screen-xchg
screen -X eval 'msgwait 0' readbuf 'msgwait 1'
```

```awk:picklastout.awk
#!/usr/bin/awk -f
BEGIN {
	prevout = "\n";
}
# CHANGEIT: prompt string
/^deton@colinux:/ {
	if (out != "") {
		prevout = out;
	}
	out = "";
	next;
}
{
	out = out $0 "\n";
}
END {
	# remove last "\n"
	printf("%s", substr(prevout, 0, length(prevout) - 1));
}
```

## 備考: スクロールバッファ内容は表示内容なので元の出力と異なる場合あり

通常のscreenでのコピーと同様に以下は気を付ける必要あり。

+ タブがスペースに展開される
+ less等で長い行を表示した際、折り返されると、継続行とみなされない。

## lynxの表示をコピーしたい場合のlynx側設定
lynxを使う場合、1スクリーンへの表示ごとにscrollback bufferがクリアされるので、
以下の設定をlynx.cfgでしておいた方が良いかもしれません。
さっき見ていたページの内容を参照したいことがよくあるので。
(遅いマシンだと少しちらつきが多くなるのが気になりますが)

```:lynx.cfg
ENABLE_SCROLLBACK:TRUE
```

## 関連
* [カーソルの一つ上の行のコピーを少ないキーストロークで行う方法](http://lists.gnu.org/archive/html/screen-users/2011-01/msg00007.html)

```:.screenrc
bind P eval "copy" "stuff -k ku" "stuff Y" "stuff \033"
# 以下でいい気も。
#bind P eval "copy" "stuff kY"
```

([GNU Screenバージョン4.2がリリースされました](http://yskwkzhr.blogspot.jp/2014/04/gnu-screen-v-4.2-has-released.html)の記事からたどって、[GNU Screen Watch: January 2011 - April 2013](http://yskwkzhr.blogspot.jp/2013/04/gnu-screen-watch-january-2011-april-2013.html#screen-users)より。)

* (screenでなく[VimShell](https://github.com/Shougo/vimshell.vim)を使う)