実践Vim 第二部・第三部: 何となくVimを使っていた自分が見落としていたファイル操作とナビゲーション
はじめに
前回の記事では、実践Vimの第一部「モード」から、何となくVimを使っていた私が見落としていたテクニックをまとめました。
今回は第二部「ファイル」と第三部「スピードアップ」から、ファイル操作、検索、ナビゲーションなど、私が見落としていたテクニック、日々のコーディングをより効率化する機能を中心にまとめました。
第二部: ファイル
第6章: 複数ファイルの管理
💭 バッファとファイルの違い
自分たちの仕事の仕方について話をするときには、あるファイルを編集しているかのようによくいうけれども、実際にやっているのはそうじゃない。そうじゃなくて、ファイルのインメモリ表現を編集しているのだ。Vimの用語ではこれを バッファ と呼ぶ。
重要なポイント:編集中の内容はメモリ上にあり、:wするまでファイルは変更されない
vim file.txt " ファイルをメモリに読み込んで編集開始
" 編集中...(この間ファイルは変更されていない)
:q! " 編集を破棄して終了(ファイルは元のまま)
:w " メモリの内容をファイルに保存
この理解があると、同じファイルを複数ウィンドウで開いても実体は1つのバッファであることや、:lsで見えるのがメモリ上のバッファ一覧であることが腑に落ちます。
🔧 引数リストの活用
つまり、:args が表示するリストは、エディタの起動時に vim コマンドに渡された値を必ずしも反映しないということだ。
引数リストは起動後も動的に変更可能で、複数ファイルの一括操作に使えます。
基本的な使い方:
:args src/**/*.tsx " srcディレクトリの全TSXファイルを引数リストに設定
:args " 現在の引数リストを表示
実践例:一括置換
:args **/*.js " プロジェクト内のすべてのJSファイルを引数リストに
:argdo %s/var /const /g " 全ファイルで var を const に置換
:argdo update " 変更されたファイルを保存
第7章: ファイルのオープンとディスクへの保存
🔧 存在しないディレクトリへのファイル保存
新しいディレクトリ構造でファイルを作成する時、ディレクトリが存在しないとエラーになります。
:edit src/components/ui/Button.tsx " ディレクトリが存在しない場合
:w " エラー: No such file or directory
解決方法:
:!mkdir -p %:h " 現在のファイルのディレクトリを作成
:w " 保存
-
%:h- 現在のファイルのディレクトリパス -
mkdir -p- 中間ディレクトリも含めて作成
第三部: スピードアップ!
第8章: モーションによるファイル内の移動
🔧 gjとgk - 表示行での移動
一方、 gj コマンドと gk コマンドは表示行を上下に移動する。
長い行が折り返されている時、論理行ではなく表示行で移動します。特にブログ記事やドキュメント執筆で役立ちます。
例:ブログ記事の編集
最近はClaude Codeなどでターミナルに触れる時間が増え、できるだけ作業をターミナルで完結させたいと思うようになりました。
この1つの論理行が画面幅で3行に折り返されている場合:
最近はClaude Codeなどでターミナルに | // j を押すと
触れる時間が増え、できるだけ作業を | // 次の段落へジャンプ
ターミナルで完結させたいと思うよう | // (この行全体をスキップ)
最近はClaude Codeなどでターミナルに | // gj を押すと
触れる時間が増え、できるだけ作業を | // ここへ移動
ターミナルで完結させたいと思うよう | // (表示行単位)
🔧 検索モーションの活用
検索コマンドはノーマルモードでしか使えないわけではない
ビジュアルモードやオペレータ待機モードでも検索が使えます。
d/pattern<CR> " patternまでを削除
v/end<CR> " "end"までをビジュアル選択
c/;<CR> " セミコロンまでを変更
d{motion}オペレータと検索モーションの組み合わせは、強力な移動手段となる。これを使って、友達や同僚をビックリさせよう
検索モーションの実践例:
const oldName = "value"; const newName = "other";
^カーソル位置
d/newName // "newName" の直前まで削除
// 結果: const newName = "other";
// 複数行にまたがる削除
if (condition) {
doSomething();
^カーソル位置
}
return result;
d/return // "return" の直前まで削除(中間の行も含む)
// 結果: return result;
🔧 自動マーク
Vimが自動的に設定してくれるマークは本当に便利だ
-
- 最後のジャンプ位置 -
'.- 最後の変更位置 -
'^- 最後の挿入位置 -
'[']- 最後の変更/ヤンクの開始と終了
第9章: ジャンプによるファイル間の移動
🔧 ジャンプリスト - Vimの「戻る」ボタン
<C-o>コマンドは[戻る]ボタンみたいなもので、これと対になる<C-i>コマンドは[進む]ボタンみたいなものだ
-
<C-o>- 前のジャンプ位置へ戻る -
<C-i>- 次のジャンプ位置へ進む -
:jumps- ジャンプリストを表示
ジャンプリストとは、編集セッションの間に、次々とファイルをオープンしていった足跡を簡単に戻っていけるようにするためのパンくずリストみたいなもの
🔧 gf - ファイルパスをハイパーリンクに
gfコマンドの動作原理を理解しておくことには価値がある。このコマンドは、ドキュメントに記述されている各ファイルパスがハイパーリンク的に振る舞うようにする
カーソル下のファイルパスを開きます。設定ファイルやimport文で特に便利です。
import { utils } from './utils/helper.js' // helper.jsにカーソルを置いてgf
特にLSPが効かない設定ファイルやMarkdownではgfが重宝します。
# docker-compose.yml
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
# nginx.confにカーソルを置いてgf
<!-- README.md -->
詳細は[設定ファイル](./docs/config.md)を参照
# config.mdでgf
💭 グローバルマークの習慣
:grep、:vimgrep、:make など、 quickfixリストを扱うコマンドを使うときには常に、その前にグローバルマークを設定するようなクセをつけよう
大規模な操作の前にmMなどでマークを設定しておけば、'Mですぐに戻れます。
なぜ大文字のM?
-
ma〜mz- ローカルマーク(ファイル内でのみ有効) -
mA〜mZ- グローバルマーク(ファイルをまたいで有効)
:grepや:vimgrepは複数ファイルを開くことが多いため、大文字のMでグローバルマークを設定します。
ファイル内の移動ならmmで十分です。例えば、同期レビューでドキュメントのテーブル定義とドメイン定義を行き来して整合性を確認する時など、mmでマークして'mで戻るという使い方をしています。ファイルをまたぐ可能性がある場合は大文字を使います。
個人的にはマークによる移動はNARUTOの飛雷針の術のような感覚があり特にお気に入りです。
マークを設定 = クナイを投げる
'mで戻る = 飛雷神でクナイの場所に瞬間移動
というイメージです。
まとめ
第二部・第三部で学んだ重要なポイント:
- ファイル操作の理解 - バッファとファイルの違いを理解する
-
効率的なナビゲーション - ジャンプリスト、マーク、
gfで素早く移動 - 検索の活用 - 検索をモーションとして使い、編集を効率化
これらのテクニックを使いこなすことで、複数ファイルにまたがる編集作業が効率化されます。
実践Vimには、まだまだ多くのテクニックが詰まっています。本記事では私の印象に残った部分を抜粋しましたが、興味を持たれた方はぜひ原書を手に取ってみてください。
参考
- 実践Vim 思考のスピードで編集しよう! - Drew Neil著、新丈径訳
おまけ:記事作成フロー
前回同様、以下のワークフローで作成しました:
- Kindleでハイライト - 第二部・第三部から実践的な内容をマーク
- Obsidianに取り込み - Kindle Highlightsプラグインで自動取得
- Claude Codeで構成 - Obsidian MCP でハイライトの内容を読み込み。第一部の記事構成を参考に、同じトーンで執筆。
- 実例の追加 - 実際のコーディングシーンを想定した例を追加
今回は3.の部分で Claude Code が前後の部、章を読み込んで記事を生成してしまい手戻りが発生してしまいました。kindle のlocation番号と目次を紐付けて再整理しましたが、Claude Codeのスラッシュコマンドなどで仕組み化したいと思いました。
Discussion