【入門編】Vimのテキストオブジェクトを自作して『操作対象』を拡張する:Luaによるカスタムテキストオブジェクトの定義 – 軽量・高機能テキストエディタ生産性向上バイブル

Vimの「その先」へ:Luaで定義するカスタムテキストオブジェクトが、コーディングの景色を一変させる

こんにちは。開発環境という「思考の拡張デバイス」を極めようとするあなたへ。

VimやNeovimを使っていると、`ciw`(単語を変更)や`cit`(タグの中身を変更)といった「テキストオブジェクト」の魔法に一度は魅了されるはずです。しかし、中級者の壁にぶつかるのは「なぜ、俺のプロジェクト特有のこのデータ構造や、この特殊な括弧をVimは認識してくれないのか?」と気づいた瞬間です。

今日は、既存の機能に甘んじるのをやめ、「自分のコーディング対象をVimに直接理解させる」という、エンジニアとしての特権階級的なテクニックを伝授します。

—

1. なぜ「テキストオブジェクト」を自作するのか?

Vimの真の力は「操作の動詞(`c`, `d`, `y`)」と「操作対象(テキストオブジェクト)」を自由に組み合わせられることにあります。

標準のテキストオブジェクトは「単語」「段落」「引用符」といった汎用的なものに限られます。しかし、実務では以下のようなニーズが必ず生まれます。

  • 「`{{ … }}`で囲まれたテンプレート変数だけを瞬時に削除したい」
  • 「特定の関数呼び出しの引数全体を、構造を壊さずに切り取りたい」
  • 「独自フォーマットのログ行を、意味の塊として操作したい」

これらを自作すれば、カーソル移動という「物理的な労働」から解放され、コードの「意味的な構造」を直接操作する領域へシフトできます。これは単なる効率化ではなく、脳内の思考を直接コードに転写する体験です。

—

2. 実装の設計思想:カーソルから「範囲」を計算する

Neovim(Lua)でテキストオブジェクトを自作する際、本質的なロジックは非常にシンプルです。

1. 開始点を見つける: 現在のカーソル位置から後方へ検索し、オブジェクトの開始マークを探す。
2. 終了点を見つける: 現在のカーソル位置から前方へ検索し、オブジェクトの終了マークを探す。
3. Vimに伝える: 決定した範囲を「視覚的選択範囲(Visual Mode)」としてVimに通知する。

これだけで、`d` や `c` といったコマンドが自動的にその範囲を対象とするようになります。

—

3. HelloWorld:`{{ … }}` を操作対象にする

まずは、テンプレートエンジンなどでよく使われる `{{ … }}` を囲むテキストオブジェクト `iq` (Inner Quoteの変種として)を定義してみましょう。

以下のコードを、あなたの `init.lua` またはプラグイン読み込み用ファイルに記述してください。

— カスタム関数: {{ … }} の中身を特定する
local function select_double_braces()
— 現在の行を取得
local line = vim.api.nvim_get_current_line()
local col = vim.api.nvim_win_get_cursor(0)[2] + 1

— 正規表現で {{ と }} の位置を探索
— 簡易的な実装:現在のカーソル位置を含む {{…}} を探す
local s, e = line:find(“{{.-}}”, 1)
if s == nil then return end

— ビジュアルモードの開始点と終了点を設定 (Vimのインデックスは1始まり)
— ‘v’ で開始、範囲を指定して ‘o’ で選択を確定
vim.api.nvim_buf_set_mark(0, ‘<', 0, s + 1, {}) -- 開始点マーク vim.api.nvim_buf_set_mark(0, '>‘, 0, e – 2, {}) — 終了点マーク
vim.cmd(‘normal! v’) — ビジュアルモードへ遷移
end

— キーマッピングの定義: ‘iq’ で実行
— は関数を即時評価するために重要
vim.keymap.set({‘o’, ‘x’}, ‘iq’, select_double_braces, { desc = “Select inside {{ }}” })

このコードがやっていることの解説

  • `vim.api.nvim_buf_set_mark(0, ‘<', ...)`: これがこの技術の核心です。Vim内部の「選択範囲レジスタ」をプログラムから直接操作しています。
  • `{‘o’, ‘x’}`: `o`はオペレーター待機モード(`d`や`c`を押した直後)、`x`はビジュアルモードを指します。これにより、`diq`(中身を削除)や`viq`(中身を選択)の両方が即座に使えるようになります。

—

4. 現場で震えるほど役立つ運用ルール

この実装をさらに実用的にするために、以下の3つの原則を守ってください。

1. 正規表現を欲張らない: 複雑なネスト構造(`{{ {{ … }} }}`)を正規表現で解こうとすると、Vimの動作が重くなります。複雑な構造は `treesitter` というライブラリのAST(抽象構文木)を利用するのがモダンな最適解です。
2. エラーハンドリングを怠らない: カーソルがオブジェクトの外にあるときに発火した場合、何もしない(あるいは通知を出す)ようにガード節を入れましょう。
3. マッピングの競合を避ける: `i` や `a` で始まるキーは標準のオブジェクトで埋まっています。自分専用の接頭辞(例: `i` の代わりに `g` を使うなど)をルール化しておくと、設定が衝突しません。

—

最後に:ツールに合わせるのではなく、ツールを自分に合わせる

多くの開発者は、IDEが用意した「便利な機能」の範囲内でしかコードを書けません。しかし、Vim/Neovimを愛するあなたは、自分の思考の速度に合わせてエディタを再構築できる立場にあります。

まずは今日紹介した `iq` を動かしてみてください。そして、日頃「あ、またこの括弧を手動で消してるな…」と思った瞬間、その操作を自作テキストオブジェクトに昇華させるのです。

それが、エンジニアとしてのあなたの「環境構築力」となり、1年後には他人が数分かけて行うリファクタリングを、あなたは数秒で完了させているはずです。

さあ、あなたのNeovimを、世界で唯一の最強の武器へと進化させましょう。質問があれば、いつでも聞いてくださいね。

タイトルとURLをコピーしました