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を追加しています。標準の検索と自分の追加設定が似た名前で並び、役割を決めないまま片方だけ使っていました。
キー表は私のLazyVim設定です。<leader>sGと検索中のAltキーは独自設定。標準の<leader>sGは作業ディレクトリのgrepで、Telescopeが開くとは限りません。
grepと置換に必要なrgは:!rg --versionで確認できます。0件なら検索先と絞り込みも見ます。通常はignore対象や隠しファイルを外すので、0件でも文字列がないとは限りません。
以下の画面は、UI検証用プロジェクトenterprise-ui-labのTypeScriptコードをWSL2上のNeovimで開いたものです。プロジェクトのルートから開いて検索の使い方を撮影し、置換だけは一時コピーで試しています。
ファイル名を覚えているなら、ノーマルモードでSpace、f、fを押し、検索欄へOrdersTableと入れます。Ctrl+j / Ctrl+kで候補を選び、Enterで開く。やめる時はEscです。Snacksは入力モードからEscで候補選択へ移り、もう一度Escで閉じます。

普段はSnacksの<leader>sgを使う
関数名、画面の文言、エラーメッセージなどを探す時は<leader>sgを最初の入口にします。プロジェクトのルートからripgrepで検索し、候補とプレビューを同じ画面で確認できます。
例えば、金額の表示処理を調べるならformatAmountと入れます。ファイル名ではなく、その文字列を含む行が候補になります。まだ正確な関数名が分からない時は、画面の文言から入口を探す使い方もできます。
今の設定では、Snacksの検索画面にAlt+tとAlt+gも追加しています。LazyVimではSnacksがすでに設定されているため、require("snacks").setup()をもう一度呼ぶのではなく、lua/plugins/に置くfolke/snacks.nvimのspecへoptsを追加します。
Altキーで検索語の後ろへ条件を足す設定です。検索画面を受け取る処理はactionsへ置き、入力欄のキーから名前で呼び出します。ライブ検索欄の更新にはinput:set(nil, 検索文字列)を使い、検索語と引数の間に--を入れます。
return {
{
"folke/snacks.nvim",
opts = {
picker = {
sources = {
grep = {
actions = {
insert_type = function(picker)
local text = picker.input:get()
local suffix = text:find(" -- ", 1, true) and " -t " or " -- -t "
picker.input:set(nil, text .. suffix)
end,
insert_glob = function(picker)
local text = picker.input:get()
local suffix = text:find(" -- ", 1, true) and " -g " or " -- -g "
picker.input:set(nil, text .. suffix)
end,
},
win = {
input = {
keys = {
["<M-t>"] = { "insert_type", mode = "i", desc = "Insert -t args" },
["<M-g>"] = { "insert_glob", mode = "i", desc = "Insert -g args" },
},
},
},
},
},
},
},
},
}
検索欄にformatAmountを入れた後、Alt+tを押し、続けてtsと入力するとformatAmount -- -t tsになります。tsはripgrepのファイルタイプ名で、.tsと.tsxの両方が対象です。名前は:!rg --type-listで確認できます。

さらにAlt+gを押し、**/v3/**と入力すると、条件はformatAmount -- -t ts -g **/v3/**になります。**はディレクトリの階層をまたぐ指定で、ここではパスにv3があるファイルだけを探します。

普段の検索はSnacksのまま、必要になった時だけ対象を絞ります。Snacksの--は検索語と引数を分ける区切りで、次のTelescopeとは入力が違います。
引数を組み立てたい時だけ<leader>sGへ切り替える
Telescopeでは、ノーマルモードでSpace、s、Shift+gを押し、開いた検索欄へ文字を入力します。rgコマンドをターミナルへ打つ操作ではありません。検索語の後ろに、ファイルタイプや検索先の指定も書ける画面です。公式READMEの入力例を、同じformatAmountで試しました。
Space sGをTelescopeへ割り当てる設定
lua/plugins/のspecで、既存のSnacks定義へkeysを統合します。標準の同じキーもSnacks側にあるため、Telescope側と二重にキーを登録しない形です。TelescopeとLive Grep Argsも必要です。すでに同じプラグインのspecがあれば、追加ファイルへ重複させず既存定義へ統合します。
return {
{
"folke/snacks.nvim",
keys = {
{
"<leader>sG",
function()
require("telescope").extensions.live_grep_args.live_grep_args()
end,
desc = "Live Grep (Telescope Args)",
},
},
},
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-telescope/telescope-live-grep-args.nvim" },
opts = function(_, opts)
local actions = require("telescope-live-grep-args.actions")
opts.extensions = opts.extensions or {}
opts.extensions.live_grep_args = {
auto_quoting = true,
mappings = {
i = {
["<C-k>"] = actions.quote_prompt(),
["<M-t>"] = actions.quote_prompt({ postfix = " -t " }),
["<M-i>"] = actions.quote_prompt({ postfix = " --iglob " }),
},
},
}
end,
config = function(_, opts)
require("telescope").setup(opts)
require("telescope").load_extension("live_grep_args")
end,
},
}
現在の設定では次のキーを使えます。
| 検索画面内のキー | 入力するもの |
|---|---|
Ctrl+k(<C-k>) |
現在の検索語を引用符で囲む |
Alt+t(<M-t>) |
検索語を引用符で囲み、-tを追加する |
Alt+i(<M-i>) |
検索語を引用符で囲み、--iglobを追加する |
まずformatAmountと入れ、Alt+tを押してからtsと入力します。検索欄は次の形になります。
"formatAmount" -t ts
最初の"formatAmount"が検索語、その後の-t tsが「TypeScriptだけ」という条件です。引用符で囲むのは、検索語と条件を分けて渡すため。検索欄に引用符そのものも表示されます。

v3だけを探す時は、いったん検索欄を空に戻し、formatAmount → Alt+i → **/v3/**と入れます。
"formatAmount" --iglob **/v3/**
--iglobはファイルのパスをパターンで絞る指定で、パスの大文字・小文字を区別しません。この例ではv3ディレクトリ内の一致行が残ります。

フォルダーが分かっているなら、もっと直接指定できます。formatAmount → Ctrl+k → src/libと入力すると、検索欄は次の形です。
"formatAmount" src/lib

追加条件をそのまま入力する例も、同じ検索欄です。
| 検索欄に入れる文字 | 探す対象 |
|---|---|
"formatAmount" -t ts --iglob **/v3/** |
TypeScriptかつv3内 |
"formatAmount" tests |
testsフォルダー内 |
"formatAmount" --no-ignore src/lib |
src/lib内。ignore指定で外れたファイルも対象にする |
--no-ignoreは.gitignoreなどによる除外を無効にします。node_modulesなどまで広げないよう、検索先を付けて使います。隠しファイルは別の条件なので、それも含める時は--hiddenを追加します。
引用符を忘れてformatAmount -t tsと入れると、私の設定では全体が検索語になり、絞り込みの指定として渡りません。auto_quotingが有効なためです。最初の語だけをCtrl+kで引用してから条件を足すか、上の入力例を引用符ごと入れます。条件を含む欄へAltキーを繰り返すより、引用した語の後ろへ必要な条件を手で足すほうが分かりやすいです。
候補は下矢印 / 上矢印で選び、Enterで開きます。Telescopeの入力中は、私のCtrl+kが引用用になっています。Escでノーマルモードへ移ればj / kで選び、そこからもう一度Escで閉じられます。
毎回ここから始めると、検索語よりオプションを考える時間が増えます。<leader>sGは、普通のgrepでは対象が広すぎた時の二手目です。
目の前の単語なら<leader>sw、コードの関係ならLSPを使う
カーソル下の関数名や型名を、設定ファイルやドキュメントも含めて文字列検索したい時は<leader>swを使います。選択範囲をそのまま検索することもできます。
OrdersTable.tsxでformatAmountへカーソルを置き、Space、s、wを押すと、その単語の一致行が出た状態でSnacksが開きます。手入力を省く入口です。

一方、定義や参照の関係が欲しい時はgrepではなくLSPです。ただし、次のキーは開いているファイルへLSPが接続し、その操作を言語サーバーが提供している時に使えます。言語やサーバーによって使える範囲は同じではありません。
| キー | 確認するもの | 必要なLSP機能 |
|---|---|---|
gd |
定義 | 定義ジャンプ |
gr |
参照元 | 参照検索 |
gI |
interfaceなどの実装 | 実装検索 |
gy |
型定義 | 型定義検索 |
gai |
呼び出し元 | Call HierarchyのIncoming Calls |
gao |
呼び出し先 | Call HierarchyのOutgoing Calls |
gyはg、yと順に押すキーです。私のWSL設定でOrdersTable.tsxを開き、TypeScript用のvtslsが接続すると、gyを含むLSPキーが現れました。テキストだけのバッファでは現れません。gを押した時のwhich-keyも、開いているファイルの状態によって変わります。

見つからない時は、まず調べるコードのファイルを開き、:set filetype?で言語を確認し、<leader>clでそのバッファへのLSP接続を見ます。接続がなければgyを探すより、言語サーバーの起動を先に確認します。接続していても、型定義の結果があるかはサーバーとカーソル位置によります。gaiとgaoはCall Hierarchyに対応する時だけ、そのバッファにキーが作られます。
例えばOrdersTable.tsxの変数orderでgyを押すと、今回の画面ではtypes.tsのOrder型へ移動しました。formatAmountの上なら、gdで関数の定義、grで参照元を調べます。grは文字列の一致とは違い、接続したLSPが返すコード上の参照です。

ファイルの中で関数名から移動したい時は<leader>ss、プロジェクト全体の名前から探す時は<leader>sSを使います。それぞれドキュメントシンボルとワークスペースシンボルに対応するLSPが必要です。
ss・sSの画面と使い方
OrdersTable.tsxを開いてSpace、s、s。現在のファイルにある関数・型・変数などが並びます。OrdersTableと入力して絞り、候補を選んでEnterで移動します。

Space、s、Shift+sでプロジェクト全体のシンボル検索を開き、formatAmountと入力します。今回のvtslsではsrc/lib/format.tsの関数が候補になりました。

私がよくやるのは、検索で対象ファイルへ飛び、gdで定義を開き、grで使われ方を見る流れです。深く移動した後はCtrl+oで戻ります。
grepは文字が一致する場所を探します。LSPは言語としての定義や参照を探します。同じ関数名を探す場合でも、設定やテストデータまで見たいならgrep、コード上の関係だけを追いたいならLSPです。
置換まで進む時は<leader>srで検索をやり直す
検索して読むだけならSnacksかTelescopeで終わります。複数ファイルを変更したい時は、結果を見つけた後に<leader>srでGrug-farを開きます。
私の設定では、現在開いているファイルに拡張子がある場合、同じ拡張子を対象ファイルの初期値にしています。
次は、既存の<leader>srのキー定義にあるコールバック関数へ組み込む部分の抜粋です。
local ext = vim.fn.expand("%:e")
require("grug-far").open({
transient = true,
prefills = {
filesFilter = ext ~= "" and "*." .. ext or nil,
},
})
Grug-farの公式READMEでは、ripgrepまたはast-grepによる検索・置換、差分表示、Quickfixへの出力などが案内されています。
例えばOrdersTable.tsxを開いている時に起動すれば、まず*.tsxが対象になります。検索結果と置換後の差分を確認してから反映できるため、変更範囲を把握しやすくなります。
このキーは前の検索語を引き継ぎません。次は一時コピーでformatAmountをformatCurrencyへ置き換える説明用の入力例です。関数名を実際に変えるなら、定義・import・参照の整合も確認する必要があり、この範囲だけでリネームが完成するわけではありません。
- Space、s、rで開き、Searchに
formatAmount、ReplaceにformatCurrencyを入れる。 - Files Filterの
*.tsxを確認し、Pathsにsrc/features/orders/v3を入れて範囲を絞る。各入力欄は矢印キーや、ノーマルモードのj/kで移動し、iで入力する。 - ファイル名と差分を見る。ここはプレビューで、まだファイルは変わらない。
- ノーマルモードでReplaceを実行する。既定の
<localleader>rはSpaceの<leader>とは別。画面上部のキー表示も見る。

Replaceは対象ファイルへ保存します。直前の版を残し、反映後はgit diffなどで確認します。戻すならその版を使い、既存の変更まで消さないようにします。同じ語を含む別の処理も確認が必要です。
私がまず試す検索の順番
新しいキーを全部覚えるのはやめました。次の順番だけをチートシートへ残しています。
- ファイル名を覚えているなら
<leader>ff - 内容から探すなら
<leader>sg - 目の前の単語を広げるなら
<leader>sw - 条件を細かく付けるなら
<leader>sG - 置換まで行うなら
<leader>sr - コードの関係は
gd、gr、gI - 迷ったら
<leader>?でチートシートを開く
これまでは<leader>sGしか使っていませんでした。まずはsg、複数の条件をまとめて渡すならsG、変更するならsr。この三段階で使います。
ターミナルからプロジェクトへ入り、Neovimで検索するまでの全体像はAIにコードを書かせた後、rg・fzf・Yazi・Neovimで読む、LSPの実行経路はNeovimのLSPが動かない原因はプラグインではなくPATHだったへ書いています。
確認した公式情報
確認日: 2026年10月14日
- Snacks Picker:Pickerの情報源、grep、非同期処理
- Snacksの入力API:ライブ検索の
input:set(pattern, search) - SnacksのPickerアクション:名前付きアクションへ検索画面を渡す処理
- LazyVimのSnacks Picker設定:ルートと作業ディレクトリを使い分ける標準キー
- Telescope Live Grep Args:ripgrep引数付き検索と入力例
- Grug-far.nvim:検索・置換、差分表示、Quickfix出力
- ripgrep公式ガイド:ignore対象・隠しファイルの扱い、ファイルタイプとglob
- Telescope.nvim:組み込みPickerと基本設定

コメント