VimでOSのクリップボードにコピペする(+レジスタとclipboard)
Vimでyyを押してからブラウザで貼り付けようとしても、出てくるのは全然関係ない文字列です。Vimのヤンクが書き込むのはVimの内部にあるレジスタで、OSのクリップボードとは最初から別の入れ物として扱われているからです。この2つをつなぐ役割を持つのが"+レジスタと'clipboard'オプションなのですが、どちらも「今使っているVimがクリップボード機能を持ってビルドされているか」に丸ごと依存します。条件が揃っていないと、設定を書いてもエラーひとつ出さずに黙って無視されます。ネットで見つけた設定をコピーしても直らない原因はたいていここにあります。
検証環境:macOS同梱のVim 9.1.1752、Neovim 0.12.4、およびDockerのUbuntu 24.04上のVim 9.1(Ubuntuパッケージ版)で確認しました。本文に載せている出力・レジスタの中身はすべてこの3環境の実物です。Windows版のgVimとWayland環境は手元に無いため、その2つについては公式ヘルプの記述を根拠に書いており、実機では確認していません。
目次(8項目)
| 操作 | これだけ覚える |
|---|---|
:echo has('clipboard') | 0ならそのVimは何をしても連携できない |
| "+yy | 現在行をOSのクリップボードへコピー |
| "+p | OSのクリップボードから貼り付け |
set clipboard=unnamed | 素のyyもクリップボードへ流す |
set paste | 端末から貼るときインデントを崩さない |
自分のVimがクリップボードを触れるか確かめる
設定を書き足す前に、まず自分のVimに機能があるかを確認します。Vimの中で:echo has('clipboard')を実行して1が返れば連携できるビルド、0ならどんな設定を書いても連携できません。シェルからならvim --versionの一覧に+clipboardと出ているか-clipboardと出ているかで判別できます。
vim --version | grep clipboard # +clipboard なら対応、-clipboard なら非対応
:echo has('clipboard') # Vimの中から確認する場合
ここで見落とされがちなのが、Linuxのvimパッケージは非対応であることが珍しくない点です。Ubuntu 24.04のコンテナでapt install vimしたVimを調べたところ、最小構成のvim-tinyだけでなく通常のvimパッケージも-clipboardでした。has('clipboard')は0、has('unnamedplus')も0です。同じコンテナにvim-gtk3を入れると+clipboard +X11 +xterm_clipboardに変わり、両方の判定が1になりました。
| 環境 | --version の表示 | has('clipboard') |
|---|---|---|
| Ubuntu の vim / vim-tiny | -clipboard | 0 |
| Ubuntu の vim-gtk3 | +clipboard +X11 | 1 |
| macOS同梱のVim 9.1.1752 | +clipboard -X11 | 1 |
| Neovim 0.12.4 | 外部コマンド方式 | 1 |
非対応のVimがいちばん厄介なのは、何をしても無反応で理由が分からないところです。Ubuntuのvimで試したところ、set clipboard=unnamedを実行しても&clipboardは空のままで、エラーメッセージも出ませんでした。"+yyも同様で、+レジスタは空のまま、直前に別の行を入れておいた無名レジスタも書き換わらず、ヤンク自体が起きていませんでした(バッチモードでの確認です。:help registersにはクリップボードが使えないとき無名レジスタが代わりに使われると書かれていますが、この環境では代替動作も走りませんでした)。設定が悪いのかと疑って~/.vimrcを書き直し続けても直らないので、先にhas('clipboard')を見るのが結局いちばん早い道になります。対処はDebian/Ubuntuならvim-gtk3、Fedora系ならvim-enhancedのように、機能付きのパッケージへ入れ替えることです。
その都度やりとりする("+y と "+p)
クリップボードへの読み書きは+という名前のレジスタを通して行います。名前付きレジスタと同じ書き方で、操作の前に"+を付けるだけです。ヤンクだけでなく削除や貼り付けにも同じように使えます。
"+yy " 現在行をクリップボードへコピー
"+3yy " 3行ぶんをコピー
"+y " ビジュアルモードで選択した範囲をコピー
"+dd " 現在行を切り取ってクリップボードへ
"+p " クリップボードの中身を貼り付け
手元のmacOS同梱Vimで、クリップボードにあらかじめ別の文字列を入れた状態から"+yyを実行し、シェルのpbpasteで中身を確認したところ、ヤンクした行にきちんと置き換わっていました。逆方向も同じで、ブラウザでコピーした文字列は"+pでバッファに入ります。Vim内部だけで完結するヤンクの種類についてはコピー(ヤンク)操作いろいろ、貼り付け側のバリエーションはレジスタを貼り付ける全パターンで扱っているので、この記事はOSとの境界だけに絞ります。
毎回"+を打つのが面倒に感じるかもしれませんが、後述する'clipboard'の設定と比べると副作用がありません。クリップボードを汚したくない編集と、外に持ち出したい編集を、手で明示的に切り分けられるのが利点です。
"*と"+はどこが違うのか
解説記事によって"*と書いてあったり"+と書いてあったりして混乱しますが、この2つが別物になるのはX11環境だけです。Vimの公式ヘルプははっきり書き分けています。
Vim uses PRIMARY when reading and writing the "* register ... and CLIPBOARD when reading and writing the "+ register.
X11のPRIMARYはマウスでドラッグ選択した瞬間に入り、中クリックで貼り付けられる領域です。CLIPBOARDのほうはCtrl-cやCtrl-vで使う、いわゆる普通のクリップボードにあたります。一方でX11以外のシステムでは、同じヘルプが両者はどちらもシステムクリップボードを使うと述べており、区別がありません。実際にmacOSのVimで"+yyと"*yyを続けて試したところ、どちらもpbpasteの内容を書き換えました。
迷ったときは"+を使うのが無難です。Linuxデスクトップで「他のアプリにCtrl-vで貼りたい」という用途に合うのは"+のほうで、macOSやWindowsではどちらを選んでも結果が同じになります。
yyをそのままOSへ流す(clipboardオプション)
毎回"+を付けるのをやめたい場合は'clipboard'オプションを使います。unnamedを指定すると無名レジスタへの操作が"*に、unnamedplusを指定すると"+に横流しされ、素のyyやpがそのままOSのクリップボードを相手にするようになります。
set clipboard=unnamed " Vim (macOS/Windows) はこちら
set clipboard=unnamedplus " Linux/Neovim はこちら
便利な反面、副作用は小さくありません。ヘルプに書かれているとおり、この設定が横流しするのはヤンクだけでなく削除・変更・貼り付けも含みます。macOS同梱のVimでset clipboard=unnamedにしてddを1回押したところ、クリップボードに入れておいた別の文字列が消えて削除した行に置き換わりました。ブラウザからコピーしてきた文字列をVimに貼ろうとして、その前に不要な行をddで消しただけでコピー内容が失われる、という事故がこれです。回避するにはブラックホールレジスタを使った"_ddで消すか、そもそも'clipboard'を設定せず"+を明示する運用にします。
macOSのVimでunnamedplusが効かない
日本語の解説記事ではset clipboard+=unnamed,unnamedplusという書き方をよく見かけますが、macOSのVimではこのunnamedplusの部分が単に無視されます。ヘルプに条件が明記されています。
Only available with the |+X11| or |+wayland_clipboard| feature.
macOS同梱のVim 9.1.1752は+clipboardを持ちますがhas('X11')は0で、has('unnamedplus')も0を返します。厄介なのは、この状態でもset clipboard=unnamedplus自体はエラーにならず、:set clipboard?で確認するとunnamedplusと表示される点です。設定できているように見えるのに動きません。
実際に測ってみました。クリップボードに目印の文字列を入れてから、unnamedplusだけを設定したVimでyyを押してもクリップボードは目印のまま変化せず、unnamedを設定した場合はyyだけでヤンクした行に置き換わりました。同じ操作をNeovim 0.12.4で行うとunnamedplusでもクリップボードが更新されます。
| 設定 | macOSのVim | Neovim | Linux(X11)のVim |
|---|---|---|---|
clipboard=unnamed | 効く | 効く | 効く(PRIMARY側) |
clipboard=unnamedplus | 無視される | 効く | 効く(CLIPBOARD側) |
環境を選ばない書き方にしたいなら、機能の有無で分岐させておくのが確実です。has('unnamedplus')という専用の判定がヘルプでも案内されているので、これをそのまま使えます。
if has('unnamedplus')
set clipboard=unnamedplus
elseif has('clipboard')
set clipboard=unnamed
endif
Neovimは仕組みが別(外部コマンドとOSC 52)
Neovimには+clipboardのようなビルド時の機能が存在せず、外部コマンドを呼び出してクリップボードを読み書きします。そのため「Neovimを入れ直す」のではなく「連携用のコマンドを入れる」のが対処になります。公式ヘルプの:help clipboard-toolには候補の一覧があり、macOSではpbcopy、Waylandではwl-copy、X11ではxselかxclip、Windowsではwin32yankが使われます。どれが選ばれたかは:checkhealthで分かります。手元のmacOSでの実際の出力はこうなりました。
:checkhealth vim.provider
Clipboard (optional) ~
- OK Clipboard tool found: pbcopy
ここがWARNINGになっていたら、表示されているコマンドをインストールすれば動きます。Linuxのサーバーでxclipもxselも入っていない、という状況が典型例です。
もうひとつ、SSHで入った先のVimからは手元のクリップボードに届かない、という長年の悩みがあります。VPS上のVimを常用しているときに困るのがこれです。Neovimはこれを端末のエスケープシーケンス(OSC 52)で解決する仕組みを内蔵していて、対応した端末で使えば、リモートのNeovimでヤンクした内容が手元のクリップボードへ入ります。連携コマンドが1つも見つからず'clipboard'が未設定のときに自動で選ばれる仕組みですが、明示的に指定することもできます。
-- init.lua でOSC 52を強制する
vim.g.clipboard = 'osc52'
本当にその経路が使われているのかを確かめるため、この設定を入れたNeovimを擬似端末の下で動かして出力を記録し、"+yyを実行してみました。結果、端末にESC ] 52 ; c ; b3NjNTItcGF5bG9hZAo=という制御シーケンスが流れており、末尾のBase64をデコードするとヤンクした行そのものでした。ヘルプには注意点も書かれていて、tmuxのような端末マルチプレクサを挟むと自動検出が働かないことがあるほか、クリップボードの読み出し(貼り付け方向)に対応していない端末もあります。コピー方向だけ使えれば十分な場面が多いので、そこは割り切って使うことになります。
貼り付けたコードが階段状に崩れるとき
クリップボードの設定とよく混同されるのが、端末のメニューやCmd-vでVimに貼り付けたときにインデントが右へ右へずれていく現象です。これはクリップボードの設定とは無関係で、端末経由の貼り付けが「猛烈な速さでタイプされた文字列」としてVimに届くのが原因です。元のテキストが持っている行頭の空白に、Vimの'autoindent'が足す空白が毎行重なっていきます。
手元のVimで、インデント付きのPythonコードを挿入モードへ流し込んで再現しました。
if a:
b = 1
c = 2
autoindent 有効のまま貼り付けif a: b = 1 c = 2
2行目以降でインデントが増え続けているのが分かります(赤い部分がVimの足した空白で、実体はタブと空白の混在です)。同じ入力をset pasteを有効にした状態で流し込むと、元のコードと1文字も違わない結果になりました。'paste'は'autoindent'や'expandtab'を一時的に無効化し、挿入モードのマッピングや略語も止めてしまう強い設定なので、貼り付けが終わったらset nopasteで戻します。
ただしこれはVimの話です。Neovimでは'paste'は廃止された扱いになっていて、公式のヘルプでも端末やGUIの貼り付け機能を使うときは自動的に処理されると説明されています。set pasteを勧める古い記事をNeovimで真似する必要はありません。Vim側も8.0以降はブラケットペースト(端末が貼り付けの開始と終了を通知する仕組み)に対応しているので、対応した端末ならset pasteなしでも崩れません。崩れるのは、その通知が届かない環境に当たったときです。行頭の空白がタブなのかスペースなのかを目で確かめたいときは、タブ・行末スペースの可視化を併用すると原因の切り分けが早くなります。
長らくset clipboard=unnamedを入れていたのですが、ddやxのたびにブラウザでコピーした内容が消えるのに耐えられなくなって外しました。今は"+を明示する運用に戻していて、<Leader>yを"+yに割り当てるだけで手数はほとんど変わりません。もうひとつ、社内のLinuxサーバーで「Vimのコピーが効かない」と相談されたときに設定ファイルを延々と見ていたことがあって、vim --versionを先に見ていれば-clipboardの1行で終わっていました。それ以来、この手の相談ではまずhas('clipboard')を聞くようにしています。
まとめ
VimとOSのクリップボードをつなぐのは"+レジスタで、'clipboard'オプションを使えば素のyyやpもそこへ流せます。ただしどちらもhas('clipboard')が1であることが前提で、Linuxのvimパッケージのように非対応のビルドでは設定を書いてもエラーすら出ずに黙って無視されるので、詰まったときは設定ファイルより先にビルドを疑うのが近道です。macOSのVimではunnamedplusが効かないためunnamedを使う、Neovimでは外部コマンドの有無を:checkhealthで見る、というように環境ごとに見るべき場所が違います。貼り付けたコードのインデントが崩れる問題はクリップボードとは別の話で、Vimならset paste、Neovimなら何もしなくて構いません。