2026-05-29 18:35:10 -04:00
|
|
|
--- Shared ignore patterns for file explorers and pickers
|
|
|
|
|
--- This module provides a centralized list of patterns to ignore across
|
2026-08-14 18:42:51 -04:00
|
|
|
--- snacks.picker and other file browsing tools. (`patterns` and the
|
|
|
|
|
--- `never_show` lists are also handed to neo-tree's `filtered_items`, see
|
|
|
|
|
--- plugins/neotree.lua.)
|
2026-07-11 18:46:47 -04:00
|
|
|
---
|
|
|
|
|
--- Everything here is fast-event-context safe (pure Lua + libuv only):
|
|
|
|
|
--- snacks picker transforms run inside async/uv callbacks where vimL
|
|
|
|
|
--- functions (vim.fn.*) raise E5560.
|
2026-05-29 18:35:10 -04:00
|
|
|
--- @module config.ignore_patterns
|
|
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
local uv = vim.uv or vim.loop
|
|
|
|
|
|
2026-05-29 18:35:10 -04:00
|
|
|
local M = {}
|
|
|
|
|
|
|
|
|
|
--- Core ignore patterns used across the configuration
|
2026-07-11 18:46:47 -04:00
|
|
|
--- These patterns use glob syntax (* and ? wildcards), matched against
|
|
|
|
|
--- file basenames and individual path segments.
|
2026-05-29 18:35:10 -04:00
|
|
|
M.patterns = {
|
|
|
|
|
-- Build artifacts and generated files
|
2026-07-05 16:56:46 -04:00
|
|
|
".beads",
|
2026-05-29 18:35:10 -04:00
|
|
|
"chain_*.json",
|
|
|
|
|
".npmrc",
|
2026-06-11 10:55:56 -04:00
|
|
|
".epiq",
|
2026-05-29 18:35:10 -04:00
|
|
|
".omc",
|
|
|
|
|
".claude",
|
|
|
|
|
".changeset",
|
|
|
|
|
".codegraph",
|
|
|
|
|
".gitignore",
|
|
|
|
|
"turbo.json",
|
|
|
|
|
"vite.config.ts",
|
|
|
|
|
"bunfig.toml",
|
|
|
|
|
"*.pb.go",
|
|
|
|
|
"*.pkl.go",
|
|
|
|
|
"*.pulsar.go",
|
|
|
|
|
"*.pb.gorm.go",
|
|
|
|
|
"*.pb.gw.go",
|
|
|
|
|
"*_templ.go",
|
|
|
|
|
"*_mock.go",
|
|
|
|
|
"*_integration.go",
|
|
|
|
|
"*_test.go",
|
|
|
|
|
"AGENTS.md",
|
|
|
|
|
"test",
|
|
|
|
|
"tests",
|
|
|
|
|
|
|
|
|
|
-- Configuration files
|
|
|
|
|
".editorconfig",
|
|
|
|
|
".gitpod.*",
|
|
|
|
|
|
|
|
|
|
-- Lock files and dependencies
|
|
|
|
|
"*.lock",
|
|
|
|
|
"*.lockb",
|
|
|
|
|
"*.sum",
|
|
|
|
|
"*.work.*",
|
|
|
|
|
"package-lock.json",
|
|
|
|
|
"pnpm-lock.yaml",
|
|
|
|
|
".gitattributes",
|
|
|
|
|
".oxlintrc.json",
|
|
|
|
|
"tsconfig*",
|
|
|
|
|
|
|
|
|
|
-- Temporary and cache files
|
|
|
|
|
"*.tmp",
|
|
|
|
|
".typecopy",
|
|
|
|
|
".python-version",
|
|
|
|
|
".prettierrc",
|
|
|
|
|
".trunk",
|
|
|
|
|
".config",
|
|
|
|
|
".pkl-lsp",
|
|
|
|
|
".tsbuildinfo",
|
|
|
|
|
".wrangler",
|
|
|
|
|
".parcel-cache",
|
|
|
|
|
".conform*",
|
|
|
|
|
".null-ls_*",
|
|
|
|
|
|
|
|
|
|
-- Binary and media files
|
|
|
|
|
"*.wasm",
|
|
|
|
|
"*.png",
|
|
|
|
|
"*.jpg",
|
|
|
|
|
"*.icns",
|
|
|
|
|
"*.ico",
|
|
|
|
|
|
|
|
|
|
-- Directories and special files
|
|
|
|
|
"contrib",
|
|
|
|
|
"interchaintest",
|
|
|
|
|
"PULL_REQUEST_TEMPLATE.md",
|
|
|
|
|
"Icon?",
|
|
|
|
|
"iCloud~",
|
|
|
|
|
"com~",
|
2026-09-22 14:14:01 -04:00
|
|
|
".githooks",
|
2026-05-29 18:35:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
--- Patterns that should never be shown in any file browser
|
|
|
|
|
M.never_show = {
|
|
|
|
|
-- Version control
|
|
|
|
|
".git",
|
|
|
|
|
".ai",
|
2026-06-28 13:54:50 -04:00
|
|
|
".omc",
|
2026-05-29 18:35:10 -04:00
|
|
|
|
|
|
|
|
-- Dependencies
|
|
|
|
|
"node_modules",
|
|
|
|
|
".wrangler",
|
|
|
|
|
"CODEOWNERS",
|
|
|
|
|
".golangci.yml",
|
|
|
|
|
|
|
|
|
|
-- Build outputs
|
|
|
|
|
".next",
|
|
|
|
|
".parcel-cache",
|
|
|
|
|
|
|
|
|
|
-- Task runners and tools
|
|
|
|
|
".task",
|
|
|
|
|
".devbox",
|
|
|
|
|
".turbo",
|
|
|
|
|
".jj",
|
|
|
|
|
".spawn",
|
|
|
|
|
|
|
|
|
|
-- IDE and editor
|
|
|
|
|
".idea",
|
|
|
|
|
".venv",
|
|
|
|
|
".metadata",
|
|
|
|
|
".dart_tool",
|
|
|
|
|
".devcontainer",
|
|
|
|
|
|
|
|
|
|
-- Build tools
|
|
|
|
|
".gradle",
|
|
|
|
|
"gradle.bat",
|
|
|
|
|
"heighliner",
|
|
|
|
|
|
|
|
|
|
-- Temporary
|
|
|
|
|
".tmp",
|
|
|
|
|
"tmp",
|
|
|
|
|
|
|
|
|
|
-- Logs
|
|
|
|
|
"sonr.log",
|
|
|
|
|
"junit.xml",
|
|
|
|
|
|
|
|
|
|
-- macOS
|
|
|
|
|
".DS_Store",
|
|
|
|
|
".DocumentRevisions-V100",
|
|
|
|
|
".Spotlight-V100",
|
|
|
|
|
".TemporaryItems",
|
|
|
|
|
".Trashes",
|
|
|
|
|
".fseventsd",
|
|
|
|
|
".timemachine",
|
|
|
|
|
|
|
|
|
|
-- Templates
|
|
|
|
|
"DISCUSSION_TEMPLATE",
|
|
|
|
|
"ISSUE_TEMPLATE",
|
|
|
|
|
|
|
|
|
|
-- License
|
|
|
|
|
"LICENSE",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
--- Patterns that should never be shown (pattern matching)
|
|
|
|
|
M.never_show_patterns = {
|
2026-10-16 11:08:32 -04:00
|
|
|
".crush",
|
2026-05-29 18:35:10 -04:00
|
|
|
"*DS_Store",
|
|
|
|
|
".obsidian",
|
|
|
|
|
".pkl-lsp",
|
|
|
|
|
".tsbuildinfo",
|
|
|
|
|
"package-lock.json",
|
|
|
|
|
".prettierrc",
|
|
|
|
|
"node_modules",
|
|
|
|
|
".DocumentRevisions-V100",
|
|
|
|
|
".Spotlight-V100",
|
|
|
|
|
".TemporaryItems",
|
|
|
|
|
".Trashes",
|
|
|
|
|
".fseventsd",
|
|
|
|
|
".editorconfig",
|
|
|
|
|
"*.min.js",
|
|
|
|
|
"*.lock",
|
|
|
|
|
"*lock*",
|
|
|
|
|
"*.lockb",
|
|
|
|
|
"*.pulsar.go",
|
|
|
|
|
"*.pb.gorm.go",
|
|
|
|
|
"*.pb.gw.go",
|
|
|
|
|
"*_templ.go",
|
|
|
|
|
"*.tmp",
|
|
|
|
|
"*.work.*",
|
|
|
|
|
"*.sum",
|
|
|
|
|
".parcel-cache",
|
|
|
|
|
"*.icns",
|
|
|
|
|
"*.ico",
|
|
|
|
|
"*.iml",
|
|
|
|
|
"Icon?",
|
|
|
|
|
"iCloud~",
|
|
|
|
|
"com~",
|
|
|
|
|
".conform*",
|
|
|
|
|
".null-ls_*",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
--- Directories to ignore when filtering files
|
|
|
|
|
M.ignored_directories = {
|
|
|
|
|
"contracts",
|
|
|
|
|
"crypto",
|
|
|
|
|
"api",
|
|
|
|
|
"chains",
|
|
|
|
|
"test",
|
|
|
|
|
"examples",
|
|
|
|
|
"scripts",
|
|
|
|
|
"bridge",
|
|
|
|
|
"client",
|
|
|
|
|
"translations",
|
|
|
|
|
"env",
|
|
|
|
|
".husky",
|
2026-07-05 16:56:46 -04:00
|
|
|
".worktrees",
|
2026-05-29 18:35:10 -04:00
|
|
|
}
|
|
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
local EMPTY = {}
|
2026-05-29 18:35:10 -04:00
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
--- Convert a glob (* and ? wildcards) to an anchored Lua pattern
|
|
|
|
|
--- @param glob string
|
|
|
|
|
--- @return string
|
|
|
|
|
local function glob_to_lua(glob)
|
|
|
|
|
return "^" .. glob:gsub("[%%%.%(%)%+%-%^%$%[%]]", "%%%0"):gsub("%*", ".*"):gsub("%?", ".") .. "$"
|
|
|
|
|
end
|
2026-05-29 18:35:10 -04:00
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
--- @param globs string[]
|
|
|
|
|
--- @return string[]
|
|
|
|
|
local function compile_globs(globs)
|
|
|
|
|
local out = {}
|
|
|
|
|
for _, g in ipairs(globs) do
|
|
|
|
|
out[#out + 1] = glob_to_lua(g)
|
2026-05-29 18:35:10 -04:00
|
|
|
end
|
2026-07-11 18:46:47 -04:00
|
|
|
return out
|
|
|
|
|
end
|
2026-05-29 18:35:10 -04:00
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
--- Find the git root for a directory by walking up (pure libuv, cached)
|
|
|
|
|
local root_cache = {} ---@type table<string, string|false>
|
|
|
|
|
--- @param dir string
|
|
|
|
|
--- @return string?
|
|
|
|
|
local function git_root(dir)
|
|
|
|
|
local cached = root_cache[dir]
|
|
|
|
|
if cached ~= nil then return cached or nil end
|
|
|
|
|
local cur = dir
|
|
|
|
|
while cur and cur ~= "" do
|
|
|
|
|
if uv.fs_stat(cur .. "/.git") then
|
|
|
|
|
root_cache[dir] = cur
|
|
|
|
|
return cur
|
|
|
|
|
end
|
|
|
|
|
local parent = cur:match "(.+)/[^/]+$"
|
|
|
|
|
if not parent or parent == cur then break end
|
|
|
|
|
cur = parent
|
|
|
|
|
end
|
|
|
|
|
root_cache[dir] = false
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--- Read additional ignore patterns from the .rgignore file in the git root.
|
|
|
|
|
--- Cached per file and invalidated on mtime change. Safe in fast event contexts.
|
|
|
|
|
--- @param dir? string directory to resolve the git root from (defaults to cwd)
|
|
|
|
|
--- @return string[] patterns List of glob patterns from .rgignore
|
|
|
|
|
local rgignore_cache = {} ---@type table<string, {mtime: number, patterns: string[]}>
|
|
|
|
|
function M.read_rgignore(dir)
|
|
|
|
|
local root = git_root(dir or uv.cwd())
|
|
|
|
|
if not root then return EMPTY end
|
|
|
|
|
local path = root .. "/.rgignore"
|
|
|
|
|
local stat = uv.fs_stat(path)
|
|
|
|
|
if not stat then return EMPTY end
|
|
|
|
|
local cached = rgignore_cache[path]
|
|
|
|
|
if cached and cached.mtime == stat.mtime.sec then return cached.patterns end
|
|
|
|
|
local patterns = {}
|
|
|
|
|
local file = io.open(path, "r")
|
|
|
|
|
if file then
|
|
|
|
|
for line in file:lines() do
|
|
|
|
|
if line ~= "" and not line:match "^#" then
|
|
|
|
|
patterns[#patterns + 1] = (line:gsub("^%./", ""))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
file:close()
|
|
|
|
|
end
|
|
|
|
|
rgignore_cache[path] = { mtime = stat.mtime.sec, patterns = patterns }
|
2026-05-29 18:35:10 -04:00
|
|
|
return patterns
|
|
|
|
|
end
|
|
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
--- Create a filter for snacks picker `transform` options.
|
|
|
|
|
--- Snacks contract: return `false` to DROP an item, `true`/`nil` to keep it
|
|
|
|
|
--- (returning nil keeps the item!). Runs per item in a fast event context,
|
|
|
|
|
--- so only pure Lua and libuv are used here.
|
|
|
|
|
--- @return fun(item: snacks.picker.finder.Item): boolean
|
2026-05-29 18:35:10 -04:00
|
|
|
function M.create_picker_filter()
|
2026-07-11 18:46:47 -04:00
|
|
|
local static ---@type string[]? compiled static globs (lazy)
|
|
|
|
|
local last_raw, last_rg = nil, EMPTY ---@type string[]?, string[]
|
2026-05-29 18:35:10 -04:00
|
|
|
return function(item)
|
2026-07-11 18:46:47 -04:00
|
|
|
local file = item and item.file
|
|
|
|
|
if not file then return true end
|
2026-05-29 18:35:10 -04:00
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
static = static or compile_globs(M.patterns)
|
|
|
|
|
local raw = M.read_rgignore(item.cwd)
|
|
|
|
|
if raw ~= last_raw then
|
|
|
|
|
last_raw, last_rg = raw, compile_globs(raw)
|
2026-05-29 18:35:10 -04:00
|
|
|
end
|
|
|
|
|
|
2026-07-11 18:46:47 -04:00
|
|
|
-- Match every path segment (directories and basename) anchored,
|
|
|
|
|
-- so `test` drops `test/foo.lua` but never `latest.md`.
|
|
|
|
|
for seg in file:gmatch "[^/\\]+" do
|
|
|
|
|
for _, pat in ipairs(static) do
|
|
|
|
|
if seg:match(pat) then return false end
|
|
|
|
|
end
|
|
|
|
|
for _, pat in ipairs(last_rg) do
|
|
|
|
|
if seg:match(pat) then return false end
|
|
|
|
|
end
|
|
|
|
|
for _, dirname in ipairs(M.ignored_directories) do
|
|
|
|
|
if seg == dirname then return false end
|
|
|
|
|
end
|
2026-05-29 18:35:10 -04:00
|
|
|
end
|
2026-07-11 18:46:47 -04:00
|
|
|
return true
|
2026-05-29 18:35:10 -04:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return M
|