📖

vim バッファ入門

2020/09/19に公開

概要

vimを日常的に使っておきながら、バッファの仕組みをロクに使わずに、1ファイル1プロセスで編集したまま長い時間が経過してしまった人 に贈る、バッファ機能の基本的な使い方を紹介。

iTerm2 を始めとするターミナルツールで画面分割をすることで、複数ファイルの編集を容易に行うことも出来るが、バッファを使った複数ファイル操作に慣れることで、関連するvimの機能やvimプラグインをさらに活用することができるので、使う使わないは一旦考えずにやってみよう。

とりあえず複数ファイル開こうや

作業用ディレクトリに以下の3つのファイルを作る。内容は Ruby のコードだが、コードそのものはまったく関係ないので読む必要はない。

ひとつ(a.rb)

file = 'this is A'

ふたつ(b.rb)

file = 'this is B'

みっつ(c.rb)

file = 'this is C'

3つのファイルがあるディレクトリで、以下のコマンドを実行しよう。3つのファイル全てが1つのvimプロセスで読み込まれる。

$ vim *.rb

vimではメモリに展開したファイルの内容をバッファと呼ぶ。

vimプロセス上で、どんなバッファが読み込まれているかは:lsコマンドで確認できる。

:ls
  1 %a   "a.rb"                         line 1
  2      "b.rb"                         line 0
  3      "c.rb"                         line 0
Press ENTER or type command to continue

画面に表示するバッファを切り替えようや

vimプロセスを起動した段階では、対象の3ファイルのうち先頭のファイル(ここではa.rb)が画面上に表示されている。

file = 'this is A'

これをb.rbや、c.rbに切り替えたい。そんなときに使うコマンドが、:bprev :bnext :bfirst :blast だ。

コマンド 効果
:bprev 1つ前のバッファに切り替え
:bnext 1つ後のバッファに切り替え
:bfirst 先頭のバッファに切り替え
:blast 末尾のバッファに切り替え

a.rbを開いてる状態で、b.rbにバッファを切り替えよう。

:bnext

b.rbに切り替わった。

file = 'this is B'

同様に:bnextを再度実行するとc.rbが開かれ、続けて:bprevを実行すると、またb.rbに帰ってくる。

:bfirstを実行すると常に先頭のa.rbに、:blastを実行すると常に末尾のc.rbに切り替わることは想像に難くないだろう。

え?切り替えめんどくさくない?

誰だってそう思う。 少ないタイプ数で高度な処理をこなせることに定評のあるvimで、何が楽しくて:bnextだの長ったらしいコマンドを打ち込まなければならないのか。それもバッファを切り替えるたびに。

ということで、大抵のvimmerはそれらのコマンドにキーバインドを割り当てる。流行りは[bとからしいが、ここでは私が採用したキーバインドの例をあげる。もちろんキーバインドにはvimmerそれぞれに拘りがあると思うので使いやすければ何でも良い。

nnoremap <silent> <C-j> :bprev<CR>
nnoremap <silent> <C-k> :bnext<CR>

<C-j><C-k> は、標準で割と空いてるのに、ホームポジション的に死ぬほど使いやすいので、他に頻出の操作を割あることがない場合はこれが良いだろう。

これでバッファの切替がメタクソに早くなった。:bfirst:blastは、個人的にはそんな使わない気がするので見送り。使うのであれば必要に応じて他のキーバインドを探す。

バッファたくさん開いたときはどうするのさ

なんやかんやでバッファリストが以下のようになったよしよう。

:ls
  1 %a   "a.rb"                         line 1
  2      "b.rb"                         line 0
  3      "c.rb"                         line 0
  4      "d.rb"                         line 0
  5      "e.rb"                         line 0
  6      "f.rb"                         line 0
  7      "g.rb"                         line 0
  8      "h.rb"                         line 0
  9      "i.rb"                         line 0
 10      "j.rb"                         line 0
 11      "k.rb"                         line 0
Press ENTER or type command to continue

おいおい、俺はg.rbを開きたいんだが、まさか:bnextを6回叩かせる気かい?
(と言っても<C-k>にバインドしていれば6<C-k>で済むが)

そんなときは:lsで出てきたバッファリストに目を通そう。左側にバッファごとに数字(バッファ番号)が振られているのがわかるだろう?

:b Nコマンドでは、バッファ番号を指定してバッファを開くことができる。よって、g.rbを開きたい場合はこうだ。

:b 7

一発でバッファ番号7が割り当てられたg.rbに移動できる。ステキ!

さらに、ファイル名がわかっていて短いなら以下のほうが早い。

:b g.rb

ちなみにファイル名の入力はTabでちゃんと補完されるので、そんなにバッファが多くないなら:bからのTab何度かが一番早いかも。

ファイル編集中にバッファ切り替えられないぞオイ

a.rb を適当に編集して保存せずに

file = 'this is A!!!!!!!!'

おっと、b.rbもついでに編集しないとな、:bnextで切り替えっと

E37: No write since last change (add ! to override)

は?(激怒)

どうやらvimでは、バッファを保存せずに閉じると警告が出るようだ。よくある「保存してないですがよろしいですか?」的なヤツ。

役立つときは役立つ警告だけど、サクサクバッファを切り替えたいときにこれが邪魔になりかねない。そういう場合は.vimrcに以下を追記することで、バッファを保存せずに切り替えることを許可できる。

:set hidden

これでよりサクサクバッファを切り替えられるようになる。

ただし、保存漏れによる事故も起こりやすくなるので、保存を忘れないような工夫が大事。

不要になったバッファを消そう

c.rbを削除しよう。削除すると言ってもファイルを削除するわけじゃく、バッファを削除する(≒編集を終了する)には、以下の:bd Nを使う。Nにはバッファ番号を指定する。
(現在開いているバッファを消すだけなら単に:bdでも可)

c.rbのバッファ番号が3であるとき

:bd 3

:lsで見ると、c.rbが消えているのがわかる。

:ls
  1  h   "a.rb"                         line 2
  2 %a   "b.rb"                         line 1
  4  h   "d.rb"                         line 1
  5  h   "e.rb"                         line 1
  6  h   "f.rb"                         line 1
  7  h   "g.rb"                         line 1
  8  h   "h.rb"                         line 1
  9  h   "i.rb"                         line 1
 10  h   "j.rb"                         line 1
 11  h   "k.rb"                         line 1
Press ENTER or type command to continue

が、実はc.rbのバッファは消えていないのだ。:bdはバッファリストから消すコマンドである。(正確にはバッファに関連したオプション、変数、マッピングなどが消える)

事実、バッファリストから消したバッファも含めてた真のバッファリストを表示する:ls!を実行するとc.rbがしぶとく生き残っていることがわかる。

:ls!
  1  h   "a.rb"                         line 2
  2 %a   "b.rb"                         line 1
  3u#    "c.rb"                         line 1
  4  h   "d.rb"                         line 1
  5  h   "e.rb"                         line 1
  6  h   "f.rb"                         line 1
  7  h   "g.rb"                         line 1
  8  h   "h.rb"                         line 1
  9  h   "i.rb"                         line 1
 10  h   "j.rb"                         line 1
 11  h   "k.rb"                         line 1
Press ENTER or type command to continue

あとかたもなく消したいなら:bw [N]を使おう。

:bw 3

:ls!を使っても表示されないことがわかる。

:ls!
  1  h   "a.rb"                         line 2
  2 %a   "b.rb"                         line 1
  4  h   "d.rb"                         line 1
  5  h   "e.rb"                         line 1
  6  h   "f.rb"                         line 1
  7  h   "g.rb"                         line 1
  8  h   "h.rb"                         line 1
  9  h   "i.rb"                         line 1
 10  h   "j.rb"                         line 1
 11  h   "k.rb"                         line 1
Press ENTER or type command to continue

言うてバッファ削除ってそんな使う?

バッファにファイルを追加したい

a.rbしか開いていない状態で

:ls
  1 %a   "a.rb"                         line 1
Press ENTER or type command to continue

b.rbを開きたい場合は:e [パス]コマンドを実行しよう。

:e b.rb

b.rbがバッファに読み込まれ、かつアクティブな状態になっている。

:ls
  1 #h   "a.rb"                         line 1
  2 %a   "b.rb"                         line 1
Press ENTER or type command to continue

この辺は無理せずNERDTreeのようなファイルツリープラグインを入れたほうが幸せになるぞ!

参考

GitHubで編集を提案

Discussion