この記事は「Vimは最強!」という話ではありません。
私は長年Vimを使ってきましたが、今回は「コードを読むとき」に限った話をまとめてみます。
新卒で業務に入ったばかりの私にとって、Vimの操作感やナビゲーションは大きな助けになりました。
なぜコードリーディングは難しい?
実務でコードリーディングが難しいのは、自分で書いた小さなコードベースとは勝手が違うからです。そもそも、自分のプロジェクト内でさえ「このファイルどこに保存したっけ?」と迷うことがあります。それが他人が書いた大量のファイルがあるコードベースだと、なおさら追いかけるのが大変です。
さらに、大規模で抽象度が高いプロジェクトでは、処理が複数のファイルに分散していて、それらを効率よく行き来しながら理解する必要があります。こうした状況では、単純な「機能」よりも、思考の流れを止めずにコードを追えるかどうかが重要になります。
コードを読むときに自分が求めること
コードを読むときに自分が求めるのは、処理の流れや構造を追いながら理解することです。
大規模なプロジェクトでは、
- 必要な箇所に素早くジャンプできること
- どのファイルにどの処理があるのかを意識せずに追求できること
- 読んでいる間に思考の流れを止めないこと
が重要です。
ここでVimが便利になります。Vimは、この「操作を思考の単位にする」という感覚を自然にサポートしてくれます。他のIDEでも同じことはできますが、Vimの場合はキーボードが中心でほぼ瞬時に移動できるので、自分にとって読みやすさが段違いに感じられます。
単一ファイル内で構造を素早く把握する基本操作
例えば、Vue + TypeScriptでこんな簡単なコンポーネントがあったとします:
<!-- @/components/hello.vue -->
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { fetchUser } from '@/api/user';
const props = defineProps<{
userId: number;
}>();
const userName = ref<string>('');
onMounted(async () => {
const user = await fetchUser(props.userId);
userName.value = user.name;
});
</script>
<template>
<div>Hello, {{ userName }}!</div>
</template>
このコードを読んでいるときに、私が実際に行うVimの操作例はこんな感じです:
-
userNameがどこで使われているかを確認したい →userName上で*→ 次の出現箇所にジャンプ →Ctrl+oで元の場所に戻る -
onMountedブロック全体をざっと確認したい →{}でブロック単位を移動 - ファイル全体の構造を把握したい →
gg(先頭) /G(末尾)で移動 - 対応する括弧に飛びたい →
%(特に<template>や<script>のブロック移動に便利) - 行内で特定の文字までジャンプ →
f{char}(例:f(で次の括弧まで)
これらはすべて1〜2キーストロークで完結し、マウスに手を伸ばす必要がありません。こうした小さな操作を組み合わせるだけで、思考の流れをほとんど止めずにコードを追いかけられます。
複数ファイル間を迷わず移動:ctagsで定義元ジャンプ
単一ファイル内なら基本操作で十分ですが、大規模プロジェクトでは処理が複数のファイルに分散しています。ここで活躍するのがctags(正確にはuniversal-ctags)です。
プロジェクトルートで一度 ctags -R を実行するとtagsファイルが生成され、Vim内で以下の操作が可能になります:
- カーソル上のシンボルで
Ctrl-]→ 定義元に即ジャンプ(別ファイルでもOK) -
Ctrl-t→ ジャンプ元に戻る(ジャンプスタックで何度でも戻れる) -
g]→ 同名の定義が複数ある場合、一覧を表示 -
:ts {name}→ タグ検索で候補一覧を表示
先ほどのコンポーネントに加え、別ファイルapi.tsがあるとします:
// @/api/user.ts
export interface User {
id: number;
name: string;
}
export async function fetchUser(userId: number): Promise<User> {
// 実際のAPI呼び出し処理
return { id: userId, name: 'Alice' };
}
hello.vueコンポーネント内でfetchUserの上にカーソルを置いてCtrl-]を押せば、即api.tsの関数定義に飛びます。確認が終わったらCtrl-tで戻るだけ。これで複数ファイル間の行き来がストレスフリーになります。
Telescopeでさらにパワーアップ(ctagsでできないこと)
ctagsは「定義元ジャンプ」に非常に強いですが、「曖昧検索」や「参照箇所の全一覧」は苦手です。そこでTelescopeの出番です。
私がよく使うpickerは以下の通り:
- Live Grep → プロジェクト全体から文字列をリアルタイム検索
- Find Files → ファイル名であいまい検索
- LSP References / Symbols → カーソル下シンボルの参照箇所一覧やシンボル検索
例えば「userNameという文字列がどこで使われているか全部見たい」場合はLive Grepが圧倒的に速いです。ctagsは定義しか追えませんが、Telescopeは「参照」「文字列」「ファイル名」など多角的に探せます。
検索結果から直接ジャンプでき、もちろんCtrl-oで戻れるので、ctagsと組み合わせると最強のナビゲーション環境になります。
マークで「後でまた見る」を残す
コードを追っていると「この関数、後でもう一度見たい」と思うことがよくあります。そんなときにマークが便利です。
-
m{a-z}→ 小文字:ファイル内マーク -
m{A-Z}→ 大文字:グローバルマーク(別ファイル間でも有効) -
`{a-zA-Z}→ そのマークにジャンプ -
:marks→ マーク一覧を表示
複雑な処理の流れを追うときに、重要な場所をブックマークしておくと安心です。
まとめ
Vimがコードリーディングに向いていると感じる理由は、特定の機能が優れているからというより、操作の速さと、思考の流れを止めにくい点にあります。
Vim単体の基本操作だけでも十分にコードを追えますが、ctagsやTelescopeのようなツールを組み合わせることで、大規模なコードベースでも迷わず探索できるようになります。
エディタにはそれぞれ得意な使い方があり、環境や好みによって最適解は変わりますが、自分にとっては「まずコードを理解する」フェーズでVimの操作感がとても合っていました。
本記事が、コードリーディングのやり方やエディタ選びを考えるきっかけになれば幸いです。