vim-shell間でクリップボードを使わずにテキストをやり取りする

# 通信用バッファ `~/.vim/bf`

クリップボードを使わずにvimとshellの間でテキストをやりとりできる方法が [Software Design 2013年10月号](https://gihyo.jp/magazine/SD/archive/2013/201310) で紹介されていました。dockerやvagrantにsshしてvimを利用している私にとっては好都合の技です。これを自分なりに使いやすくした方法を紹介します。

## aliasとして使う
```shell:.bashrc
alias bf='cat > ${HOME}/.vim/bf'
alias bfcat='cat ${HOME}/.vim/bf'
```

zshのglobal aliasとして使う

```shell:.zshrc
alias -g B='| bf'
```

## vimのキーマップを設定して使う
```vim:.vimrc
" vim - shell 通信用バッファ
imap <leader>p <ESC>:read ${HOME}/.vim/bf<CR>i
nmap <leader>p :read ${HOME}/.vim/bf<CR>
" vmap <C-b> :w!${HOME}/.vim/bf<CR> の改良↓
augroup MyBuf
    autocmd!
    autocmd TextYankPost * call writefile(v:event.regcontents, $HOME . "/.vim/bf")
augroup END
```

雑誌上では<kbd>C-B</kbd>が使われていましたが、"1ページ戻る"デフォルトのキーバインドが潰れてしまうため、私は<kbd>Leader p</kbd>を使っています。(Pasteのpと近いので。)

> <kbd>Leader</kbd>のデフォルトはバックスラッシュですが、私の場合、<kbd>Leader</kbd>を<kbd>Space</kbd>に設定しています。
>
```vim:vimでLeaderをSpaceに設定するキーマップ
let mapleader = "\<Space>"
```

また、雑誌に載っていたスクリプトでは選択→yankしないと`~/.vim/bf`に保存されませんでしたが、autocmdを使って改良したスクリプトでは選択→yankだけでなく、<kbd>yy</kbd>や<kbd>yG</kbd>など、選択せずにyankした文字列も`~/.vim/bf`に格納されるよう拡張しました。


# 使い方

## shellの結果をvimにペースト
```shell-session:shellの実行結果をvimに読み込む
# bashなど
$ ps | bf
# zsh
$ ps B
# vim上で<Leader>p
  PID TTY          TIME CMD
26353 pts/5    00:00:00 ps
26354 pts/5    00:00:00 cat
26966 pts/5    00:00:03 zsh
```

## vimで書いたコマンドをshellで実行
```vim:vim上でshellコマンドを書いてyankする
echo hello world
```

```shell-session:vim上で書いたコマンドを実行する
$ $(bfcat)
hello world

# または
$ bfcat | sh
hello world
```

## bfの実行をalias化

これよく使いそうだからaliasにできますね。記事書きながら良いのを思いつきました。

```shell:bfcatの内容を$SHELLで実行する
alias bfexec='bfcat | ${SHELL}'
```

```text:vimで以下のように書いてからyank
for i (hoge1 hoge2 hoge3) echo $i
```

```shell-session:vimでyankした内容をshellで実行する
$ bfexec  # `for i ...echo $i` をzshで実行
hoge1
hoge2
hoge3

$ bfexec | bf  # 実行結果を~/.vim/bfに保存
```

```text:vim上でLeader-p
hoge1
hoge2
hoge3
```

`for i ...$i`の文法はbashでは使えず、zsh専用です。
aliasのパイプ後を`${SHELL}`環境変数にすることで実行シェル、私の場合はzshで実行されます。

> vimで書いたコマンドをshellに流して実行し、その結果をまたパイプ+bfで拾ってvimに再書き込み？この手順は二度手間ってやつでは？


## vimで書いたコマンドをバッファ通さずvim上で実行するには？
shellとの通信用バッファを使わないので、この記事の範疇ではありませんが、気になったので調べてみると、`:'<,'>!<command>`を使えばよいそうです。つまり、実行したいコマンドを書いたテキストを選択してから<kbd>:</kbd>.
[Vimで変態テキスト処理！シェルコマンドを使い倒す](https://dev.classmethod.jp/tool/vim-use-shellcommands/)

リンク先に倣って設定ファイルに<kbd>Leader CR</kbd>でその行または選択範囲をシェルに渡して実行するよう設定しました。

```vim:選択範囲または現在行をshellとして実行するキーマップ
vnoremap <Leader><CR> :!${SHELL}<CR>
nnoremap <Leader><CR> V:!${SHELL}<CR>
```


# まとめ

**shell -> vim**
shellの実行結果をvimに渡す。またはvimで書いたコマンドをshellに読み込むか実行する。

```shell:.bashrc
# vimとの通信用バッファ
alias bf='cat > ${HOME}/.vim/bf'  # 書込
alias bfcat='cat ${HOME}/.vim/bf'  # 読込
alias bfexec='bfcat | ${SHELL}'  # 実行
```

shellの実行結果をvimに渡す(zshのglobal alias)

```shell:.zshrc
alias -g B='| bf'
```

**vim -> shell**
vimで書いたコマンドをshellに渡す

```vim:.vimrc
" vim - shell 通信用バッファ
" vim - shell 通信用バッファ
imap <leader>p <ESC>:read ${HOME}/.vim/bf<CR>i
nmap <leader>p :read ${HOME}/.vim/bf<CR>
" vmap <C-b> :w!${HOME}/.vim/bf<CR> の改良↓
augroup MyBuf
    autocmd!
    autocmd TextYankPost * call writefile(v:event.regcontents, $HOME . "/.vim/bf")
augroup END
```

**おまけ**
vim上で書いたshellコマンドをvim上で実行

```vim:.vimrc
vnoremap <Leader><CR> :!${SHELL}<CR>
nnoremap <Leader><CR> V:!${SHELL}<CR>
```

## tmux使えば良いんじゃ...？
tmuxのコピー機能を使って端末間のテキストコピーは以前から行っていましたが、改行文字やらshellのPS1(ホスト名とか現在ディレクトリ名)をコピーしないようにor貼付け後に削除する作業が煩雑でした。
しかし、このbfバッファを挟む方法なら純粋なテキストだけをshell-vim間でやりとりできます。

**tmuxとbf alias運用法の違い**

* tmuxでyank: 実行後に必要範囲を取捨選択してコピー
* bfに流し込む: 実行前にパイプ`| bf`して、バッファに流すことを予め宣言

shellからvimへ、1行程度を思いつきでvimにペーストするならtmuxの方がよいかもしれませんが、コマンドの結果を何度もvimに貼り付けたりするならbfの方が良いかもしれません。複数行をtmuxであとでまとめてvimに貼り付けるとプロンプトを消したり面倒くさいので、`command | bf` →　vimで<kbd>Leader p</kbd>→`command | bf` →　vimで<kbd>Leader p</kbd>繰り返します。

vimからshellへは

* 複雑なコマンドをvimで書いてから、ターミナルで結果を継続観察(`| tail -f`)
* コマンドをバックグラウンドで走らせておいて後から戻りたい(`command &`してから`fg`)
* 対話的な実行(`rm -i path/to/file.txt`)するならvim上でshellコマンドの実行

上記のような操作はvim上でshell走らせるよりは、vimで書いたコマンドをターミナル上で`bfexec`してあげたほうが良いかもしれません。tmux上でコピー→shellに貼り付けは改行文字が入ったりして経験上やっかいです。この辺は適材適所でしょう。

# 参考

![jpg](https://image.gihyo.co.jp/assets/images/cover/2013/thumb/TH160_641310.jpg)

[Software Design 2013年10月号](https://gihyo.jp/magazine/SD/archive/2013/201310)