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

GNU screenからVimへのペーストを、インデント崩れを回避しつつ簡潔な操作で行う

$
0
0

GNU screenからVimへのペーストを、インデント崩れを回避しつつ簡潔な操作で行う

Vim Advent Calendar 2013の59日目(2014-01-28)の記事です。

GNU screenを使う目的の一つは、キーボード操作によるコピー&ペーストです。
GNU screenの他windowのシェル等でコピーした文字列をvimにペーストすることがよくあります。

が、GNU screen側の操作でペースト(CTRL-O .に設定してます)すると、vim側の'smartindent'が効いてインデントが崩れることがあります。

そうなった時は、以下の操作をしていましたが、繁雑なので、簡潔な操作で行う方法を調べてみました。

  1. EscでInsert modeを抜けて、
  2. uでundoして、
  3. :se pasteして、
  4. iでInsert modeに入って、
  5. 再度GNU screenのペースト操作(CTRL-O .)をして、
  6. EscしてInsert modeを抜けて、
  7. :se nopasteする。

(なお、GNU screenのペースト操作でペーストする際は、vim側が日本語入力モードになっていたら、日本語入力モードをオフにする操作も必要になります。この点も解決したいところです。:se pasteすれば問題ないですが。)

方法1: 'pastetoggle'を使用

.vimrc
setpastetoggle=<C-Q>
autocmd InsertLeave * setnopaste
  1. Insert modeで、CTRL-Qにより、set pasteして、
  2. GNU screenのペースト操作
  3. EscしてInsert modeを抜けると、set nopasteされる。

方法2: :a!:i!を使用

:a!:i!すればインデントは崩れない、という記述も見かけるのですが、手元ではなぜか駄目だったので:se pasteを使っていました。

少し試してみたところ、:set smartindentだけしていると駄目で、:set autoindentも必要なようです。

  1. :a!
  2. GNU screenのペースト操作
  3. <CR>で改行して、.<CR>で終了

終了方法がちょっと癖がある印象です。

方法3: Xのselectionを使う

vimで+xterm_clipboard featureが有効になっている場合、xterm内のvimでも、普通に"*p等の操作でXからのペーストが可能。

  1. "*p

もしくは、Insert modeで、

  1. CTRL-R CTRL-O *

ただし、GNU screenのペーストバッファをXのselectionに入れる設定や、操作(例えば以下の設定を~/.screenrcに入れてCTRL-O y)が必要。

.screenrc
bind y eval writebuf screen 'stuff "xsel -i -p < $HOME/tmp/screen-xchg; exit^M"'

X無しの場合(Windowsからsshでリモートに接続している場合等)は使用不可。

方法4: fakeclipを使用

Vim側で"&pすれば、GNU screenのペーストバッファからペースト可能。

  1. "&p

tmuxやX、Mac OS X、Cygwinにも対応。Vim側操作で、各システムからのペーストや各システムへのyankが可能。

方法5: fakeclipと同様の自作script

(車輪の再発明をしてました。fakeclipを失念してて、既に同じものがありそうだと思って、「GNU screen vim paste」あたりで少しぐぐっても見つけられず、自分で書いてました。「tmux vim」でぐぐってfakeclipを発見。)

  1. gp

fakeclipに比べて、以下の違いがあります。

  • ペーストする文字列に改行が含まれていたら(最後が改行で終わっていなくても)、 :putを使ってlinewiseにペースト。 行の途中にいる時に複数行をペーストする場合、 linewiseの方が使いやすい気がするので。 (ただし、"*pはlinewiseではないので、整合性はなくなりますが。)
  • screenへのyankは、レジスタ指定無しでyank操作をした後、 screenのペーストバッファへのコピーを行う操作(gy)を行う形。 これにより、screen側にyankするつもりだったのに、 "&を付けずにyank操作をしてしまった場合に、 "&を付けて再度yank操作をし直さなくても、 gyを入力するだけで良くなります。
  • screenへのyank時に、screenのreadbufが、「Slurped 28 characters into buffer」 のようなメッセージを出すと少し目ざわりなので、出さないようにmsgwait 0を追加。
.vimrc
" GNU screenのペーストバッファの内容を、Vim側に読み込む。" ~/.screenrcで以下の設定をしている前提"   bufferfile $HOME/tmp/screen-xchglets:screenfile ='~/tmp/screen-xchg'function!s:PasteFromScreen()silent!screen -X writebuf
  lets= system('cat ' . s:screenfile)calls:PasteStr(s)endfunctionnnoremap<silent>gp :<C-U>call<SID>PasteFromScreen()<CR>function!s:PasteStr(str)let save_reg = @@
  let @@ =a:str
  if stridx(a:str,"\n")>=0put" ペースト後のカーソル位置を通常の`p`の場合と合わせる
    normal!'[
  else
    normal!pendiflet @@ = save_reg
endfunctionfunction!s:YankToScreen()call writefile(split(@@,'\n',1), expand(s:screenfile),'b')" suppress message like "Slurped 28 characters into buffer"silent!screen -X eval 'msgwait 0' readbuf 'msgwait 5'"silent execute '!screen -X register . "$(cat ' . s:screenfile . ')"'endfunctionnnoremap<silent> gy :<C-U>call<SID>YankToScreen()<CR>if has('xterm_clipboard')" linewiseにしたいのでnnoremap<silent> gP :<C-U>call<SID>PasteStr(@*)<CR>"nnoremap <silent> gP "*pnnoremap<silent> gY :<C-U>let @* = @@<CR>elsefunction!s:PasteFromX()lets= system('xsel -o -p')lets= iconv(s,'utf-8',&encoding)" &encがeuc-jpの場合用calls:PasteStr(s)endfunctionnnoremap<silent> gP :<C-U>call<SID>PasteFromX()<CR>nnoremap<silent> gY :<C-U>call system('xsel -i -p', @@)<CR>endif" XXX: vimが-X付きで起動されたかの判定もするなら以下。"      もっと簡単に判定できるならいいけど、ここまでやらなくてもいい気が。" function! s:has_xterm_clipboard()"   if !has('xterm_clipboard')"     return 0"   endif"   let expect = strftime('%c')"   call system('xsel -i -p', expect)"   let actual = @*"   if actual ==# expect"     return 1"   endif"   return 0" endfunction

おまけ: ペースト直後に、ペーストした複数行のインデントを調整

通常のpを使う場合でも、ペースト直後にインデントの増減をすることが多いのですが、']を打つのが少し面倒なので。

.vimrc
" paste直後に、pasteした複数行のインデントを増減nnoremap<p<']
nnoremap>p>']
" pastetoggleや、`:a!`用。redoできるように、最初に先頭に移動nnoremap<P'[<']
nnoremap>P'[>']

gvim使用時も同じ操作ができるようにする

gvim使用時も同じ操作ができるように、~/.gvimrcに以下の設定を入れておきます。
(Windows上のgvim用でも同様に、~/_gvimrcに設定を入れておきます。)

.gvimrc
nnoremap<silent>gp"*p
nmap <silent> gP gpnnoremap<silent> gy :<C-U>let @* = @@<CR>
nmap <silent> gY gy

参考:GNU screenのペーストバッファ内容を、vimで編集した内容に更新する

普段は日本語入力IMを起動していなくて、lynxやコマンドラインで少しだけ日本語が入力したい場合、以下の操作をしていました。
(なお、lynxは、テキストフィールドでも、CTRL-X eでvimを起動して編集できるようになったので、以下の操作は不要。)

  1. screenの別windowを作って
  2. vimを起動して
  3. vim内で日本語を入力して(tcvimeを使ってIM無しでvimだけで日本語入力)
  4. 入力した日本語をscreenのコピー操作(対象文字列の選択操作も含む)でコピー
  5. screenの元のwindowに切り替えて
  6. screenのペースト操作でペースト
  7. (その後、一時的にvimを起動したwindowの後始末)

繁雑なので、以下の手順でできるようにするシェルスクリプトです。
screenのペーストバッファ内容を、vimを起動して編集した内容に更新します。

  1. screenの操作で、編集用vimを起動(CTRL-O v)
  2. vim内で日本語を入力して
  3. vimを終了(:x)。 (終了により、vimで編集した内容がscreenのペーストバッファに入り、 vim用のwindowも閉じられる。)
  4. screenのペースト操作でペースト

~/.screenrcの設定:

.screenrc
bind v eval screen 'stuff "vs; exit^M"'

上で呼んでいる~/bin/vsの内容は以下。

~/bin/vs
#!/bin/sh# edit file and copy to screen's buffer
cp /dev/null $HOME/tmp/.sv
$EDITOR$HOME/tmp/.sv
screen -X register . "`cat $HOME/tmp/.sv|nkf -e`"

Viewing all articles
Browse latest Browse all 5608

Trending Articles