Vimで画面分割する方法(:split / :vsplit / :new / :vnew)
Vimの画面分割(ウインドウ分割)のコマンドは、「今のバッファをもう1枚の窓に映すのか、新しいバッファを作るのか」と「上下に分けるのか、左右に分けるのか」の2軸で並べると4つに収まります。名前の似ている:splitと:newを区別しないまま使うと、片方の窓に書いた文字がもう片方にも出て面食らうので、この2軸から入るのが近道です。
この記事の数値は、macOS 26.4.1 上の Vim 9.1(patches 1-1752)と Neovim 0.12.4 を、120桁39行の端末で設定を読み込まずに起動し、winheight()とwinwidth()で測った値です。端末の大きさが違えば数字も変わりますが、端数の行き先や上限の求め方は変わりません。
目次(8項目)
| キー | これだけ覚える |
|---|---|
| Ctrl-w s | 今のファイルを上下分割 |
| Ctrl-w v | 今のファイルを左右分割 |
| Ctrl-w n | 新規バッファを上下分割で開く |
:vnew | 新規バッファを左右分割で開く(キーバインドなし) |
用語の整理:水平分割と垂直分割
まず用語です。水平分割(split)は画面を上下に分ける分割、垂直分割(vsplit)は左右に分ける分割を指します。コマンド名のvは「vertical(垂直)」の頭文字で、「virtual」の略ではありません。上下に並ぶほうを水平と呼ぶのは、分割線が水平に走るからです。窓の並び方で覚えると必ず取り違えるので、線の向きで覚えると引っかかりません。
もう1つの軸は、分割した先に何を映すかです。:split系は今と同じバッファをもう1枚の窓に映すだけで、バッファの数は増えません。:new系はその場で名前の無いバッファを1つ作り、それを新しい窓に映します。前者は同じ文章を2か所から眺める道具、後者は空白の作業場を出す道具で、見た目が似ているわりに用途が重なりません。
| 既存ファイルを分割 | 新規バッファを開く | |
|---|---|---|
| 水平(上下) | :split | :new |
| 垂直(左右) | :vsplit | :vnew |
今のファイルをもう1枚の窓で見る
Ctrl-w s " 上下に分ける
Ctrl-w v " 左右に分ける
:split / :sp " 上下に分ける
:vsplit / :vsp " 左右に分ける
┌─ file.txt ────────┐ │ │ │ │ └────────────────────┘
┌─ file.txt ────────┐
│ │
├────────────────────┤
│ file.txt │
└────────────────────┘
:split で上下に分けたところ。同じファイルを別の位置で見られるどちらのコマンドも今の窓を2つに割り、両方に同じバッファを映します。ヘルプでも、結果は同じファイルに対する2つのビューポートだと説明されています。実際、:vsplitで分けたあと左の窓で hello と打つと、getbufline(winbufnr(2), 1)が返す右の窓の1行目も hello になりました。バッファが1つしかないので、アンドゥの履歴もマークも2つの窓で共通です。長い関数の頭と末尾を同時に見る読み方は、この性質の上に成り立っています。
大きさは半分ずつになりますが、割り切れないぶんは新しく開いた窓が受け取ります。120桁39行の端末で:vsplitすると左60桁・右59桁で、これは区切り線の1桁を引いた119桁の分配です。分け合う行数が奇数になるように端末を1行広げて:splitすると上19行・下18行になり、'splitbelow'を入れて新しい窓を下に出すと18行・19行に反転しました。端数が付くのは上下の位置ではなく、新しい窓のほうです。
キー版のCtrl-w sにはCtrl-w Ctrl-sという別名もありますが、ヘルプはこちらに、端末によっては効かず入力が止まることがあるのでCtrl-qで復帰するように、という注意を付けています。多くの端末でCtrl-sが画面出力の一時停止に割り当てられているためで、指に入れるならCtrl-w sのほうです。
分割した瞬間に本文が上下へずれて見えることがあります。200行のファイルの100行目にカーソルを置き、画面が82行目から表示されている状態で:splitすると、上下どちらの窓も92行目からの表示に変わりました。'splitkeep'の既定値がcursorで、狭くなった窓にカーソル行を残すため表示をずらすからです。set splitkeep=screenにすると上の窓は82行目から、下の窓は101行目からになり、画面上の文字は動きません。既定値も測った値もVimとNeovimで同じでした。
新しいバッファを開く
Ctrl-w n " 空のバッファを上下分割で開く
:new " 同上
:vnew " 空のバッファを左右分割で開く
:vertical new " :vnew と同じ
:newが何をしているかは、ヘルプの一文がそのまま答えになっています。
This behaves like a ":split" first, and then an ":enew" command.
分割してから空のバッファに切り替える、という2段構えです。a.txt だけを開いた状態で:newを打つと、新しい窓のバッファ番号は2、bufname()は空文字列、'buftype'も空で、getbufinfo()のlistedは1でした。特殊な窓ではなく普通の編集用バッファなので、:w memo.txtと名前を与えれば保存でき、:lsにも並びます。
使い分けは、置きたい中身の出どころで決まります。今のファイルの別の場所を見たいなら:split、貼り付けた文字列を加工する場所や、コマンドの出力を溜める下書きが欲しいなら:newです。:splitで開いた2枚目の窓に何か書けば元のファイルが変わりますが、:newのバッファはどのファイルにも結び付いていないので、名前を付けて保存しない限りディスクには何も起きません。
キーがあるのはCtrl-w nだけで、:vnewに対応するキーはありません。カウントを前に置けるのは他の分割と同じで、5 Ctrl-w nと押すと高さ5行の窓が開きました。左右に空バッファが欲しいときは:vnewか:vertical newを使います。:verticalは分割系のコマンドに前置できる修飾子で、これを付けると上下ではなく左右に開きます。
ファイルやバッファを指定して開く
4つのコマンドはどれも末尾にファイル名を取れます。そして引数を付けた瞬間、:splitと:newの差は消えます。ヘルプでも:new {file}と:split {file}は1つの項目にまとめて書かれており、手元で b.txt を両方で開き比べてもバッファ番号は同じ3、1行目はどちらも BBB でした。:newが空のバッファを作るのは、引数を省いたときだけの話です。
:split ~/notes/todo.md " 上下に分けて開く
:vsplit config.lua " 左右に分けて開く
:sview README.md " 読み取り専用で分けて開く
:sfind main.c " 'path' から探して分けて開く
相対パスの起点はカレントディレクトリで、編集中のファイルの場所ではありません。sub/c.txt を開いている状態で:split a.txtを打つと、開いたのは sub/a.txt ではなく起動したディレクトリの a.txt でした(expand("%:p")で確認)。隣のファイルを開くなら:split %:h/other.txtと書くか、set autochdirで追従させます。
:sviewは:splitに読み取り専用を付けた版です。開いた窓では'readonly'が1になりますが'modifiable'は1のままなので、打ち込むこと自体はできて、保存しようとしたところで止められます。参照用のファイルを並べるとき、うっかり保存する事故を1段減らせます。
:sfindは'path'を辿ってファイルを探し、見つかったら分割して開きます。set path=subとしてから:sfind c.txtを打つと窓が2つになり、開かれたのは sub/c.txt でした。見つからないときはE345: Can't find fileが出て、窓の数は1のまま分割自体が起きません。'path'の組み立て方はプラグイン無しでファイル名からファイルを探す記事で扱っています。
開きたいものがすでにバッファとして読み込まれているなら:sbufferです。分割するつもりで:eを打ってしまい今の窓が置き換わったときも、Ctrl-^で直前のファイルに戻ってから:sb 3のようにバッファ番号を渡せば並べ直せます。番号の調べ方はバッファ一覧(:ls)の読み方の記事にまとめています。
同じバッファを別のタブページに出したいなら:tab splitです。手元で打つとtabpagenr("$")が2に増え、新しいタブの窓の数は1でした。画面を割らずに作業場所だけ増やす形です。タブそのものの開き方や切り替えはVimのタブ操作の記事にあります。
分割する向きを固定する
既定では、水平分割は上に、垂直分割は左に新しい窓が開きます。'splitbelow'も'splitright'も既定値はオフで、Vim 9.1.1752 と Neovim 0.12.4 のどちらも0を返しました。分割するとカーソルは新しい窓へ移るので、既定のままだと画面を分けるたびにカーソルが上か左へ跳ぶことになります。
set splitbelow " 水平分割は下に開く
set splitright " 垂直分割は右に開く
この2行を入れると、分割するたびに新しい窓が下か右に増えます。読む順番と増える方向が一致するので入れている人が多い設定で、戻したいときはset nosplitbelowとset nosplitrightです。
設定を変えずに、そのとき1回だけ向きを指定することもできます。:belowright splitと打つと、'splitbelow'がオフのままでも新しい窓は下に来ました。反対向きが:aboveleftで、どちらも:vsplitや:newの前に置けます。
もう1組ある:topleftと:botrightは、今の窓ではなく画面全体の端に開きます。左右に分けた状態で普通に:splitすると割られるのは今いる列だけで、3つの窓の幅は60桁・60桁・59桁のままでした。同じ状態で:botright splitを打つと、画面の下端に幅120桁の窓が開きます。横いっぱいで読みたいものを出すときに効きます。
分割したときの大きさを決める
コマンドの前に数字を置くと、新しい窓の大きさを指定して開けます。39行の端末で:10splitを打つと新しい窓が10行、残りが26行になりました。合計36行なのは、コマンドライン1行とステータス行2本を除いた本文の総量がそれだけだからです。幅を指定するなら:vertical 40splitで、40桁と79桁に分かれます。数字が指す先は、どちらの場合も新しく開くほうの窓です。
| 打ったもの | 結果(120桁39行の端末) |
|---|---|
:split | 上18行 / 下18行 |
:10split | 上10行 / 下26行 |
:vsplit | 左60桁 / 右59桁 |
:vertical 40split | 左40桁 / 右79桁 |
:botright split | 下端に幅120桁の窓 |
分割は無限には増やせません。同じ端末で:splitを繰り返すと、20枚目を作ろうとしたところでE36: Not enough roomが出て、窓の数は19で止まりました。窓1枚には本文の最低1行とステータス行1行が要るので、コマンドラインを除いた38行を2で割った19枚が上限という計算です。垂直方向は同じ理屈で60枚まで入りました。
この最低1行を決めているのが'winminheight'で、既定は1です。set winminheight=0にすると本文が1行も見えない窓が許されるようになり、同じ端末で37枚まで分割できました。ステータス行だけが積み上がるので実用ではありませんが、上限の決まり方はこれではっきりします。幅側の'winminwidth'も既定は1で、値はVimとNeovimで同じでした。
分割したあとの操作は、それぞれ別の記事に分けてあります。作った窓の大きさを:resizeなどで整えるのがウインドウサイズを変更する記事、窓から窓へカーソルを移すのがウインドウ間をカーソル移動する記事、並び順そのものを組み替えるのがウインドウの位置を入れ替える記事、増やしすぎた窓を畳むのがウインドウを閉じる4つの方法の記事です。
最初は:splitと:vsplitの上下左右がどちらか毎回迷っていましたが、「vはvertical=左右」と覚えてからは迷わなくなりました。ワイドモニタで作業するときはvsplitで左右に並べ、ノートPCの狭い画面ではsplitで上下に分けるというように、画面比率に応じて使い分けています。
まとめ
画面分割は、同じバッファをもう1枚の窓に映す:split系と、名前の無いバッファを作る:new系を、上下と左右で掛け合わせた4つが基本形です。vが付けば左右になり、末尾にファイル名を渡せば両系統の差は無くなります。新しい窓が上や左に来るのが落ち着かないなら'splitbelow'と'splitright'を入れます。