Vimでウインドウ間をカーソル移動する方法(Ctrl-w)
ウインドウを分割しても、間をマウスでクリックして移動していては速度が出ません。Ctrl-w系のキーバインドを覚えておけば、キーボードから手を離さずにウインドウ間を移動できます。
ここに書いた挙動は、すべて手元で打って確かめた結果です。Vim 9.1.1752とNVIM v0.12.4、macOS 26.4.1、120桁40行の端末で、素の動きを見たかったので-Nu NONE -i NONE付きで起動しています。位置の確認にはwinnr()とwin_screenpos()の戻り値を使っています。GUI版とプラグイン入りは見ていません。
| キー | これだけ覚える |
|---|---|
| Ctrl-w + hjkl | 方向でウインドウ移動 |
| Ctrl-w w / Ctrl-w W | 次/前のウインドウへ順に移動 |
| Ctrl-w t / Ctrl-w b | 1番目/最後のウインドウへ |
| Ctrl-w p | 直前にいたウインドウへ戻る |
方向で移動する
Ctrl-w h " 左のウインドウへ
Ctrl-w j " 下のウインドウへ
Ctrl-w k " 上のウインドウへ
Ctrl-w l " 右のウインドウへ
┌───┬───┐
│A │ B │
├───┼───┤
│ C │ D │
└───┴───┘
┌───┬───┐
│ A │B │
├───┼───┤
│ C │ D │
└───┴───┘
hjklはノーマルモードのカーソル移動と同じ方向感覚なので、覚えやすくなります。矢印キー版(Ctrl-w <Down>等)やCtrlを押しっぱなしにする版(Ctrl-w Ctrl-j等)も同じ動作です。左に1つ、右を上下に割った3分割で両方を打ち、hjkl版と同じ番号に着くことを確かめました。
端に着いたときの挙動は先に知っておくと戸惑いません。2行2列に分けて左上のウインドウに立ち、Ctrl-w hを押してもwinnr()は1のままで動きませんでした。Ctrl-w kも同じです。反対側の端へ回り込むことはなく、画面にもメッセージは出ません。行き過ぎないので、左端まで詰めたいときは連打で済みます。
数字を前置すると、その方向へその数だけ進みます。縦4分割の左から2番目で2Ctrl-w lを押すと、4番目のウインドウに着きました。足りないときは手前で止まり、同じ配置で9Ctrl-w hを押すと一番左の1番で止まります。方向キーのカウントは「いまの位置から数えていくつ先か」という相対の指定で、次の節のCtrl-w wとは意味が違います。
:vsplit notes.txt のあと Ctrl-w l で右へ移ったところ。ステータス行の明るいほうが今いるウインドウ行き先が一つに決まらない場面もあります。上に横幅いっぱいのウインドウ、下を左右に割った配置を作り、上のウインドウでカーソルの桁だけを変えながらCtrl-w jを押すと、下の左右で行き先が入れ替わりました。winwidth()で測ると下の左が60桁、右が59桁で、境目はちょうどその継ぎ目にあります。
| カーソルの桁 | Ctrl-w j の行き先 | winnr() |
|---|---|---|
| 5 | 下の左 | 2 |
| 61 | 下の左 | 2 |
| 62 | 下の右 | 3 |
| 100 | 下の右 | 3 |
Vimは「下のウインドウ」を番号で選んでいるのではなく、いまカーソルがある画面上の桁の真下にあるウインドウを選びます。同じキーを押したのに違うファイルが出てきて驚くのは、たいていこれが原因です。行の末尾にいたか行頭にいたかで結果が変わるため、配置は同じなのに再現しないことがあります。行き先を固定したいなら、後述の:wincmdにウインドウ番号を渡します。
方向を使わずに移動する
Ctrl-w w " 次のウインドウへ(最後まで行ったら先頭へ)
Ctrl-w W " 前のウインドウへ(先頭まで行ったら最後へ)
Ctrl-w wは方向を考えずにウインドウを順に回すキーです。最後のウインドウで押すと先頭へ戻り、Ctrl-w Wは逆順で、先頭で押すと最後へ回ります。4つに分けた配置の4番目でCtrl-w wを押すとwinnr()は1になり、その1番でCtrl-w Wを押すと4に戻りました。分割が2つか3つなら、方向を考えるより速く済みます。
カウントを付けたときの意味は方向キーと違います。Ctrl-w wのカウントは相対ではなく絶対で、N番目のウインドウへ行けという指定になります。1番で2Ctrl-w wを押すと2番に移りますが、その2番でもう一度同じキーを押しても2番のままでした。Ctrl-w Wも同様で、3Ctrl-w Wは3つ戻るのではなく3番目へ飛びます。
| キー | 移動前 | 移動後 |
|---|---|---|
| Ctrl-w w | 4 | 1 |
| Ctrl-w W | 1 | 4 |
| 2Ctrl-w w | 1 | 2 |
| 2Ctrl-w w | 2 | 2 |
| 3Ctrl-w W | 1 | 3 |
| 9Ctrl-w w | 1 | 4 |
3Ctrl-w w " 3番目のウインドウへ移動
番号の振られ方には決まりがあります。画面を左上から右へ走査した順ではなく、分割した順序、つまり内部で持っている木構造の順に振られます。同じ2行2列に見える配置でも、先に:vsplitで左右に割った場合と、先に:splitで上下に割った場合とで並びが変わりました。画面座標をwin_screenpos()で出して突き合わせた結果が次の表です。
| 作り方 | 1番 | 2番 | 3番 | 4番 |
|---|---|---|---|---|
:vsplitが先 | 左上 | 左下 | 右上 | 右下 |
:splitが先 | 左上 | 右上 | 左下 | 右下 |
つまりCtrl-w wの巡回順は、見た目が同じでも作り方で変わります。どちらの並びかは:echo winlayout()の返す入れ子の外側がrowかcolかで読めます。
Neovimのフローティングウインドウはこの巡回に入ります。上下2分割にフロートを1つ開くとwinnr('$')は3になり、Ctrl-w wを2回押すとそこに着きました。Vimのポップアップウインドウは数に入らず、winnr('$')は2のままで何度押しても着きません。診断やヘルプをフロートで出すNeovimでは、意図しない1枚が巡回に挟まります。
Ctrl-w t " 1番目のウインドウへ(Topの頭文字)
Ctrl-w b " 最後のウインドウへ(Bottomの頭文字)
Ctrl-w p " 直前にいたウインドウへ(Previousの頭文字)
Ctrl-w tとCtrl-w bは1番目と最後のウインドウへ飛びます。番号の振り方は上のとおり作り方で変わりますが、試した2通りの2行2列ではどちらも1番が画面の左上、4番が右下に来ました。分割を増やして自分がどこにいるか分からなくなったとき、Ctrl-w tで左上に戻ってから数え直す使い方が手軽です。
Ctrl-w pは、方向を考えずに直前のウインドウへ戻るキーです。この「直前」の中身はwinnr('#')で見えて、ウインドウを移るたびに書き換わります。:vsplitで作った直後は分割元の番号が入り、Ctrl-w tのようなジャンプでも更新されました。端に当たって移動できなかったときは書き換わりません。
左右3分割の1番にいてwinnr('#')が3の状態で:3closeを実行すると、winnr('#')は0になります。その状態でCtrl-w pを押しても1番のままで、エラーも出ませんでした。Neovimでも同じです。ウインドウを閉じる4つの方法のどれでも、閉じた直後はCtrl-w pが効きません。
コマンドでも移動できる
:wincmd j
:winc k
Ctrl-wの代わりに:wincmd(短縮形:winc)を使う書き方です。ノーマルモードのキー入力ができない自動コマンドや関数の中で移動を書きたいときに使います。手元では:wincmd lで右へ、:winc hで左へ移り、キー版と同じ番号に着きました。カウントを前に付けるとCtrl-w wと同じ絶対指定になり、:2wincmd wで2番目のウインドウへ移ります。
:exe nr . "wincmd w" " nr番のウインドウへ移動
いまどこにいるかを数値で確かめる関数もそろっています。winnr()が現在の番号、winnr('$')が総数、win_getid()が閉じるまで変わらない一意のIDです。手元の最初のIDは1000で、分割するたびに1001、1002と増えました。番号は分割のたびに振り直されるのでIDのほうが控えておく先に向きます。
winnr()に方向を渡すと、その方向にあるウインドウの番号が分かります。癖があるのは行き先が無い場合で、0ではなく自分の番号を返してきます。上下に分かれた配置の上側で試すとwinnr('h')もwinnr('k')もwinnr('l')も1、つまり自分自身で、winnr('j')だけが2でした。移動できるかは戻り値がwinnr()と一致するかで判定します。
" 下にウインドウがあるときだけ移る
function! s:GoDown() abort
if winnr('j') != winnr()
wincmd j
endif
endfunction
nnoremap <silent> <Leader>j :call <SID>GoDown()<CR>
上下2分割の上側でこのマッピングを打つと下へ移り、もう一度押しても下側にとどまりました。素のCtrl-w jと結果は同じですが、この形なら「移動できないときだけ画面分割を作る」といった分岐を1つのキーに入れられます。
移動でつまずくところ
ビジュアルモードで範囲を選んだままウインドウを移ると、選択がどうなるかは移動先の中身で変わります。左右2分割で別々のファイルを開き、左でvのあと10lと押して11文字を選んでからCtrl-w lを押すと、右のウインドウはノーマルモードで、モード表示も消えました。ところが引数なしの:vsplitで同じファイルを左右に出して同じ手順を踏むと、移った先でも選択が生きたままでした。
見分け方は単純で、同じバッファを2つのウインドウで開いているときだけ選択が残ります。引数なしの:vsplitや:splitは同じバッファを2つ並べるので、この状態には案外あたります。選んだまま隣へ移る操作を書くなら、先にどちらか確かめてください。VimとNeovimで結果は同じでした。
'splitbelow'と'splitright'を設定していても、移動キーそのものの動きは変わりません。この2つが決めるのは新しいウインドウが作られる向きだけだからです。設定した状態と外した状態で同じ見た目の配置を作り、Ctrl-w hが画面の並びどおりに動くことを確かめました。ただし番号の並びは変わるので、Ctrl-w wの巡回順は間接的に影響を受けます。
3分割・4分割で作業することが多く、最初はCtrl-w wで順番に巡回していましたが、方向を覚えてからはCtrl-w hjklで一発移動できるようになり体感速度が変わりました。Ctrl-w pは、ファイルとターミナルバッファを行き来するときに特に重宝しています。
位置と大きさを変えるキー
カーソルの移動ではなく、ウインドウの並びを変えたいときは大文字を使います。Ctrl-wに続けてH J K Lを押すと、いまのウインドウがその方向の端へ移り、画面いっぱいに伸びます。上下に分割したものを左右に並べ直したいときも、Ctrl-w Lを1回押すだけで済みます。
Ctrl-w H " 左端へ移動して縦いっぱいに
Ctrl-w J " 下端へ移動して横いっぱいに
Ctrl-w r " 並び順を回転させる
Ctrl-w x " 隣のウインドウと入れ替える
並びを変えるとウインドウ番号も振り直されます。2行2列の1番でCtrl-w Lを押すと、そのウインドウは4番になり、残りが1つずつ繰り上がりました。2Ctrl-w wのような番号指定を体で覚えていると行き先が変わるので、入れ替えを混ぜて使うなら方向キーで動くほうが安定します。回転と入れ替えの違いはウインドウの位置を入れ替える方法で分けて扱っています。
大きさも同じCtrl-wから始まるキーで変えられ、数字を前に付ければその量だけ動きます。細かく調整するより、Ctrl-w _でいまのウインドウを最大にして、必要なときだけCtrl-w =で戻すほうが手数は少なく済みます。数値で指定する:resizeとの使い分けはウインドウサイズを変更する方法にまとめています。
Ctrl-w = " すべて均等な大きさに
Ctrl-w _ " 高さを最大に
Ctrl-w | " 幅を最大に
5Ctrl-w + " 高さを5行増やす
5Ctrl-w < " 幅を5桁減らす
キーを短くする
Ctrl-wの2打が煩わしいなら、移動だけを1打に割り当てる人が多くいます。Ctrl-hのような組み合わせなら、ノーマルモードで潰しても困りません。
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
ただしCtrl-lは本来「画面を描き直す」キーで、Neovimでは検索ハイライトの解除も兼ねています。潰す前に、自分がその機能を使っていないかを確かめてください。空いているキーの探し方は未割り当てキーの記事にまとめています。
tmuxを使っているなら、Ctrl-wがVimまで届くかも気になります。tmuxの既定のprefixはCtrl-bなのでCtrl-wは素通しされ、この記事の検証もすべてtmuxの中で行いましたが取り合いは一度も起きませんでした。
問題になるのはprefixをCtrl-wに変えている場合です。そのtmuxの中でVimを開き、左右2分割の右側からCtrl-w hを送ったところ、winnr()は2のままで届きませんでした。prefixがCtrl-bなら同じ手順で1へ移るので、tmuxが先に受け取っているのが原因です。移動を1打に割り当てておけば取り合いは避けられます。
まとめ
ウインドウ間の移動はCtrl-w + hjklが基本です。巡回移動にはCtrl-w w、直前の場所へ戻るにはCtrl-w pを組み合わせれば、複雑な分割でも迷わず移動できます。ウインドウの作り方、位置を入れ替える方法にまとめています。