feat(picker): allow configuring pathspec for git grep (#2311)

## Description

This is in place of the rejected PR #2178. Please consider the following
reasons for merging.

This PR adds the possibility to specify pathspec patterns to the `git
grep .... -- <patchspec>` command. This is necessary for ignoring large
git-tracked files (that cannot be added to `.gitignore`) from the git
grep search. git-grepping in some large files with very long lines can
freeze Neovim and make `Snacks.picker.git_grep` completely unusable.

Without this change the picker cannot be configured to use some
pathspecs by default. They can be added dynamically in live mode but
re-typing the same pathspecs every time one needs to use
`Snacks.picker.git_grep` would be silly.

In reply to the [question if cmd_args can be used for
this](https://github.com/folke/snacks.nvim/pull/2178#discussion_r2448762906):
No. The "pathspecs" need to be specified *last* (optionally after `--`).
When configuring Snacks.picker like this:
```lua
  sources = {
    git_grep = {
      cmd_args = { ':!*.min.js', ':!*.min.css', ':!uv.lock'  },
    },
  }
```
then the `cmd_args` are inserted in front of the search pattern and `git
grep` doesn't find anything. The following config can't be used either
because that will cause the [search
pattern](c9fa6f7b07/lua/snacks/picker/source/git.lua (L76))
to be treated as one of the pathspecs.
```lua
    git_grep = {
      cmd_args = { '--', ':!*.min.js', ':!*.min.css', ':!uv.lock'  },
    },
```
This commit is contained in:
Jakub F. Bortlík 2025-10-22 06:33:33 +02:00 committed by GitHub
parent d293b21fe1
commit 57fbda70d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 12 additions and 1 deletions

View file

@ -260,6 +260,7 @@ M.git_files = {
---@field untracked? boolean search in untracked files
---@field submodules? boolean search in submodule files
---@field need_search? boolean require a search pattern
---@field pathspec? string|string[] pathspec pattern(s)
---@field ignorecase? boolean ignore case
M.git_grep = {
finder = "git_grep",

View file

@ -73,7 +73,17 @@ function M.grep(opts, ctx)
if opts.ignorecase then
table.insert(args, "-i")
end
table.insert(args, ctx.filter.search)
local pattern, pargs = Snacks.picker.util.parse(ctx.filter.search)
table.insert(args, pattern)
args[#args + 1] = "--"
vim.list_extend(args, pargs)
local pathspec = type(opts.pathspec) == "table" and opts.pathspec or { opts.pathspec }
---@cast pathspec string[]
vim.list_extend(args, pathspec)
if not opts.cwd then
opts.cwd = Snacks.git.get_root() or uv.cwd() or "."
ctx.picker:set_cwd(opts.cwd)