更新履歴
2020/01/04 追記
SendViaOSC52関数の呼び出し条件を変更しました。
2019/12/23 追記
以下の内容で、小規模なテキストについて、ヤンクした内容がクリップボードに連携されることは確認した。(実用上はこれで問題ない。)
しかし、大きなデータ(1000行とか)をヤンクすると、クリップボードに反映されない、という現象が発生している。詳細と次善の対処方法(手順4)を後述する。
問題
Ubuntu18.04LTSにSSH接続して、リモートのvimでテキストを編集するとき、ヤンクした内容をクリップボードに反映したい。
vimはUbuntuのパッケージ vim を利用。(vim-tinyではない。)
vimのバージョンは、以下の通り。
$ dpkg -l | grep vim
ii vim 2:8.0.1453-1ubuntu1.1 amd64 Vi IMproved - enhanced vi editor
ii vim-common 2:8.0.1453-1ubuntu1.1 all Vi IMproved - Common files
ii vim-runtime 2:8.0.1453-1ubuntu1.1 all Vi IMproved - Runtime files
ii vim-tiny 2:8.0.1453-1ubuntu1.1 amd64 Vi IMproved - enhanced vi editor - compact version
$ ll /usr/bin/vim
lrwxrwxrwx 1 root root 21 Aug 24 2018 /usr/bin/vim -> /etc/alternatives/vim*
$ ll /etc/alternatives/vim
lrwxrwxrwx 1 root root 18 Aug 24 2018 /etc/alternatives/vim -> /usr/bin/vim.basic*
$ vim --version | grep Vi
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Jun 06 2019 17:31:41)
$ vim --version | grep version
Huge version without GUI. Features included (+) or not (-):
対処
OSC 52という端末制御シーケンスを用いると、クリップボードに連携できる模様。
ただし、「OSC 52でのクリップボードアクセスはセキュリティ面の懸念から、デフォルトでは無効にしている端末が多い」とのこと。
ご利用は、自己責任で。
手順 1. RLoginあるいはiTerm2の設定(OSC52の有効化)
Rloginの設定(Windows)
Server Edit Entryで[クリップボード] → [制御コードによるクリップボード操作] → [OSC 52 によるクリップボードの書き込みを許可する] にチェック
iTerm2の設定(Mac)
メニューのProfiles/Open Profilesで Allow clipboard access to terminal appsにチェックを入れる
手順 2. vimプラグインのインストール
以下のコマンド(3行)を実行して、pluginディレクトリに、osc52.vimファイルを配置します。
ここで登録するファイルは、GitHubで公開されている ShikChen/osc52.vim です。
このプラグインには、関数 SendViaOSC52() が定義されています。
$ mkdir -p ~/.vim/plugin/
$ cd ~/.vim/plugin/
$ wget https://raw.githubusercontent.com/ShikChen/osc52.vim/master/plugin/osc52.vim
プラグインが不要なら、以下のようにして削除してください。
$ rm ~/.vim/plugin/osc52.vim
手順 3. 関数 SendViaOSC52() の呼び出し設定
とりあえず、すべてのテキストヤンクに対して、クリップボードに連携する設定を行います。
以下の設定(5行)を、~/.vimrc に追加します。
augroup osc52
" 最初にこのグループのautocmd定義を削除する。
autocmd!
autocmd TextYankPost * if v:event.operator ==# 'y' | call SendViaOSC52(getreg(v:event.regname)) | endif
augroup END
上記の設定では、
autocmd
(自動コマンド)という機能を使います。
テキストをヤンクしたあとのイベント(TextYankPost
)において、すべてのファイル(*
)で、y
キーでヤンクしたときだけ、SendViaOSC52()
関数を呼び出す設定です。2020/01/04 追記
記事公開当初は、autocmd TextYankPost * call SendViaOSC52(getreg(v:event.regname))
と紹介していたが、x
キーで文字を削除するとき、いちいち関数が呼ばれて動作が重くなってしまうため、y
キーだけで関数を呼び出すようにした。autocmdは、イベントにコマンドを追加するだけなので、再読み込みすると、イベントに何度も追加されてしまいます。このため、
augroup
で、osc52
という自動コマンドグループを定義し、最初にautocmd!
でグループ内のautocmd
定義をすべて削除します。
セキュリティ的に懸念がある場合は、キー割り当てで呼び出す設定をしてもよいと思います。
上記の設定を行わずに、以下の設定(1行)を、~/.vimrc に追加します。
vnoremap Y y:call SendViaOSC52(getreg('"'))<CR>
上記の設定では、
vnoremap
を使って、ビジュアル(選択)モードで、Y
(=Shift-y
)キーに、以下の動作を割り当てます。
y
(=ヤンク)- 関数
SendViaOSC52()
の呼び出し(無名レジスタの値をクリップボードに送る)※2019/12/23 追記
デフォルトでは、キー Y には、何も機能がマッピングされていないはず。
デフォルトでは、キー Y は、"yy"(行ヤンク) と同じ動作となっています。
2019/12/23 追記
上記設定を行った状態で、大きなデータ(1000行とか)をヤンクすると、クリップボードに反映されない、という現象が発生している。
確認した環境は、Windows10のRLogin経由。このとき、vimでヤンクしたテキストは98292bytes、送信するBASE64データが131064bytesまではうまく送信できたが、テキスト98293bytes、送信するBASE64データが131068bytesになると、クリップボードに反映されなかった。
vimプラグイン側は送信しているようなので、受け取り側の問題のような気がする。
ただ、RLogin側の問題か、Windows10側クリップボードの仕様か、メモリ割り当ての問題あたり?
RLogin側の該当部分は、このあたり。 RLogin/RLogin/TextRamProc.cpp [Line.4680]if ( (m_pDocument->m_TextRam.m_ClipFlag & > OSC52_WRITE) != 0 ) { clip.Base64Decode(MbsToTstr(p)); if ( pView != NULL ) pView->SetClipboard(&clip);
そこで、ヤンクを使わない方法として、マウスによる範囲選択でコピーしてしまう方法を検討。以下は、その設定方法。
手順 4. 行番号と不可視文字の表示・非表示をトグルするための設定
※この手順は、手順1~3を行っていなくても有効な設定手順です。
以下の通り、.vimrcに設定する。(listcharsはお好みで。)
set number
set list
set listchars=tab:»-,trail:-,eol:↲,extends:»,precedes:«,nbsp:%
set mouse=a
" 行番号と不可視文字の表示・非表示とマウスモードをトグルする
noremap <silent> <F12> <ESC>:set number!<CR>:set list!<CR>:exec &mouse!=""? "set mouse=" : "set mouse=a"<CR>
上記の設定では、set number
で行表示を、set list
で不可視文字の表示を、set mouse=a
でマウスモードをall
に設定している。
また、noremap
の行で、F12キーに対して、「行番号と不可視文字の表示・非表示とマウスモードをトグルする」コマンドを割り当てている。
これにより、F12を押して非表示にすれば、端末ソフトウェアの機能を使って範囲選択・コピーすることができる。再度F12を押して表示できる。
なお、範囲選択だけでクリップボードにコピーするようにするには、以下を行う。
- RLoginの場合は、「クリップボード」「左クリックの範囲指定だけでクリップボードにコピーする」にチェックを入れる。
- iTerm2の場合は、メニューのPreference ->General -> Copy to clipboard on selectionにチェックを入れる