SSH接続先のvimでヤンクした内容をローカルホストクリップボードに反映する

# 更新履歴
## 2020/01/04 追記
SendViaOSC52関数の呼び出し条件を変更しました。

## 2019/12/23 追記
以下の内容で、小規模なテキストについて、ヤンクした内容がクリップボードに連携されることは確認した。（実用上はこれで問題ない。）
しかし、大きなデータ（1000行とか）をヤンクすると、クリップボードに反映されない、という現象が発生している。詳細と次善の対処方法（手順４）を後述する。

# 問題
Ubuntu18.04LTSにSSH接続して、リモートのvimでテキストを編集するとき、ヤンクした内容をクリップボードに反映したい。
vimはUbuntuのパッケージ vim を利用。（vim-tinyではない。）
vimのバージョンは、以下の通り。

```console
$ 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プラグインのインストール
以下のコマンド（３行）を実行して、pluginディレクトリに、osc52.vimファイルを配置します。
ここで登録するファイルは、GitHubで公開されている ShikChen/osc52.vim です。
このプラグインには、関数 SendViaOSC52() が定義されています。

```console
$ mkdir -p ~/.vim/plugin/
$ cd ~/.vim/plugin/
$ wget https://raw.githubusercontent.com/ShikChen/osc52.vim/master/plugin/osc52.vim
```

プラグインが不要なら、以下のようにして削除してください。

```console
$ rm ~/.vim/plugin/osc52.vim 
```

## 手順 3. 関数 SendViaOSC52() の呼び出し設定
とりあえず、すべてのテキストヤンクに対して、クリップボードに連携する設定を行います。

以下の設定（５行）を、~/.vimrc に追加します。

```console
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```定義をすべて削除します。

セキュリティ的に懸念がある場合は、キー割り当てで呼び出す設定をしてもよいと思います。
上記の設定を行わずに、以下の設定（１行）を、~/.vimrc に追加します。

```console
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. 行番号と不可視文字の表示・非表示をトグルするための設定
※この手順は、手順１~３を行っていなくても有効な設定手順です。
以下の通り、.vimrcに設定する。（listcharsはお好みで。）

```console
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にチェックを入れる