From fce59322a73383731c5b2254a1665ac1f5931533 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Thu, 13 Aug 2026 20:55:26 -0400 Subject: [PATCH] =?UTF-8?q?feat(plugins):=20add=20two=E2=80=91stage=20find?= =?UTF-8?q?=E2=80=91by=E2=80=91extension=20command=20with=20e=20short?= =?UTF-8?q?cut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/plugins/astrocore.lua | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lua/plugins/astrocore.lua b/lua/plugins/astrocore.lua index 5d74eef..97c9d7c 100644 --- a/lua/plugins/astrocore.lua +++ b/lua/plugins/astrocore.lua @@ -18,6 +18,54 @@ local function with_trouble(source, opts) require("snacks").picker[source](opts) end +-- e: two-stage find-by-extension. Stage 1 scans the repo with fd +-- (respects .gitignore) and shows every file extension ranked by count; +-- stage 2 opens the regular files picker restricted to the chosen +-- extension (snacks passes `ft` to fd as `-e`). +local function find_files_by_extension() + local snacks = require "snacks" + local root = snacks.git.get_root() or vim.uv.cwd() + local files = vim.fn.systemlist { "fd", "--type", "f", "--base-directory", root } + if vim.v.shell_error ~= 0 then + vim.notify("fd failed to list files in " .. root, vim.log.levels.ERROR) + return + end + local counts = {} + for _, path in ipairs(files) do + -- last dot of the basename; skips dotfiles (.gitignore) and bare names + local ext = path:match "[^/]%.([%w_%-]+)$" + if ext then counts[ext] = (counts[ext] or 0) + 1 end + end + local items = {} + for ext, count in pairs(counts) do + items[#items + 1] = { text = ext, ext = ext, count = count } + end + if #items == 0 then + vim.notify("No file extensions found in " .. root, vim.log.levels.WARN) + return + end + table.sort(items, function(a, b) + if a.count ~= b.count then return a.count > b.count end + return a.ext < b.ext + end) + snacks.picker { + title = "File Extensions", + layout = { preset = "select" }, + items = items, + format = function(item) + return { + { ("%-12s"):format(item.ext), "SnacksPickerLabel" }, + { ("%d file%s"):format(item.count, item.count == 1 and "" or "s"), "SnacksPickerComment" }, + } + end, + confirm = function(picker, item) + picker:close() + if not item then return end + snacks.picker.files { cwd = root, ft = item.ext, transform = file_filter } + end, + } +end + return { "AstroNvim/astrocore", ---@type AstroCoreOpts @@ -230,6 +278,10 @@ return { function() require("snacks").picker.files { transform = file_filter } end, desc = "Find files (cwd)", }, + ["e"] = { + find_files_by_extension, + desc = "Find files by extension", + }, [""] = { function() require("snacks").picker.lsp_symbols { layout = { preset = "vscode", preview = "main" } }