Neovimに検索機能を3つ入れたのに、Space sGしか使っていなかった

VS Codeだけでコードを読んでいた頃、特にやりづらかったのが検索でした。結果を待ち、対象ファイルを開き、定義や呼び出し先を確認して、また検索へ戻る。この往復に引っかかりを感じていました。

Neovimへ移ってからは<Space>sGで検索しています。rgを使っているつもりはなかったのですが、いつものキーの裏でripgrepが動いていました。私の環境ではレスポンスに不満はありません。しかし設定を調べ直すと、Snacks Picker、Telescope Live Grep Args、Grug-farの3つが入っていました。それでも、実際に使っていたのは<Space>sGだけです。

一つの検索画面ですべてを済ませるのではなく、普段の検索、複数のripgrep引数を組み立てる検索、置換で入口を分けることにしました。まず使うのはSnacksの<Space>sg、引用・除外・検索先をまとめて指定したい時はTelescopeの<Space>sG、複数ファイルを置換する時はGrug-farの<Space>srです。小文字のsgはSpace、s、g。大文字のsGはSpace、s、Shift+gです。

設定を増やす前に、すでにあるキーを確認した

現在の設定には、次の検索キーがありました。<leader>はSpaceキーです。

キー 役割 実体
<leader>ff ファイル名から探す Snacks Picker
<leader>sg プロジェクト全体を文字列検索 Snacks Picker + ripgrep
<leader>sG 引数付きで文字列検索 Telescope Live Grep Args + ripgrep
<leader>sw カーソル下の単語・選択範囲を検索 Snacks Picker + ripgrep
<leader>ss 現在のファイル内のシンボル(対応するLSP接続中) LSP + Snacks Picker
<leader>sS ワークスペース全体のシンボル(対応するLSP接続中) LSP + Snacks Picker
<leader>sr 検索結果を見ながら置換 Grug-far + ripgrep

SnacksのPicker公式ドキュメントには、ファイル、grep、バッファ、LSPシンボルなどの検索元が並んでいます。私のLazyVim設定では標準の検索入口がSnacksになっていました。

一方、<leader>sGには自分でTelescope Live Grep Argsを追加しています。標準の検索と自分の追加設定が似た名前で並び、役割を決めないまま片方だけ使っていました。

普段はSnacksの<leader>sgを使う

関数名、画面の文言、エラーメッセージなどを探す時は<leader>sgを最初の入口にします。プロジェクトのルートからripgrepで検索し、候補とプレビューを同じ画面で確認できます。

例えば、APIの認証処理を調べるならauthorizeやエラーメッセージをそのまま入れます。まだ正確な関数名が分からない時は、まず文字列から入口を見つけます。

今の設定では、Snacksの検索画面にAlt+tAlt+gも追加しています。LazyVimではSnacksがすでに設定されているため、require("snacks").setup()をもう一度呼ぶのではなく、lua/plugins/に置くfolke/snacks.nvimのspecへoptsを追加します。実際の設定では、ripgrepへ渡す引数との区切り--が未入力なら自動で補います。

return {
  {
    "folke/snacks.nvim",
    opts = {
      picker = {
        sources = {
          grep = {
            win = {
              input = {
                keys = {
                  ["<M-t>"] = {
                    function(picker)
                      local text = picker.input:get()
                      local suffix = text:find(" -- ", 1, true) and " -t " or " -- -t "
                      picker.input:set(text .. suffix)
                    end,
                    mode = "i",
                    desc = "Insert -t args",
                  },
                  ["<M-g>"] = {
                    function(picker)
                      local text = picker.input:get()
                      local suffix = text:find(" -- ", 1, true) and " -g " or " -- -g "
                      picker.input:set(text .. suffix)
                    end,
                    mode = "i",
                    desc = "Insert -g args",
                  },
                },
              },
            },
          },
        },
      },
    },
  },
}

Alt+tでripgrepのファイルタイプ、Alt+gでglobを入力できます。普段の検索はSnacksのまま、必要になった時だけ対象を絞れます。

引数を組み立てたい時だけ<leader>sGへ切り替える

Telescope Live Grep Argsは、検索欄へripgrepの引数も入力できます。公式READMEには、引用符で囲んだ語句、--no-ignore--iglob、検索対象ディレクトリなどの例があります。

現在の設定では次のキーを使えます。

検索画面内のキー 入力するもの
<C-k> 現在の検索語を引用符で囲む
<M-t> -tを追加する
<M-i> --iglobを追加する

例えばC#だけを対象にするなら、次のような検索です。

"CreateOrder" -t cs

テストディレクトリだけを探すなら、次のように絞れます。

"CreateOrder" --iglob **/test/**

毎回ここから始めると、検索語よりオプションを考える時間が増えます。<leader>sGは、普通のgrepでは対象が広すぎた時の二手目です。

目の前の単語なら<leader>sw、コードの関係ならLSPを使う

カーソル下の関数名や型名を、設定ファイルやドキュメントも含めて文字列検索したい時は<leader>swを使います。選択範囲をそのまま検索することもできます。

一方、定義や参照の関係が欲しい時はgrepではなくLSPです。ただし、次のキーは開いているファイルへLSPが接続し、その操作を言語サーバーが提供している時に使えます。言語やサーバーによって使える範囲は同じではありません。

キー 確認するもの 必要なLSP機能
gd 定義 定義ジャンプ
gr 参照元 参照検索
gI interfaceなどの実装 実装検索
gy 型定義 型定義検索
gai 呼び出し元 Call HierarchyのIncoming Calls
gao 呼び出し先 Call HierarchyのOutgoing Calls

現在のLazyVimでは、特にgaigaoは対応するCall Hierarchy機能がある時だけ、そのバッファにキーが作られます。キーが見当たらない時は設定漏れと決めつけず、接続中のLSPがその機能に対応しているかを確認します。<leader>ss<leader>sSも、それぞれドキュメントシンボルとワークスペースシンボルに対応するLSPが必要です。

私がよくやるのは、検索で対象ファイルへ飛び、gdで定義を開き、grで使われ方を見る流れです。深く移動した後はCtrl+oで戻ります。

grepは文字が一致する場所を探します。LSPは言語としての定義や参照を探します。同じ関数名を探す場合でも、設定やテストデータまで見たいならgrep、コード上の関係だけを追いたいならLSPです。

置換まで進む時は<leader>srで検索をやり直す

検索して読むだけならSnacksかTelescopeで終わります。複数ファイルを変更したい時は、結果を見つけた後に<leader>srでGrug-farを開きます。

私の設定では、現在開いているファイルに拡張子がある場合、同じ拡張子を対象ファイルの初期値にしています。

local ext = vim.fn.expand("%:e")

require("grug-far").open({
  prefills = {
    filesFilter = ext ~= "" and "*." .. ext or nil,
  },
})

Grug-farの公式READMEでは、ripgrepまたはast-grepによる検索・置換、差分表示、Quickfixへの出力などが案内されています。

例えばC#ファイルを開いている時に起動すれば、まず*.csが対象になります。検索結果と置換後の差分を確認してから反映できるため、プロジェクト全体へいきなり置換コマンドを実行するより、変更範囲を把握しやすくなります。

私がまず試す検索の順番

新しいキーを全部覚えるのはやめました。次の順番だけをチートシートへ残しています。

  1. ファイル名を覚えているなら<leader>ff
  2. 内容から探すなら<leader>sg
  3. 目の前の単語を広げるなら<leader>sw
  4. 条件を細かく付けるなら<leader>sG
  5. 置換まで行うなら<leader>sr
  6. コードの関係はgdgrgI
  7. 迷ったら<leader>?でチートシートを開く

これまでは<leader>sGしか使っていませんでした。まずはsg、複数の条件をまとめて渡すならsG、変更するならsr。この三段階で使います。

ターミナルからプロジェクトへ入り、Neovimで検索するまでの全体像はAIにコードを書かせた後、rg・fzf・Yazi・Neovimで読む、LSPの実行経路はNeovimのLSPが動かない原因はプラグインではなくPATHだったへ書いています。

確認した公式情報

確認日: 2026年9月15日

コメント

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