Quantcast
Channel: Vimタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 5608

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

$
0
0

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

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

aliasとして使う

.bashrc
alias bf='cat > ${HOME}/.vim/bf'alias bfcat='cat ${HOME}/.vim/bf'

zshのglobal aliasとして使う

.zshrc
alias-gB='| bf'

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(split(string(v:event.regcontents)[2:-3],"', '"), $HOME ."/.vim/bf")" [ 2:-3 ]はリストのprefix [' と surfix ']を消すため
augroup END

注意点

  • split()writefile()の引数がリストを要求しているため、string->listに変換する必要がある
  • split(..., "', '")はリストの区切りを消すため
  • [ 2:-3 ]はリストのprefix [' と surfix ']を消すため

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

Leaderのデフォルトはバックスラッシュですが、私の場合、LeaderSpaceに設定しています。

vimでLeaderをSpaceに設定するキーマップ
let mapleader ="\<Space>"

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

使い方

shellの結果をvimにペースト

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上でshellコマンドを書いてyankする
echo hello world
vim上で書いたコマンドを実行する
$$(bfcat)hello world

#または
$ bfcat | sh
hello world

bfの実行をalias化

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

bfcatの内容を$SHELLで実行する
alias bfexec='bfcat | ${SHELL}'
vimで以下のように書いてからyank
for i (hoge1 hoge2 hoge3) echo $i
vimでyankした内容をshellで実行する
$ bfexec  # `for i ...echo $i` をzshで実行hoge1
hoge2
hoge3

$ bfexec | bf  # 実行結果を~/.vim/bfに保存
vim上でLeader-p
hoge1
hoge2
hoge3

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

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

vimで書いたコマンドをバッファ通さずvim上で実行するには?

shellとの通信用バッファを使わないので、この記事の範疇ではありませんが、気になったので調べてみると、:'<,'>!<command>を使えばよいそうです。つまり、実行したいコマンドを書いたテキストを選択してから:.
Vimで変態テキスト処理!シェルコマンドを使い倒す

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

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

まとめ

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

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

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

.zshrc
alias-gB='| bf'

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

.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(split(string(v:event.regcontents)[2:-3],"', '"), $HOME ."/.vim/bf")" [ 2:-3 ]はリストのprefix [' と surfix ']を消すため
augroup END

おまけ
vim上で書いたshellコマンドを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でLeader pcommand | bf→ vimでLeader p繰り返します。

vimからshellへは

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

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

参考

jpg

Software Design 2013年10月号


Viewing all articles
Browse latest Browse all 5608

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>