Vimのテキスト編集コマンドって一見複雑なようで、実は難しいことは全然やってません。一度その仕組みがわかってしまえば、Ctrl 等プレフィクスキーを使う系のコマンドよりずっと分かりやすいと僕は思います。
オペレータとモーション
Vimのノーマルモードコマンドの多くは「オペレータ」+「モーション(もしくはテキストオブジェクト)」の組み合わせでできています。
- オペレータ:「何を(する)」を決めます。
- モーション:「どこに(する)」あるいは「どこに(行く)」を決めます。要は移動コマンドです。
これ伝わるか分かりませんが、RPGで技を打つ時ってまず技を選択してから → 技を当てる相手(範囲)を決めるじゃないですか。Vimのコマンドもあれと一緒で、オペレータで何をするか決めてから → オペレータを適用する範囲を決める。めっちゃシンプルな構造なんです。
コマンドは細分化して覚えること
Vimチートシート系の記事は大量のコマンドを手早くインプットするのに便利ですが、そういった記事では dG : ファイル末尾まで削除する
みたいな書き方をされていることがあります。
間違ってはいないんですが、このとき、「 dG
がファイル末尾まで削除するコマンドなんだ」と理解しないようにしてください。正しくは「 d
で削除の属性をのせられるんだ」「 G
でファイル末尾まで移動できるんだ(正確にはcount行に移動する)」です。このようにインプットしていけば、新しいモーション、例えば w
を新しく覚えたときに「dw
で次の単語まで削除できるんだ」ということも容易に想像できます。新しくオペレータを覚えた時も同様です。
ddとかccは?
上の話とつながりますが、比較的初期に覚えるであろう dd
とか cc
, yy
等についても同様です。これは「 dd
で現在行を削除する」というコマンドではなく「1つ目の d
で削除の属性をのせ、2つ目の d
でそれを現在行に適用する」というコマンドです。
Vimでは、モーションを入力する代わりにオペレータの最後の文字を繰り返すとそれを現在行に適用します。dd
, cc
, yy
, gUU
, ==
など全てこの法則に則っていますので、「 dd
で現在行を削除」「 yy
で現在行をコピー」とひとくくりに覚えないようにしてください。
優先して覚えるべきはモーション
で、上を理解していただいたところで、オペレータとモーションどっちを先にたくさん覚えればいいかと言ったらモーションです。というのは、日常的によく使うオペレータってそんなに種類がないからです。d
, c
, y
, <
, >
, =
くらいじゃないですか?あとはまあ gu
, gU
, g~
とか。
そういうわけで、意識的にインプットしていきたいのはモーション(と、テキストオブジェクト)です。モーションを覚えれば覚えるほど単純に移動が早くなりますし、最短効率でコマンドを打てるようになってきます。vimgolfのスコアも上がります。
テキストオブジェクトは?
めっちゃ大事です。
でもテキストオブジェクトってイメージ的にはモーションに a
か i
足すだけなんで、そんなに難しくありません。でもめっちゃ大事だし有能です。
いい感じのモーション
word
と WORD
Vimでは w
, b
, e
, ge
で移動する一区切りのことを word
と呼び、 W
, B
, E
, gE
で移動する一区切りのことを WORD
と呼んでそれぞれ区別しています。
分かりやすいのは WORD
単位の移動で、これは単純に空白文字(スペース)を基準に移動します。人間の目にも自然と「区切り」として映る単位なので、初心者にも分かりやすいと思います。
WORD
をさらに細かく区切っているのが word
です。word
は英字、数字、アンダースコアが連続したもの、または記号が連続したものを基準とします。アンダースコアでは区切られないし大文字小文字の区別もしないため、キャメルケースやスネークケースの中では人間の思い通りに動かないことも多いです(これを解消するにはCamelCaseMotionプラグインなどが有用)。word
に関しては、w
, b
, e
, ge
を使うときに移動先を予想しつつ移動する練習をすると上達が早くなると思います。
word
と WORD
の違いはテキストオブジェクトにも関連するため必ず使いこなせるようにしておきましょう。「 WORD
のなかに word
がある」と考えるとイメージしやすいんじゃないかなと。
f
と t
f
と t
も非常につよつよなモーションです。どちらも横方向にのみ動作する検索だと思えばいいでしょう。
f
は直後に押した文字を右方向に検索します。fb
なら、右方向にある最初のbにカーソルを合わせます。F
はその逆。直後に押した文字を左方向に検索し、最初に出会った検索結果にカーソルを合わせます。
t
は f
とよく似ていますが、 f
が検索結果にカーソルを合わせるのに対して t
は検索結果の一つ手前で止まります。tp
なら、右側で最初に出会ったpの一つ左側で止まります。T
はやはりその逆で、左側で出会った検索結果の一つ右側で止まります。
;
と ,
も覚えておきましょう。;
は最後に使ったf
, F
, t
, T
を繰り返します。fg;;;
とすれば、「右側のg、次のg,次のg,次のg,,,」と進んでいけます。,
は、最後に使ったf
, F
, t
, T
を裏返して使います。例えば fy
を記憶していたなら ,
は Fy
と同義になります。
この f
, F
, t
, T
もモーションですから、当然オペレータと組み合わせられることを覚えておきましょう。
{
と }
、テキストオブジェクト ap
, ip
これも便利です。上下方向に大きく移動したい時って C-d
, C-u
, C-f
, C-b
を使う人が多いかもしれませんが、それだとオペレータと組み合わせられないんですよね。あといっぱい動きすぎるのでコードがいまいち頭に入ってこない。
そこで、いい塩梅の上下移動として {
と }
をオススメします。{
は上方向の空行、 }
は下方向の空行に移動します。 {
と }
なら、オペレータと組み合わせて d}
などとすることも可能です。
テキストオブジェクト ip
, ap
は空行を区切りとするので {
, }
と感覚的にはほぼ同じように使えます。dap
とか便利ですね。
検索
検索の /
も、実はオペレータと組み合わせて使えます。
「/
で検索して確定した後はヒットした部分のうち一番左の文字に移動する」ことを意識しておくとうまく使えるでしょう。
/
を移動用のコマンドとして考えて頻繁に使うのは結構オススメです(f
の強化版みたいな)。
行頭と行末
行頭・行末の移動でよく使われるのは 0
, ^
, $
ですね。ただしこいつらは押しにくいのが難点です(特に$
)。
なので僕は行頭移動に _
、行末移動に g_
を使っています。_
, g_
はcountを指定しなければそれぞれ現在行の最初と最後の非空白文字に移動してくれます。実質的に ^
, $
と同じ動きです。個人的にはこっちの方が押しやすいし、他のキーも潰さないので結構お気に入りです。
ただし _
, g_
はそのままだとオペレータの後に使っても現在行ごと削除したりしてしまうので注意してください。気になるなら、もうキーマッピングで完全に ^
, $
に寄せてしまうのもありだと思います。
モーションやテキストオブジェクトの範囲がわかりづらい?
慣れないうちはそう思いがちかも。
そういう時は v
でビジュアルモードに入ってからモーションやテキストオブジェクトを打ってみましょう。一目瞭然です。
ちなみにビジュアルモードの場合オペレータを打った時点で即座に変更が適用されますが、この理解には冒頭の話を思い出してください。
これ伝わるか分かりませんが、RPGで技を打つ時ってまず技を選択してから → 技を当てる相手(範囲)を決めるじゃないですか。Vimのコマンドもあれと一緒で、オペレータで何をするか決めてから → オペレータを適用する範囲を決める。めっちゃシンプルな構造なんです。
ノーマルモード時はまさに上の通りなんですが、ビジュアルモードではすでに有効範囲が選択されている状態です。ノーマールモードでは「技→有効範囲」の順に決定していましたが、ビジュアルモードではその逆、「有効範囲→技」の順に決定しているというわけです。
さらにモーションを覚えるなら
motion - Vim日本語ドキュメントに全て書いてあります。目指せ1日1モーション。