Neovimに行と全体のテキストオブジェクトが入る al と il
「この行の中身だけを消したい」「ファイルを丸ごと選びたい」という操作は毎日のように出てくるのに、Vimにはそれを一発で指すテキストオブジェクトがありませんでした。全体はggVG、行の中身は^vg_のように、移動キーを組み合わせて表現するのが普通です。Neovim 0.13では、ここにalとilという2つのテキストオブジェクトが追加されました。ciwやdi(と同じ書き味で、行と全体を扱えるようになります。
検証環境:nightlyビルドのNVIM v0.13.0-dev-1336+g8c0bf18374、安定版のNVIM v0.12.4、VIM 9.1(いずれもmacOS)で同じキー列を流しました。掲載しているレジスタとバッファの中身はすべて実行結果です。0.13は開発中なので、リリースまでに細部が変わる可能性があります。
| キー | これだけ覚える |
|---|---|
| al | all lines。バッファ全体を行単位で指す |
| il | inner line。前後の空白を除いた現在行を指す |
行の中身だけを、インデントを残して扱う
ilは前後の空白を含みません。 bbb という行(前に空白4つ、後ろに3つ)にカーソルを置いてyilすると、レジスタに入るのはbbbだけでした。
-- バッファ: aaa / " bbb " / ccc (2行目にカーソル)
yil レジスタ = bbb
dil バッファ = aaa / " " / ccc -- 空白だけが残る
gUil バッファ = aaa / " BBB " / ccc
dilで消えるのは中身だけで、インデントは残ります。ccでも似たことはできますが、あちらは挿入モードに入りますし、インデントが残るかどうかはautoindent次第です。dilはノーマルモードのまま、見えている空白をそのまま残します。中身を書き直したいならcilで、これはci(と同じ感覚で使えます。
ひとつ仕様として押さえておきたいのが、空白しかない行では失敗することです。 だけの行でdilを試したところ、バッファは変わりませんでした。ヘルプにも「空行や空白だけの行では失敗する」と明記されています。全部消したいならddを使う、という切り分けになります。
バッファ全体を1操作で指す
alはバッファ全体で、ビジュアルモードでは行単位になります。全体をコピーするyalと、全体を消すdalを実行すると、3行のバッファが空になりました。
yal レジスタ = aaa\n bbb \nccc\n -- 3行ぶん、行単位
dal バッファ = 空(1行)
従来のggVGや:%yと結果は同じですが、オペレータと組み合わせられるのが違いです。全体をインデントし直す=al、全体を大文字にするgUalのように、オペレータとモーションの組み合わせの枠にそのまま乗ります。カーソル位置を覚えておく必要がないのも地味に効きます。ggから始める書き方はカーソルが動くので、元の位置に戻るにはCtrl-oを押すかマークを打っておく必要がありました。
0.12とVimでは動かない
同じキー列を安定版のNeovim 0.12.4とVim 9.1で流すと、どちらも何も起きませんでした。レジスタは書き換わらず、バッファも変わりません。エラーが出ないので「効かない」ことに気づきにくいのが厄介なところです。
| 操作 | Vim 9.1 | Neovim 0.12.4 | Neovim 0.13 |
|---|---|---|---|
yil | 変化なし | 変化なし | 行の中身 |
yal | 変化なし | 変化なし | バッファ全体 |
両方を使い分けている場合、設定ファイルで補うこともできます。il相当の動きは、オペレータ待機モードのマッピングで近いものを作れます。
" Vimや0.12で il に近い動きを用意する
onoremap il :<C-u>normal! ^vg_<CR>
xnoremap il ^og_
ただし空白だけの行で失敗する挙動までは再現していないので、本物とまったく同じにはなりません。移行期のつなぎとして使うものです。
どこで効いてくるか
個人的にいちばん出番が多いのはcilです。設定ファイルの1行を書き直すとき、インデントを保ったまま中身だけ入れ替えられます。JSONやYAMLのように行頭の空白に意味があるファイルでは、0Dのようにインデントごと消す操作をしてしまうと直すのが面倒です。
2番目が=alで、ファイル全体のインデントを整え直すときに使います。gg=Gとの違いはカーソルが動かないことだけですが、その1点のためにCtrl-oを押していた手間が消えます。インデント操作をまとめてやり直す場面では手数が減ります。
最初に試したときは正直「ggVGで足りているのでは」と思っていました。考えが変わったのはcilのほうで、インデントの深いLuaの設定を書き直すときに手が止まらなくなりました。これまではccを押してからインデントが消えているかを目で確かめる癖がついていたので、その確認自体が不要になったのが大きいです。逆にハマったのが空白だけの行で、dilを押しても無反応なのを最初はキーの打ち間違いだと思い込みました。ヘルプを読んで仕様だと分かるまで数分かかっています。
まとめ
Neovim 0.13のalはバッファ全体、ilは前後の空白を除いた現在行を指すテキストオブジェクトです。dilならインデントを残したまま中身だけ消せ、yalや=alならカーソルを動かさずにファイル全体を対象にできます。空白だけの行でilが失敗する点と、Vim 9.1およびNeovim 0.12.4では無反応のまま何も起きない点だけ覚えておけば、あとはiwやi(と同じ感覚で使えます。ドット繰り返しの変更と合わせて、0.13は手が覚えている操作のほうに手を入れてくる更新です。