Claude Code Vimモードの使い方—hjkl・ビジュアル選択・jjでEsc設定

Claude Code Vimモードの使い方—hjkl・ビジュアル選択・jjでEsc設定 | mohablog

長いプロンプトの真ん中で打ち間違いに気づいたとき、矢印キーとBackspaceでは1文字ずつしか戻れません。Claude Codeの入力欄はVimモードに切り替えられて、bで単語の頭へ、ciwで単語ごと打ち直せます。対象はプロンプトの入力欄だけ。ファイルの編集方法は変わりません。

目次

Vimモードを有効にする

Claude Codeの入力欄には、素の状態でもreadline風のキー操作が入っています。行頭へCtrl+A、行末へCtrl+E、単語を消すならCtrl+W。Vimモードは、この土台をモード付きの操作体系に置き換える設定です。現行のv2.1.214時点で標準搭載されています。

/config の Editor mode で切り替える

有効化は/configを開き、Editor modeをvimに変えるだけ。公式ドキュメントの「Vim editor mode」セクションも、有効化を「/config → Editor mode」の一手順として説明しています。切り替えると入力欄の左下にNORMALINSERTのモード表示が出て、今どちらにいるかが分かります。

settings.json の editorMode で固定する

毎セッション/configから入るのは手間です。ユーザー設定ファイル~/.claude/settings.jsoneditorModeを書けば、起動時からVimモードで立ち上がります。

{
  "editorMode": "vim"
}

起動後の入力欄はこうなります。左下がNORMAL始まり。

NORMAL  ~/workspace/api
FastAPI の非同期ハンドラを直す█

iを押すとINSERTに変わり、文字を打てるようになります。プロジェクト単位で切り替えたい設定ではないので、ユーザー設定に置くのが素直です。素の入力モードに戻したくなったら、/configでEditor modeを切り替え直すか、editorModeの行を消すだけ。設定を外してもコマンド履歴や下書きはそのまま残ります。

素の入力モードとの違い

Vimモードにしなくても入力欄は動きます。差が出るのは、繰り返しと範囲指定。同じ削除を何度もやる、囲みの中身だけ替える、といった操作でキー数が縮みます。

操作素の入力モードVimモード(NORMAL)
行頭へ移動Ctrl+A0 / ^
行末へ移動Ctrl+E$
単語を消すCtrl+W(前方向のみ)dw / db / daw
1文字消すBackspacex
直前の操作を繰り返すなし.

.dawのような「動詞+対象」の組み合わせが、素のモードにはありません。ここがVim側の効きどころです。

逆に、短い1行を打つだけならモード切り替えのぶん手数が増えます。素のモードとVimモードの損益分岐は、プロンプトの長さと打ち直しの回数。数十行の指示を何度も練り直す使い方なら、Vim側が効いてきます。1行コマンドを投げて終わりなら、素のモードのままで困りません。

NORMALモードで狙った位置に飛ぶ

NORMALモードはカーソルを動かすためのモードです。文字は打てませんが、そのぶん1キーが移動やジャンプに割り当たっています。

hjklとw・b・eで単語単位に動く

hjklが左・下・上・右。1文字ずつ動くのはhl、単語送りはw、単語の先頭に戻すのはb、単語末はe。長いプロンプトほど、単語ジャンプの差が出ます。

NORMAL
GET /users/{id}/posts を Depends で書き換える█

ここでbを2回押すと、カーソルは末尾から単語2つぶん左へ戻ります。

GET /users/{id}/posts を █Depends で書き換える

f・t と ;・, で行内の文字を狙う

行内の特定文字に飛ぶならff{でカーソル右の最初の{へ一気に移動します。t(なら(の直前まで。同じ狙いを繰り返すなら;、逆方向に戻すなら,。スネークケースの変数名やパスを直すとき、1文字ずつ進めずに済みます。

NORMAL  ← 行頭にカーソル
█docker run -e DATABASE_URL=postgres://localhost:5432/app

f:で最初の:(postgresの直後)へ飛び、;で同じ探索を繰り返すと、次の:(ポート番号5432の前)に着きます。ポート番号だけ直したいなら、この2打で目的地です。

入力の端では履歴移動に切り替わる

NORMALモードでjkを押すと、通常はカーソルが上下します。ただしカーソルが入力の先頭か末尾にあって、それ以上動けないとき。jkと矢印キーはコマンド履歴の移動に切り替わります。1行だけのプロンプトでkを押すと前の入力が出てくるのは、この挙動によるもの。編集のつもりが履歴を呼び出してしまったら、カーソルが端にいたサインです。行内に戻してkを押せば、上の行へ普通に動きます。

消す・変える・ヤンクする

編集は「動詞+範囲」で組みます。削除はd、変更(削除してINSERTに入る)はc、ヤンクはy。そこにw$で範囲を足します。

コマンド動き
xカーソル上の1文字を削除
dd / D行を削除 / 行末まで削除
dw / cw単語を削除 / 単語を変更
yy / p行をヤンク / カーソル後にペースト
>> / <<行をインデント / デインデント
u / .取り消し / 直前の変更を繰り返す

sS(1文字・1行を消してINSERT)はv2.1.211以降で追加されました。それより前のバージョンではclccで代用します。

テキストオブジェクトで囲みの中身だけ入れ替える

Vimモードで入力欄の編集が変わるのは、テキストオブジェクトを覚えてから。i(inner)とa(around)に囲み文字を足すと、カーソルが囲みのどこにあっても、内側や外側をまとめて掴めます。移動してから消す、の2ステップが1つになります。

ci” で引用符の中身を打ち直す

ダブルクオートの中身を差し替える場面。カーソルが文字列のどこにあっても、ci"で中身が消えてINSERTに入ります。

NORMAL
curl -s "https://old.example.com/api" | jq .█

行末にカーソルがある状態でci"を押すと、引用符の中だけ空になり、カーソルがそこに入ります。

INSERT
curl -s "█" | jq .

あとはURLを打ち直すだけ。引用符の開き位置までカーソルを運ぶ手間が消えます。JSONのキーを直すときのci"も同じ動きです。

複数の引用符を同じ文字列に替えたいなら、1回目をci"で打ったあと、次のクオートへカーソルを移して.を押すだけ。直前の変更(削除+入力)がそのまま繰り返されるので、2つ目以降は入力し直しません。

diw・daw の内側と周りの違い

iwは単語そのもの、awは単語+隣の空白。diwは単語だけを消し、dawは前後の空白ごと消します。文の途中の単語を1つ抜くなら、dawのほうが余分な空白が残りません。単語をxで1文字ずつ消すのは、10文字なら10回。dawなら1回です。

掴める囲みの一覧

囲み系のテキストオブジェクトは、クオートと括弧をひととおりカバーしています。

  • iw / aw: 単語の内側 / 周り(空白込み)
  • i" / a", i' / a': クオートの内側 / クオート込み
  • i( / a(, i[, i{: 括弧の内側 / 括弧込み

関数呼び出しの引数を丸ごと替えるならci(。配列の中身ならci[。カーソルがどこにあっても「中身」を名指しできる。テキストオブジェクトが効くのはこの一点です。プロンプトにコマンド例やパスを貼って一部だけ直す作業で、いちばん差が出ます。

移動と組み合わせると1息になります。ggで入力の先頭へ戻り、f"で最初のクオートに飛んでci"。マウスにも矢印にも手を出さず、狙った引用符の中身をNORMALのまま打ち替えられます。

ビジュアルモードで範囲を選ぶ

どこからどこまで消すか、目で確かめてから操作したい。そういうときはビジュアルモードです。テキストオブジェクトが「意味のかたまり」を掴むのに対して、ビジュアルは範囲を手で伸ばします。

vとVで文字選択・行選択を切り替える

vで文字単位の選択を開始、Vで行まるごと。選択中にカーソルを動かすと範囲が伸び、そのままdyで操作します。選択の途中でvVを押し直せば、文字選択と行選択を切り替えられます。

選択して d・y・c・> で操作する

選択した範囲に対して、削除はd、ヤンクはy、変更はc、インデントは>~で大文字小文字の反転、Uで大文字化。oを押すと選択の起点と終点が入れ替わるので、選び始めと反対側を伸ばし直せます。

VISUAL LINE  ← 2行を選択中
docker compose up
docker compose logs -f

Vで2行選び>を押すと、選択範囲だけがまとめて1段インデントされます。複数行のプロンプトで手順の一部を字下げしたいとき、行ごとに>>を打たずに済みます。

Ctrl+Vの矩形選択は対象外

Vimの矩形選択(ブロックビジュアル)は使えません。公式ドキュメントも Block-wise visual mode with Ctrl+V is not supported と明記しています。列をまとめて編集したいときは、Ctrl+Vではなく、1行やってから.で繰り返す形で組み立てます。各行の頭に-を足すなら、1行目でIから- と打ってEsc、次の行へ移って.。行数ぶん.を押せば、同じ挿入が繰り返されます。

jjでNORMALに戻すremapと、その安全設計

INSERTから抜けるたびにEscへ手を伸ばすと、ホームポジションが崩れます。この往復を減らすのがvimInsertModeRemaps。押さえておきたいのは仕様そのものより、どこに書けるかという制限のほうです。

vimInsertModeRemapsでjjをEscにする

2文字の連続入力をEscに割り当てます。定番はjj

{
  "editorMode": "vim",
  "vimInsertModeRemaps": { "jj": "<Esc>" }
}

INSERTモードでjを素早く2回打つと、2文字とも残らずNORMALへ戻ります。この設定はv2.1.208以降が必要です。挙動には1秒の判定窓があり、1文字目のjはいったん表示され、1秒以内に2文字目が来ればNORMALへ。間が空けば両方ただの文字として残ります。jjを含む単語も、途中で一拍おけば普通に打てます。公式の「Remap INSERT-mode key sequences」によると、キーは印字可能な2文字ちょうど、割り当て先は"<Esc>"だけ。長さや対象が違うエントリは無視されます。

プロジェクトのsettings.jsonでは効かない

この設定を読むのは、ユーザー設定ファイルと--settingsフラグ、管理者設定だけ。プロジェクトの.claude/settings.json.claude/settings.local.jsonに書いても無視されます。理由は、チェックアウトしたリポジトリに他人のキー入力を書き換えさせないため。cloneしてきたコードにvimInsertModeRemapsを仕込んでも、あなたのjjが別の動作に化けることはありません。キーバインド系の設定をプロジェクト側で拾わないのは、この手の乗っ取りを塞ぐ設計だと読めます。

Vimモードが変えないもの

Vimモードが効くのはプロンプトの入力欄まで。Claudeがファイルを読み書きする方法も、コード生成の中身も変わりません。公式ドキュメントは守備範囲を Vim mode handles input at the text input level ... while Keybindings handle actions at the component level と分けています。カーソル移動やモード切り替えはVim、todoの表示切り替えや送信はキーバインド側の担当です。

もう1点。VimモードでのEscはINSERTからNORMALへの切り替えに使われ、Claudeへの割り込みは起こしません。生成を止めたいのに止まらないときは、モード表示がNORMALになっていないか見てください。入力欄まわりの見た目を含めて手を入れたいなら、Claude Code statuslineの仕組みにステータス行の自作をまとめています。

まとめ

Vimモードは、Claude Codeの入力欄をモード付きの編集体系に置き換える設定です。長いプロンプトの手直しで、カーソル移動と削除の往復が縮みます。慣れるまでは左下のNORMALINSERTの表示が頼り。INSERTのつもりでNORMALのまま打つと、文字がそのままコマンドとして走ります。表示を見る癖がつくまでの保険です。

  • 有効化は/configのEditor mode、固定は~/.claude/settings.jsoneditorMode
  • 移動はhjklwbf、編集はdwcwci"daw
  • テキストオブジェクトはカーソル位置を問わず、囲みの内側と周りを掴む
  • ビジュアルはvVCtrl+Vの矩形選択は未対応
  • vimInsertModeRemapsjj→Escはユーザー設定でだけ有効(v2.1.208以降)
  • 効くのは入力欄だけで、ファイル編集とコード生成は変わらない
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次