Vimでファイルとvimrcを再読み込みする(:e! / :source)
別プロセスがログを書き足したり、git checkoutでブランチを切り替えたりすると、Vimが抱えているバッファは古い内容のまま取り残されます。開き直さずに最新化する方法と、同じ「再読み込み」でも意味が違う「vimrcを反映し直す」方法を分けて整理します。どちらも1コマンドで済むのですが、Vimが自動で追随してくれる範囲を誤解しているとハマります。
検証環境:macOS同梱のVim 9.1.1752とNeovim 0.12.4で確認しました。オプションの既定値・エラーメッセージ・autocmdの登録件数はすべて実行結果の実物です。Windows環境では確認していません。
目次(8項目)
| コマンド | これだけ覚える |
|---|---|
:e | 今のバッファをディスクの内容で読み直す |
:e! | 未保存の変更を捨てて強制的に読み直す |
:checktime | 外部で変更されていないか確認させる |
:source $MYVIMRC | 設定ファイルを読み直す |
| Ctrl-l | 崩れた画面だけを描き直す(ファイルは読まない) |
今のバッファを読み直す
引数なしの:edit(省略形:e)を実行すると、今開いているファイルをディスクから読み直します。
:edit
:e
バッファに未保存の変更があると、この形は拒否されます。手元で変更済みのバッファに対して実行したときのメッセージがこれです。
E37: No write since last change (add ! to override)
書かれているとおり、変更を捨ててよければ末尾に!を付けます。:e!は確認を挟まずにバッファの内容をディスクの内容で上書きするので、残したい編集があるなら先に保存します。
:edit!
:e!
捨てた編集は、ファイルが短ければuで戻せます。読み直す直前のバッファを丸ごとundo履歴に積んでおく'undoreload'というオプションがあり、既定値は10000です。1行のファイルでEDITEDと書き換えてから:e!し、続けて:undoすると、VimでもNeovimでも1行目はEDITEDに戻りました。ところが12,000行のファイルで同じ手順を踏むとAlready at oldest changeが出て、何も戻りません。行数がこの値以上のファイルは保存の対象から外れるためで、巨大なログを開いているときほど:e!は取り返しがつかないと考えておくのが無難です。
読み直してもカーソルの行は変わりません。30行目にいる状態で:eを実行すると、VimでもNeovimでも30行目に留まりました。ログの途中を読んでいて最新化したい場面では、末尾へ飛ばされないぶん:eのほうが開き直すより扱いやすいです。もうひとつ、:eには読み方を1回だけ指定し直す使い道があります。Shift_JISのファイルがlatin1と判定されて化けているなら:e ++enc=cp932、改行が^M付きで見えているなら:e ++ff=dosで、手元ではどちらも1回で正しく読めました。この指定はその1回限りで、続けて引数なしの:eを打つと'fileencoding'はlatin1に戻ります。文字コードの選び方は別の文字コードで開き直す記事で扱っています。
「refresh」で探している場合、ファイルではなく画面のほうが崩れているのかもしれません。:!で外部コマンドを走らせた後や、裏で動くジョブが端末に文字を書き込んだときに表示が乱れるのは画面の問題で、Ctrl-l(または:redraw!)で描き直せば直ります。こちらはディスクを読みに行かないので、バッファの中身は1文字も変わりません。NeovimではCtrl-lに既定のマッピングがあり、:nmap <C-L>で確かめると<Cmd>nohlsearch|diffupdate|normal! <C-L><CR>と出ます。描き直しと同時に検索ハイライトの消去とdiffの再計算までするので、VimでCtrl-lを押しても同じ結果にはなりません。
autoreadを入れないと自動では追随しない
外部でファイルが書き換わったとき、Vimが黙って最新内容に差し替えてくれるかどうかは'autoread'オプションで決まります。ここがVimとNeovimで違います。素の状態で読み取った既定値がこれです。
| エディタ | 'autoread'の既定値 | 外部変更の扱い |
|---|---|---|
| Vim 9.1.1752 | 無効 | 警告が出るだけでバッファは古いまま |
| Neovim 0.12.4 | 有効 | 変更が無ければ黙って最新化される |
差が実際に出るところまで確かめました。同じ手順で、バッファを編集していない状態のままファイルを外部から書き換え、:checktimeを実行してバッファの1行目を読み出しています。
set autoread → buffer 1行目=[CHANGED BY OUTSIDE]
set noautoread → buffer 1行目=[original line]
'autoread'が無効だと、Vimは「ファイルが変わっている」と教えるだけで中身は入れ替えません。「設定を入れたのに反映されない」という話の多くはここが原因で、Neovimの記事をそのままVimに持ち込むと噛み合わなくなります。
その「教えるだけ」のときに出るのが次の確認です。Vimで'autoread'を無効のままファイルを外から書き換え、:checktimeを実行するとこう聞かれます。
W11: Warning: File "a.txt" has changed since editing started
See ":help W11" for more info.
[O]K, (L)oad File, Load File (a)nd Options:
ここでLを押すと:eと同じ読み直しになり、Oを押すと古い内容のまま編集を続けます。Oを選んだあとは、もう一度:checktimeを打っても同じ変更については何も言われません。次に外で書き換わるまで黙るので、うっかりOで閉じたなら:eで読み直すしかありません。バッファも手元で書き換えていた場合は番号がW12に変わり、文面が「the buffer was changed in Vim as well」になります。選択肢は同じなので、Lを押す前に手元の変更が要るかどうかを考える合図として読めば足ります。Lで読み込んだ直後でも、前の節の'undoreload'が効いていてuで元に戻せることを確認しました。
なお'autoread'が有効でも、バッファ側に未保存の変更があるときは自動では上書きされません。編集内容を勝手に捨てない作りになっていて、この場合は読み直すか変更を保存するかを自分で選ぶことになります。
外部の変更を自動で取り込む
'autoread'は「聞かれたときに答える」だけの設定で、Vimが常時ファイルを監視しているわけではありません。実際にチェックが走るのは:checktimeを実行したときや、コマンドを打つなど何らかの操作をしたタイミングです。ログを開きっぱなしにして眺めたいなら、チェックのきっかけを自分で仕込みます。
set autoread
augroup AutoReload
autocmd!
autocmd FocusGained,BufEnter,CursorHold * silent! checktime
augroup END
set autoreadとautocmdはセットで書く必要があります。checktimeだけ仕込んでも、Vimでは既定が無効なので警告が出るだけで終わります。CursorHoldを入れておくと、キー操作を止めてしばらく経ったときにもチェックが走るので、フォーカスを移さずに眺めているだけの場面でも追随します。
autocmdをaugroupとautocmd!で囲んでいるのは、この設定ファイルを読み直したときに同じautocmdが積み重ならないようにするためです。理由は後述します。
複数のバッファをまとめて読み直す
git checkoutのようにファイルが一斉に変わったときは、1つずつ:e!していられません。:bufdoや:tabdoと組み合わせると一括で処理できます。
:bufdo e! " 開いている全バッファ
:tabdo e! " 全タブページのカレントウインドウ
:windo e! " 現在のタブページの全ウインドウ
ただし:bufdoはバッファリストにある全部が対象なので、未保存の作業を抱えたバッファまで巻き込みます。無関係なファイルを触りたくないときは、対象のバッファへ移動してから個別に実行するほうが安全です。
:ls " バッファ番号を確認する
:buffer 3
:e!
どのバッファに未保存の変更が残っているかは:lsの出力で分かります。+が付いているものが変更ありなので、一括実行の前に眺めておくと事故を減らせます。
vimrcを反映し直す
ここまではファイルの中身の話でしたが、「設定を変えたので反映したい」という意味で再読み込みを探している場合はコマンドが変わります。設定ファイルは:sourceで読み直します。
:source $MYVIMRC " どこからでも設定ファイルを読み直す
:source % " 設定ファイルを編集中ならこれで足りる
:so % " 省略形
$MYVIMRCは、起動時に実際に読み込んだ設定ファイルのパスがVim側で入る変数です。手元で通常起動して中身を確認したところ、Vimでは~/.vimrcのフルパスが入っていました。Neovimでも同じ変数が使えて、こちらはinit.luaのパスが入ります。パスを覚えていなくてもこの1行で済むので、設定をいじりながら試すときに便利です。
注意したいのは、:sourceは設定ファイルをもう一度上から実行するだけで、前回の設定を打ち消してはくれない点です。設定ファイルから削除したsetやキーマッピングは、読み直しても消えずに残ります。設定を消したときの動作を確かめたいなら、素直にVimを再起動するのが確実です。
再起動で面倒なのは、開いていたファイルと分割の配置を作り直すことです。Vimには再起動のコマンドが無いので、:mksession! Session.vimで今の状態を書き出してから:qaで抜け、vim -S Session.vimで起動し直します。2つのファイルを縦に並べた状態で試すと、起動し直した直後もウインドウは2枚、カーソルは同じファイルにありました。Neovim 0.12には:restartがあり、1コマンドで終了と起動をこなします。ただし引数なしの:restartは起動時のコマンドラインをもう一度実行するだけで、分割は消え、:letで作った変数も残りませんでした。配置ごと戻したいときは、ヘルプにある:mksession! Session.vim | restart source Session.vimの形にすると、分割したウインドウ2枚がそのまま戻ります。未保存のバッファがあると終了の段階でE37が出て再起動まで進まないのは:eと同じです。:restartの細かい使い方とセッションファイルの中身はそれぞれ別の記事にまとめています。
再sourceでautocmdが二重登録される
「打ち消してくれない」の実害がいちばん分かりやすく出るのがautocmdです。augroupで囲っていない(あるいは囲っていてもautocmd!を書いていない)autocmdは、読み直すたびに増えていきます。実際に同じ設定ファイルを3回:sourceして、登録件数を数えました。
1回source: 2件
2回source: 4件
3回source: 6件
件数が増えるということは、保存するたびに同じ処理が2回3回と走るということです。整形コマンドを仕込んでいると目に見えて遅くなりますし、通知系なら同じメッセージが何度も出ます。augroupの先頭でautocmd!を実行してグループの中身を空にしてから登録し直せば、この問題は起きません。同じ手順で数え直すと件数が変わりませんでした。
augroup MyGroup
autocmd!
autocmd BufWritePost * echo "saved"
augroup END
1回source: 1件
2回source: 1件
3回source: 1件
設定ファイルに書くautocmdは、最初からこの形にしておくのが安全です。どのファイルが読み込まれているかを確認したいときは:scriptnamesが使えます。
ビルドが吐くログをVimで開きっぱなしにしていた頃、FocusGained * checktimeだけ書いて満足していたのですが、まったく更新されずに悩みました。Neovimで動いていた設定をVimに持ってきたのが原因で、set autoreadが抜けていただけでした。もうひとつ、設定をいじりながら:so %を連打していたら保存のたびに整形が3回走るようになったことがあって、これがaugroupとautocmd!を必ず書くようになったきっかけです。数え方を知らないと原因にたどり着けないので、:autocmd BufWritePostで一覧を出す方法は覚えておく価値があります。
まとめ
ファイルの中身を読み直すのは:e、未保存の変更を捨ててよければ:e!です。外部の変更に自動で追随させたいならset autoreadとautocmdのchecktimeをセットで書きます。Vimは'autoread'が既定で無効、Neovimは有効という差があるので、他所の設定をそのまま持ってくると噛み合いません。設定ファイルのほうを反映し直したいときは:source $MYVIMRCですが、これは打ち消しをしないので、autocmdはaugroupとautocmd!で囲っておかないと読み直すたびに増えていきます。表示が崩れただけならCtrl-lで描き直せば済み、設定を消した影響まで見たいならVimは:mksessionとvim -S、Neovimは:restartで起動し直します。