Vimのマクロで複雑な繰り返し作業を自動化する
同じ形の修正を10行、20行と繰り返す作業は、手打ちだとミスも増えますし飽きます。.コマンドでは対応できない複数ステップの操作は、マクロに記録してしまうのが早いです。
目次(10項目)
| キー | これだけ覚える |
|---|---|
| qa 〜 q | レジスタaへ操作を記録 |
| @a | 記録した操作を実行 |
| 10@a | 10回まとめて実行 |
| @@ | 直前に実行したマクロをもう一度 |
記録・実行・確認の基本
qa " レジスタaへの記録を開始
... " 記録したい操作
q " 記録終了
@a " レジスタaの内容を実行
10@a " 10回実行
@@ " 直前に実行したマクロをもう一度
記録中は画面の隅に「記録中」の表示が出ます。記録した内容はレジスタとして保存されているので、:registers(省略形:reg)で中身を確認できます。マクロの正体は「名前付きレジスタに記録したキー入力を、あとから再生する」仕組みにすぎません。
3@a で3回再生したところマクロを編集する
記録し損ねた1手を直したいときは、いちいち録り直さなくても中身を直接編集できます。
"ap " レジスタaの内容をバッファに貼り付け
(貼り付けた内容を編集)
"ay " 編集後の内容をレジスタaへ再格納(ビジュアル選択してヤンク)
貼り付け、編集、選択してヤンクし直す、という3ステップでマクロの中身を書き換えられます。録り直すより早いことが多いです。
実行開始位置に依存させない
マクロを複数行に適用するとき、想定と違う位置で崩れることがあります。原因の多くは「カーソルが特定の位置にある前提」で記録してしまっていることです。マクロの先頭で行頭や行末に移動する操作を入れておくと、多少カーソル位置がずれていても安定して動きます。
よく使う具体例
行末にセミコロンを追加して次の行へ移動するマクロは、コードの整形でよく使います。Aで行末からインサートモードに入り、;を打って<Esc>でノーマルモードに戻り、jで次の行へ移動します。
let a = 1
let b = 2
let c = 3
2@a
let a = 1; let b = 2; let c = 3;
これをqa〜qで記録しておけば、対象の行数だけN@aで一気に処理できます。
複数ファイルへまとめて適用する
記録したマクロは1つのファイルだけでなく、開いている複数のファイルに一気に適用することもできます。:bufdoと組み合わせれば、同じ修正をファイル横断でまとめて実行できます。
:bufdo normal! @a
この場合はファイルごとにカーソル位置が異なるため、マクロの先頭で行頭移動などを入れて開始位置に依存しない記録にしておく重要性がさらに増します。windo/bufdo/tabdoそのものの使い分けは別記事にまとめています。
最初は記録に失敗するたびに録り直していましたが、レジスタの中身を直接編集できると知ってからは無駄なやり直しがかなり減りました。特にマクロの途中に1手足したいだけのときに、毎回最初から録り直すのは時間の無駄だったと今は感じます。
回数を数えずに最後まで流す
マクロは、途中のコマンドが失敗した時点で再生を止めます。f, で探した文字が行に無ければそこで止まる、という具合です。この性質を使うと、対象が何行あるかを数えずに済みます。
1000@a " 対象が尽きた時点で自然に止まる
数え間違いで足りなくなることも、行き過ぎて余計な行まで処理することもありません。そのためには、手順の中に「見つからなければ失敗する」コマンドを入れておくことが条件になります。f や n がその役割を果たします。
逆に j だけで次の行へ移る手順は、ファイルの末尾に着いても失敗しないので止まりません。末尾を越えたぶんは何も起きないだけですが、余計な変更が積まれることもあるので、止まる条件を1つ入れておくほうが安全です。
よく使うマクロを設定ファイルに残す
レジスタの中身は文字列なので、設定ファイルに直接書いておけます。毎回記録し直している手順があるなら、この形で持っておくと起動した瞬間から使えます。
let @s = 'A;\j' " 行末にセミコロンを足して次の行へ
特殊キーは \<Esc> のように書きます。ダブルクォートで囲んだ文字列の中でしか展開されないので、シングルクォートで書く場合は実際の制御文字を入れることになります。読みにくくなるので、複雑なものは記録して "sp で貼り出し、書式を確かめてから移すほうが確実です。
再生が遅いとき
数百行にマクロをかけると、1回ごとに画面が描き直されて時間がかかります。set lazyredraw を入れておくと、マクロの実行中は描画を省くようになり、体感でかなり速くなります。
set lazyredraw
それでも遅い場合は、そもそもマクロが向いていない可能性があります。行の条件で対象が決まるなら :g、文字列の置き換えなら :%s のほうが一度に処理できます。マクロが向くのは、複数の操作にまたがっていて条件では書き表せない手順です。グローバルコマンドで書けないかを先に考えると、待ち時間を減らせます。
まとめ
マクロは複数ステップの操作を繰り返すための機能で、実体はレジスタへのキー入力の記録です。編集も応用もレジスタの仕組みを理解していれば難しくありません。まずは行末への文字追加のような単純な作業から試すと感覚をつかみやすいです。1回だけの単純な繰り返しなら、マクロを組むより.のほうが手軽です。記録した内容はレジスタに入るので、名前付きレジスタの扱いを知っておくと保存や使い回しがしやすくなります。
ここで扱ったキーは、ブラウザ上で動くVim道場の操作を記録して繰り返すでそのまま試せます。インストールもログインも要りません。