2018-02-23

tobijibu

VirtualBoxのゲストとホスト間でvimのクリップボードを共有

普段仕事ではWindowsを使っています。 以前からmsys2が重いなぁと感じていたのですが、 最近は特にひどい状態で、tigを起動するにも10秒以上掛かってしまいます。 また、pacmanも正常に動かない状態で、 何度インストールしなおしても治りません。

ちょうど仕事が落ち着いたタイミングなので、 Vagrant + VirtualBoxにCent7を入れて新しい環境を作りました。 (ちなみに現場の開発環境はXAMPPを使っています。レガシーですね。)

Vimでコピーした内容をゲスト(CentOS)→ホスト(Windows)に渡したかったのですが、 思った以上に複雑で、手を焼いてしまいました。 その方法を残しておこうと思います。


この記事では、既にVagrant + VirtualBoxで環境が構築されている前提で説明します。 利用したボックスは以下のボックスです。
CentOS 7.2 x64 (Minimal, Puppet 4.2.3, Guest Additions 4.3.30)
https://github.com/CommanderK5/packer-centos-template/releases/download/0.7.2/vagrant-centos-7.2.box

下準備

まず、環境によってはVirtualBoxと、ゲストOSのGuestAdditionのバージョンにずれがあるかもしれません。 vagrant upで以下のエラーが表示される場合、GuestAdditionを更新しましょう。

==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.

vagrant-vbguestをインストールします。 これはVirtualBoxのプラグインです。 vagrant upを実行した時に、自動でGuestAdditionのバージョンをアップデートしてくれます。

$ vagrant plugin install vagrant-vbguest

プラグインがインストールできたら、コマンド実行します。 これでGuestAdditionのバージョンが更新され、VitualBoxとゲストOSのバージョンが揃います。

$ vagrant vbguest

Vagrantfileを編集

ホストとゲスト間でクリップボードの共通を有効にするために、Vagrantfileを編集します。 変更箇所は、52行目あたりのconfig.vm.providerで始まるブロックです。

ブロックのコメントを解除し、以下のように指定します。 具体的にはvb.customizeを追加し、その中に設定内容を追加します。


config.vm.provider "virtualbox" do |vb|
  # Display the VirtualBox GUI when booting the machine
  #vb.gui = true

  # Customize the amount of memory on the VM:
  #vb.memory = "1024"
  vb.customize ['modifyvm', :id,
    "--clipboard", "bidirectional", # クリップボードの共有
    "--draganddrop", "bidirectional", # ドラッグアンドドロップ可能に
  ]
end

xsel、Xvfbインストール

ここからはCentOSでの作業になります。

$ vagrant up
$ vagrant ssh

ログインできたら、xselXvfbをインストールします。

$ sudo yum -y install xsel
$ sudo yum -y install xorg-x11-server-Xvfb

xselはクリップボードを管理するためのコマンドです。 X(X11とも言います)のXセレクション(クリップボードのようなもの)を管理します。 Vimのclipboardでは、XセレクションのPRIMARY領域を使うため、このコマンドを使います。

XvfbはXの中に仮想的なスクリーンを生成するための機能です。 xselでコピーした内容を保持する場所を作るために使います。 Xvfbを実行しても何も表示されませんが、 裏で動いている状態なので、スクリーンショットを撮ることもできます。 ブラウザを裏で動かして、スクリーンショットを取るといったWebの表示テスト等でよく使われますね。

Xvfbの設定

仮想スクリーンを起動し、環境変数DISPLAYに設定を追加します。

$ Xvfb -screen 0 320x240x8 &
$ DISPLAY=:0 VBoxClient --clipboard &

.bashrcにログイン時にXvfbを自動立ち上げ設定を追加

ログインする度に手動でXvfbを起動するのは大変です。 ログイン時に自動で立ち上がるようにしましょう。

私は普段仕事ではbashを使っているので、.bashrcにコマンドを設定します。

if [ -x /usr/bin/Xvfb ] && [ -x /usr/bin/VBoxClient ] && [ ! -f /tmp/.X0-lock ]; then
  Xvfb -screen 0 320x240x8 > /dev/null 2>&1 &
  sleep 0.5
  DISPLAY=:0 VBoxClient --clipboard
fi

.vimrcにコマンドを追加

これでいわゆるクリップボードが使えるようになりましたので、 次はVimのコマンドを設定します。 以下の内容を~/.vimrcに追記します。

"=================================================
"== 選択範囲をクリップボードに保存
"=================================================
function! s:copyText() range
  let tmp = @@
  silent normal gvy
  let selected = @@
  let @@ = tmp
  call system("echo -e '".selected."'| xsel --display :0 -bi")
endfunction
command! -range CopyText <line1>, <line2> call s:copyText()
noremap ,y :CopyText<CR>

本来ならば、yや、d等で取得したテキストを自動でクリップボードに入れたいところですが、 各キーマップに指定するのは骨が折れるので、今回は別のキーマップを使うことにしました。

clipboard対応のVimを導入

Vimのクリップボードはvimx(いわゆるgVim)じゃないと使えないようです。

If you are running Redhat/CentOS, you can install the vim-X11 package (if you have gvim then this is already installed). This provides the vimx command, which is a console version of Vim with X11-clipboard support.
引用 - Checking for X11-clipboard support in terminal

そこで、既存のVimを削除して、新たにvimxを導入します。 以下のコマンドを実行して、+clipboardと表示された場合は対応不要です。

$ vim --version | grep clipboard

競合するパッケージを削除

$ su
# yum remove vim-minimal-2:7.4.160-1.el7.x86_64

注意:vim-minimalを削除すると、依存関係のsudoも削除されます。 この後に改めて入れ直すので問題無いのですが、 それまでsudoや、それに付随するvisudoも使用できません。

Vim8(vimx8)をインストール

vimxをインストールします。

# yum install -y http://mirror.ghettoforge.org/distributions/gf/el/7/plus/x86_64/vim-minimal-8.0.003-1.gf.el7.x86_64.rpm
# yum install -y http://mirror.ghettoforge.org/distributions/gf/el/7/plus/x86_64/vim-common-8.0.003-1.gf.el7.x86_64.rpm
# yum install -y http://mirror.ghettoforge.org/distributions/gf/el/7/plus/x86_64/vim-X11-8.0.003-1.gf.el7.x86_64.rpm

sudo復帰

sudoを入れ直します。 そして、新しく生成されたsudoersを、 sudo削除時に自動でコピーされた設定ファイルで上書きします。

# yum -y install sudo
# mv /etc/sudoers.rpmsave /etc/sudoers

エイリアス設定

インストールしたVimはvimxで起動します。 利用中のシェルに併せてエイリアスを設定しましょう。

if [ -e /usr/bin/vimx ]; then alias vim='/usr/bin/vimx'; fi

再ログイン

ここまでできたら、一旦ログインしなおします。

Vimを立ち上げて、ビジュアルモードでテキストを選択し、 ,yキーを押すと、クリップボードにコピーされます。

ホストからの貼付けはShift + Insertで対応します。

一点、注意が必要です。 コピーするテキストに'(シングルクォート)が含まれている場合、 正しくコピーすることができません。 そのため、'(シングルクォート)を含む文字列をコピーする場合は、 細かく分けてコピーするか、 ファイルとして保存し、 cat (ファイル名) | xsel --display :0 -biというような形式でコピーしてください。

参考サイト

Accessing the system clipboard
http://vim.wikia.com/wiki/Accessing_the_system_clipboard

VirtualBox の Windows と Linux (CUI) でクリップボードでテキスト共有
http://subtech.g.hatena.ne.jp/secondlife/20100526/1274883708

ビジュアルモードの選択情報の取得
http://nanasi.jp/articles/code/screen/visual.html