爆速Fuzzy FinderプラグインSnacks.pickerの使い方
snacks.nvimにあるFuzzy Finderプラグインpickerの設定方法や使い方を紹介します。

Snacksとは?
snacks.nvimは便利プラグインが詰め込まれたプラグイン集です。イメージとしてはmini.nvimに近いです。
この記事で紹介する「picker」の他、「ダッシュボード」「スクラッチバッファ」「lazygitとの連携」など20以上の機能があります。
全部知りたい人はREADMEを見るのがオススメです。
pickerとは?
SnacksのpickerはFuzzy Finderプラグインです。
近いプラグインを挙げるとtelescope.nvimなどがあります。毎月Fuzzy Finderプラグインの産声が聞こえるのは気のせいでしょうか。
pickerはビルトインで使える絞り込みが多いです。2025年2月時点では40以上あります。
「複数選択」「横に開く(vsplit)」「quickfixで開く」「レイアウトを変更する」など、さまざまな操作ができるキーマップも簡単に設定できます。
Snacksのpickerは非同期にファイル検索・マッチ処理をしてくれるため、めっちゃ速い&スムーズです。
fzfのSearch syntaxもサポートされてます。
導入方法
folke/snacks.nvim各々が使っているプラグインマネージャーでインストールします。
インストール
lazy.nvimだと次のように書いてインストールできます。
return { "folke/snacks.nvim", priority = 1000, lazy = false, ---@type snacks.Config opts = {},}遅延読み込みせずに優先度をあげて早めに読み込むことが推奨されています。
遅延読み込み大好き人間にとっては心配かもしれませんが、snacks本体のsetupはautocmdの定義ぐらいで、全部の機能を読み込んでしまうわけではありません。
依存プラグイン
依存プラグインはありません。
アイコンを表示させたい人はmini.iconsかnvim-web-deviconsのどちらかを入れておきましょう。
最低限の設定
最低限のプラグインの設定はsetupを呼び出すだけで完了です。
require('snacks').setup()lazy.nvimの場合、setupの中身はoptsに書くためこの記述は不要です。この書き方について知りたい人は別の記事「lazy.nvimの使い方から起動を爆速にする方法までを解説」を読んでください。
pickerの基本的な使い方
さくっと使い方を紹介します。カスタマイズは後で説明します。
snacksはrequireの他、グローバル変数Snacksから呼び出すこともできます。
require("snacks.picker").buffers()Snacks.picker.buffers()この記事では面倒なので次のようにpicker.〇〇()と書きます。
local picker = require("snacks.picker")picker.buffers()ピッカーのキーマップの一覧
ピッカーを開くと挿入モードになっています。
まずはEscでノーマルモードにしてから?を入力し、キーマップのヘルプを開いてみましょう。

画面の下に、pickerで使えるデフォルトのキーマップが表示されます。
あるいは:help snacks-picker-configでデフォルトの設定を見てみましょう(長いけども)。
バッファ一覧
picker.buffers()バッファの一覧では、見た目がそのまま表示されます。

winbarやsigncolumn、diagnosticsなどがそのまま表示され、まるでスクショみたいです。
ノーマルモードに切り替えてddを入力するとバッファを削除できます。
ファイル系
みんな大好きファイルピッカーもあります。

picker.git_files()picker.files()picker.recent()files()ではfd・rg・findのコマンドを自動で見つけて使ってくれるようです。
recentは最近開いたファイルです。
smart
picker.smart()smartを実行すると、buffers・recent・filesの結果を重複を削除して一覧にしてくれます。
バッファならプレビューがbuffersのときと同じようになります。
エクスプローラー
ファイルの一覧をツリーでみたいならexplorerを使います。
picker.explorer()
ファイルの移動や削除もできるようです。詳しくは?を入力するか:help snacks-picker-sources-explorerでデフォルトのキーマップを見てみましょう。
grep
grepもあります。
picker.grep()実装を見てみると、内部で叩かれるコマンドはripgrepのようです。
LSP系
LSP関係のピッカーも用意されています。よく使いそうなのは次の2つでしょうか。
picker.lsp_references()picker.lsp_definitions()Vim・Neovim関係
これもたくさんあるのでよく使いそうなやつを。
ヘルプ
picker.help()ヘルプの一覧です。遅延読み込みのプラグインでも表示されます。
プレビューも表示されるので便利です。
keymaps
picker.keymaps()定義されているキーマップの一覧です。

luaの関数で定義した場合、そのファイルがプレビューされて分かりやすいです。
highlights
picker.highlights()highlightsはハイライトして表示されます。

colorschemes
picker.colorschemes()colorschemesはカーソル行のカラースキームがすぐに適用されるため、何度もピッカーを開かなくていいですね。

TODOコメント検索
todo-comments.nvimを使っている場合、TODOコメントを検索可能です。
picker.todo_comments()
ピッカーのピッカー
ビルトインのピッカーが40以上あるため、全部にキーマップを設定するのは大変ですし覚えられません。
使用頻度が少ないものはキーマップをセットせず、ピッカーのピッカーから呼びましょう。
picker.pickers()ピッカーの一覧が表示され、選んだピッカー実行されます。

直前のピッカーを呼び出す
直前に閉じたピッカーをもう一度表示するにはresumeを使います。
picker.resume()Snacks.pickerのカスタマイズ例
ピッカーの紹介はこれぐらいにして、ここからは実際に筆者が使っているカスタマイズの例を解説します。
レイアウトを変えたい
レイアウトの種類を変える場合はlayout.presetに書きます。
require("snacks").setup({ picker = { layout = { cycle = true, --- Use the default layout or vertical if the window is too narrow preset = function() return vim.o.columns >= 120 and "default" or "vertical" end, }, }})ピッカー毎に変更したいならpicker.〇〇の引数に渡してあげましょう。これはレイアウトに限らず、キーマップなど他の設定でも同様です。
次はfilesのレイアウトをverticalにする例です。
picker.files({ layout = { preset = "vertical", layout = { width = 0.9 } }})レイアウトの値を調整したいだけなら次のようにlayouts(複数形)の方に書きます。
require("snacks").setup({ picker = { layouts = { default = { layout = { width = 0.95 } }, }, }})上記は、デフォルトのレイアウトの幅を変更しています。
キーマップを変えたい
デフォルトのキーマップを変えるなら、picker.win.input.keysに書きます。
require("snacks").setup({ picker = { win = { input = { keys = { -- select allを無効化 ["<c-a>"] = false, ["<c-b>"] = false, ["<c-d>"] = { "preview_scroll_down", mode = { "i", "n" } }, ["<c-f>"] = false, ["<c-u>"] = { "preview_scroll_up", mode = { "i", "n" } }, ["<c-s>"] = false, ["<c-x>"] = { "edit_split", mode = { "i", "n" } }, }, }, }, }})無効化するならfalseを指定します。
パスの省略表記を変更したい
デフォルトではファイル名が40文字以上だと、パスの一部が省略されます。これを変更したい場合はtruncateを変えます。
require("snacks").setup({ picker = { formatters = { file = { truncate = 200 } }, }})visualモードなら選択テキストを検索ワードにしたい
「visualモードでピッカーを起動したら選択テキストを検索ワードにする方法」を紹介します。
まずは選択テキストを取得する関数を定義。
local function get_text() local visual = picker.util.visual() return visual and visual.text or ""endこの関数はpickerを立ち上げる前に呼びます。
filesやgit_filesならpatternに渡します。
local text = get_text()picker.files({ pattern = text })picker.git_files({ pattern = text })grepならon_showで挿入します。
local text = get_text()picker.grep({ on_show = function() vim.api.nvim_put({ text }, "c", true, true) end,})git_filesで未追跡ファイルも表示
デフォルトのpicker.git_files()は、ステージングに上げてないファイルは非表示です。
未追跡でも表示したい場合はuntrackedを指定します。
picker.git_files({ untracked = true })dotfilesのpicker
dotfilesの一覧を出したいなら次のようにcwdを変更します。
picker.git_files({ cwd = '~/dotfiles' })Gitを使っているか気にしないファイル検索
いちいち「カレントディレクトリがGit管理下なのか」を意識するのは面倒です。
そこで、カレントディレクトリがGitを使っていればgit_files、使っていないならfilesを呼んでくれるキーマップを定義します。
local function project_files() local text = get_text()
local root = require("snacks.git").get_root() if root == nil then picker.files({ pattern = text }) return end picker.git_files({ untracked = true, pattern = text, })end先ほど定義したget_textをここでも使っています。
モノレポ対応
前述のproject_filesをモノレポでも使いやすくします。
次のようなリポジトリを例にします。
./awesome├── .git├── packages│ ├── project-1 # カレントディレクトリ│ └── project-2「カレントディレクトリ(project-1)だけを検索対象にしたい」「リポジトリ全体を検索対象にしたい」という2つのケースが出てくると思います。
これに対応するのが次の定義です。
---@param use_git_root boolean git_rootを使うかどうか。モノレポの個別プロジェクトならfalselocal function project_files(use_git_root) local text = get_text()
local root = require("snacks.git").get_root() if root == nil then picker.files({ pattern = text }) return end if use_git_root then picker.git_files({ untracked = true, pattern = text, }) else picker.git_files({ untracked = true, pattern = text, cwd = vim.uv.cwd(), }) endendproject_files(false)ならカレントディレクトリだけを検索対象にします。
筆者は次のようにlazy.nvimのkeysで定義して使ってます。
{ "<space>ff", function() project_files(false) end, mode = { "n", "x" }, desc = "モノレポでプロジェクト毎"},{ "<space>fF", function() project_files(true) end, mode = { "n", "x" }, desc = "モノレポでプロジェクト全体"},通常は<space>ffで検索し、モノレポ構成でリポジトリ全体を見たいときに<space>fFを使います。
オリジナルのピッカーを作る
ここからはオリジナルのピッカーの作り方を解説します。
同階層のファイルだけを検索
同階層のファイルだけを検索するピッカーを作りました。Angularのような同階層のファイル間を行き来するプロジェクトで重宝しています。
今まではpicker.〇〇を使っていましたが、今度はpicker()に直接引数を渡します。
先に実装の全体を載せます。次の項目から小分けにして解説します。
picker({ finder = "proc", cmd = "find", args = { vim.fn.expand("%:h"), "-type", "f", "-not", "-name", vim.fn.expand("%:t") }, ---@param item snacks.picker.finder.Item transform = function(item) item.file = item.text end,})finderをprocにする
finderをprocにすると外部コマンドを呼べます。cmdにコマンド名、引数はargsにテーブルとして渡します。
picker({ finder = "proc", cmd = "find", args = { vim.fn.expand("%:h"), "-type", "f", "-not", "-name", vim.fn.expand("%:t") }, -- ...})-not -name ……を引数に渡すことで、現在カーソルがあるファイルは一覧から省けます。
transformとは
コマンドの実行結果をピッカーで扱えるように変換する処理をtransformに書きます。
transform = function(item) item.file = item.textend,findの出力結果はただのファイル名のみであるため、item.file = item.textを指定します。
find src/pages/foo/foo-buz -maxdepth 1 -type f -not -name 'foo-buz.html'src/pages/foo/foo-buz/foo-buz.scsssrc/pages/foo/foo-buz/foo-buz.tssrc/pages/foo/foo-buz/foo-buz.module.tsファイル以外のピッカーを作る
ファイル以外を扱うピッカーは、finderにsnacks.picker.Item[]型を返す関数を書きます。
ここでは選んだアイテムを通知するだけの簡単なピッカーを例に挙げます。

先に実装の全体を載せます。次の項目から小分けにして解説します。
picker({ finder = function() local my_list = { { quote = "選ばれるのは私よ!", thanks = "ありがとうなのだわ!" }, { quote = "うるさいんですけどぉ〜", thanks = "別にありがとうとか思ってないんだからね!" }, { quote = "ちっす", thanks = "どうも" }, } ---@type snacks.picker.Item[] local items = {} for i, person in ipairs(my_list) do ---@type snacks.picker.Item local item = { idx = i, score = 0, text = person.quote, thanks = person.thanks, } table.insert(items, item) end return items end, ---@type snacks.picker.Action.spec confirm = function(the_picker, item) the_picker:close() vim.notify(item.thanks) end, format = "text", preview = "none", layout = { preset = "vscode" },})finderでリストを返す
finderの中身を見てみましょう。
local my_list = { { quote = "選ばれるのは私よ!", thanks = "ありがとうなのだわ!" }, { quote = "うるさいんですけどぉ〜", thanks = "別にありがとうとか思ってないんだからね!", }, { quote = "ちっす", thanks = "どうも" },}---@type snacks.picker.Item[]local items = {}for i, person in ipairs(my_list) do ---@type snacks.picker.Item local item = { idx = i, score = 0, text = person.quote, thanks = person.thanks, } table.insert(items, item)endreturn itemsピッカーに渡すItemはidx・score・textが必須です。thanksのように独自のキーも追加できます。
confirm
confirmには、アイテムを選択したときに実行する処理を書きます。
---@type snacks.picker.Action.specconfirm = function(the_picker, item) the_picker:close() vim.notify(item.thanks)end,残りのキー
残りのキーは見た目に関するものです。
{ -- ... format = "text", preview = "none", layout = { preset = "vscode" },}text-case.nvimをSnacksに対応させる
text-case.nvimはテキストをPascalCaseやsnake_caseに変更してくれるプラグインです。
これをpickerで選んで実行できるようにしました。

長いので折りたたみの中に書きました。
設定例(クリックで開きます)
require("textcase").setup({})local plugin = require("textcase.plugin.plugin")local picker = require("snacks.picker")local constants = require("textcase.shared.constants")local api = require("textcase").apilocal api_list = { api.to_upper_case, api.to_lower_case, api.to_snake_case, api.to_dash_case, api.to_title_dash_case, api.to_constant_case, api.to_dot_case, api.to_comma_case, api.to_phrase_case, api.to_camel_case, api.to_pascal_case, api.to_title_case, api.to_path_case,}
---@param mode string---@return snacks.picker.Item[]local function create_items(mode) ---@type snacks.picker.Item[] local items = {}
---@type { prefix: string, type: string }[] local conversion_dict = {} if mode ~= "n" then table.insert(conversion_dict, { prefix = "Convert to ", type = constants.change_type.VISUAL }) else table.insert(conversion_dict, { prefix = "Convert to ", type = constants.change_type.CURRENT_WORD }) table.insert(conversion_dict, { prefix = "Lsp rename ", type = constants.change_type.LSP_RENAME }) end
local i = 1 for _, conversion in pairs(conversion_dict) do for _, method in pairs(api_list) do ---@type snacks.picker.Item local item = { idx = i, score = 0, text = conversion.prefix .. method.desc, method_name = method.method_name, type = conversion.type, } table.insert(items, item) i = i + 1 end end return itemsend
---@type snacks.picker.Action.speclocal function invoke_replacement(the_picker, item) the_picker:close() if item.type == constants.change_type.CURRENT_WORD then plugin.current_word(item.method_name) elseif item.type == constants.change_type.LSP_RENAME then plugin.lsp_rename(item.method_name) elseif item.type == constants.change_type.VISUAL then plugin.visual(item.method_name) endend
vim.keymap.set({ "n", "v" }, "gt", function() local mode = vim.api.nvim_get_mode().mode picker({ finder = function() return create_items(mode) end, confirm = invoke_replacement, format = "text", preview = "none", layout = { preset = "vscode" }, })end, { desc = "Picker: textcase" })end,以上、snacks.nvimのpickerの紹介でした。めちゃくちゃ便利!