Skip to content

fix(grep): Store slot match options and add async git grep fallback#32

Merged
mhiro2 merged 5 commits into
mainfrom
fix/grep-match-options-and-async-fallback
Jun 3, 2026
Merged

fix(grep): Store slot match options and add async git grep fallback#32
mhiro2 merged 5 commits into
mainfrom
fix/grep-match-options-and-async-fallback

Conversation

@mhiro2

@mhiro2 mhiro2 commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Store each pinned word's match options (whole_word/case_sensitive) on its slot and read them directly, removing the fragile reverse-parse of the saved Vim pattern in the grep integration.
  • When ripgrep is unavailable, fall back to an asynchronous git grep before the synchronous vimgrep, so grep in a Git repository no longer freezes the UI on large projects.
  • Repair CI that had gone red on current toolchains (independent of the grep work): make the Telescope and command-description tests robust to newer Neovim/Telescope, and fix the benchmark workflow's PR-comment cleanup.

Changes

  • cfdba8e : refactor(grep): store match options on slots instead of reparsing patterns
    • Capture whole_word/case_sensitive on each slot at pin time and read them directly in to_grep_entry, dropping the :sub reverse-parse that silently depended on pattern.build's exact format.
    • Require both booleans in validate_slot_entry so a restored slot always carries the match semantics grep relies on.
  • 8dd2117 : fix(grep): add async git grep fallback to avoid UI freezes without ripgrep
    • Run git grep asynchronously via vim.system before the synchronous vimgrep, one invocation per slot so per-slot whole-word/case options are honored, merging matches into a single sorted quickfix list.
    • Match literally with -F plus --untracked --exclude-standard to mirror ripgrep's scope; vimgrep now runs only when neither ripgrep nor git is present. Document the rg -> git grep -> vimgrep chain in README and :help.
  • 02fa4ff : test(telescope): stabilize unpin/clear cases against newer Telescope
    • Drive the picker keys with nvim_feedkeys "x" and poll for the expected state instead of fixed sleeps, and assert against the actually selected slot, so the cases pass under newer Telescope's headless (normal-mode) behavior.
  • a62afd2 : test(commands): assert command descriptions via nvim_get_commands
    • Read command descriptions from the API (desc on Neovim 0.13, definition on 0.12) instead of parsing :command output, fixing the nightly matrix; verified locally on both stable and nightly.
  • fa4bfac : build(ci): fix benchmark PR comment cleanup to use REST comment ids
    • List PR comments via the REST API (numeric ids) and filter by the marker in jq, so the cleanup no longer 404s on the GraphQL node ids returned by gh pr view --json comments.

mhiro2 added 2 commits June 3, 2026 08:27
…terns

Capture whole_word/case_sensitive on each slot entry at pin time and read
them directly in to_grep_entry. Reparsing the saved Vim pattern with :sub
depended on pattern.build's exact format and would silently break if that
format changed, so the reverse-parse is removed entirely.

validate_slot_entry now requires both booleans, so a slot in global state
always carries the semantics grep relies on.
…pgrep

When ripgrep is unavailable the only fallback was a synchronous
`vimgrep **/*`, which walks the project tree in-process and can freeze the
UI on large projects. Insert an asynchronous `git grep` step (run via
vim.system) before that path: inside a Git repository it searches without
blocking the UI, runs one invocation per slot so per-slot whole-word/case
options are honored, and merges the matches into a single quickfix list.
The synchronous vimgrep now only runs when neither ripgrep nor git exists.

`git grep -F` matches literals, so there is no regex-dialect mismatch (the
saved Vim pattern is not portable to external greps), and `-n --column`
output reuses parse_rg_vimgrep. `--untracked --exclude-standard` mirrors
ripgrep by also searching untracked files that are not gitignored.

Update README and :help to describe the rg -> git grep -> vimgrep chain.
@mhiro2 mhiro2 self-assigned this Jun 2, 2026
@mhiro2 mhiro2 added the enhancement New feature or request label Jun 2, 2026
mhiro2 added 2 commits June 3, 2026 08:50
The <C-d>/<C-x> cases fed keys with nvim_input and slept a fixed 200ms.
Under newer Telescope the prompt stays in normal mode in headless runs,
so the insert-mode mappings never fired and the cases failed in CI,
independently of this branch's changes (a fresh Telescope clone is used
on every run). Drive the keys with nvim_feedkeys "x" so the typeahead
executes synchronously, poll for the expected state instead of sleeping,
and assert against the actually selected slot since Telescope's default
selection is not guaranteed to be the first entry.
The PinWordGrep/PinWordLiveGrep/PinWordList registration cases parsed
`:command {name}` output and searched for the description string, which
newer Neovim wraps/truncates differently, so the cases failed on the
nightly matrix (independently of this branch). Read the description from
the API instead: newer Neovim (0.13) exposes it in `desc` while older
Neovim (0.12) put it in `definition`, so check both. Verified locally on
stable and nightly.
@mhiro2
mhiro2 force-pushed the fix/grep-match-options-and-async-fallback branch from 6bd6e6a to a62afd2 Compare June 3, 2026 01:47
The cleanup step listed comments with `gh pr view --json comments`, whose
`.id` is a GraphQL node id. Passing that to the REST issues/comments
endpoint returns HTTP 404 once a previous benchmark comment exists, which
failed the job on every run after the first. List comments via the REST
API instead so the ids are numeric, and filter by the marker in jq
server-side (which also drops the per-comment body fetch).
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

Benchmark Results

nvim --headless -u NONE -c "lua dofile('bench/run.lua')" -c "qa!"

== bench.bench_reapply ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
reapply_all  slots=1 wins=1                         50          2.6          0.7         14.8
reapply_all  slots=1 wins=5                         50          6.4          3.3         28.0
reapply_all  slots=1 wins=10                        50         16.9          9.7         40.4
reapply_all  slots=1 wins=20                        50         14.1         11.6         53.9
reapply_all  slots=5 wins=1                         50          1.1          0.7          3.4
reapply_all  slots=5 wins=5                         50          5.9          3.8         12.9
reapply_all  slots=5 wins=10                        50         13.8          7.0         43.5
reapply_all  slots=5 wins=20                        50         15.0         13.7         21.1
reapply_all  slots=9 wins=1                         50          1.1          0.8          2.1
reapply_all  slots=9 wins=5                         50         10.4          4.4         23.8
reapply_all  slots=9 wins=10                        50          8.1          7.8          8.5
reapply_all  slots=9 wins=20                        50         25.4         15.7         70.8
---------------------------------------------------------------------------------------------

== bench.bench_apply ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
apply_slot_globally  wins=1                        100          5.4          3.9         27.1
apply_slot_globally  wins=5                        100         20.5         18.7         33.5
apply_slot_globally  wins=10                       100         45.4         38.2         85.3
apply_slot_globally  wins=20                       100         86.3         76.5        171.7
apply_slot_for_window  existing=0                  200          4.3          3.7         31.8
apply_slot_for_window  existing=5                  200          6.3          4.2         34.0
apply_slot_for_window  existing=9                  200          5.1          4.7         23.9
---------------------------------------------------------------------------------------------

== bench.bench_clear ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
clear_all_globally  slots=1 wins=1                  30         67.8         47.8        155.0
clear_all_globally  slots=1 wins=5                  30        173.4        133.6        312.5
clear_all_globally  slots=1 wins=10                 30        283.3        236.3        533.9
clear_all_globally  slots=5 wins=1                  30        102.7         72.9        215.0
clear_all_globally  slots=5 wins=5                  30        286.3        232.6        564.8
clear_all_globally  slots=5 wins=10                 30        513.1        443.6        804.9
clear_all_globally  slots=9 wins=1                  30        131.1        101.1        293.4
clear_all_globally  slots=9 wins=5                  30        406.9        344.9        697.0
clear_all_globally  slots=9 wins=10                 30        752.1        661.5       1186.6
---------------------------------------------------------------------------------------------

== bench.bench_set_clear ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
set+clear cycle  wins=1                             50         25.6         13.4        140.0
set+clear cycle  wins=5                             50         47.6         39.6         95.3
set+clear cycle  wins=10                            50         71.0         67.3         86.5
---------------------------------------------------------------------------------------------

== bench.bench_jump ==---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
jump.next  slots=1                                 100         23.0          9.2         75.0
jump.next  slots=5                                 100       5108.5       5004.8       5598.2
jump.next  slots=9                                 100      15254.4      15040.8      16474.4
---------------------------------------------------------------------------------------------

== bench.bench_cword ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
apply_cword_for_window                             200          3.4          2.1         69.8
---------------------------------------------------------------------------------------------

== bench.bench_symbol ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
symbol: get_symbol (on identifier)                 200         10.4          4.4         55.2
symbol: get_symbol (on keyword)                    200         17.2          5.2         91.3
symbol: set+clear cycle (source=symbol)             50         22.9         17.6        138.5
symbol: set+clear cycle (source=cword)              50         14.6         12.7         40.3
---------------------------------------------------------------------------------------------

== SUMMARY ==
---------------------------------------------------------------------------------------------
Benchmark                                        Iters    Mean (us)     Min (us)     Max (us)
---------------------------------------------------------------------------------------------
reapply_all  slots=1 wins=1                         50          2.6          0.7         14.8
reapply_all  slots=1 wins=5                         50          6.4          3.3         28.0
reapply_all  slots=1 wins=10                        50         16.9          9.7         40.4
reapply_all  slots=1 wins=20                        50         14.1         11.6         53.9
reapply_all  slots=5 wins=1                         50          1.1          0.7          3.4
reapply_all  slots=5 wins=5                         50          5.9          3.8         12.9
reapply_all  slots=5 wins=10                        50         13.8          7.0         43.5
reapply_all  slots=5 wins=20                        50         15.0         13.7         21.1
reapply_all  slots=9 wins=1                         50          1.1          0.8          2.1
reapply_all  slots=9 wins=5                         50         10.4          4.4         23.8
reapply_all  slots=9 wins=10                        50          8.1          7.8          8.5
reapply_all  slots=9 wins=20                        50         25.4         15.7         70.8
apply_slot_globally  wins=1                        100          5.4          3.9         27.1
apply_slot_globally  wins=5                        100         20.5         18.7         33.5
apply_slot_globally  wins=10                       100         45.4         38.2         85.3
apply_slot_globally  wins=20                       100         86.3         76.5        171.7
apply_slot_for_window  existing=0                  200          4.3          3.7         31.8
apply_slot_for_window  existing=5                  200          6.3          4.2         34.0
apply_slot_for_window  existing=9                  200          5.1          4.7         23.9
clear_all_globally  slots=1 wins=1                  30         67.8         47.8        155.0
clear_all_globally  slots=1 wins=5                  30        173.4        133.6        312.5
clear_all_globally  slots=1 wins=10                 30        283.3        236.3        533.9
clear_all_globally  slots=5 wins=1                  30        102.7         72.9        215.0
clear_all_globally  slots=5 wins=5                  30        286.3        232.6        564.8
clear_all_globally  slots=5 wins=10                 30        513.1        443.6        804.9
clear_all_globally  slots=9 wins=1                  30        131.1        101.1        293.4
clear_all_globally  slots=9 wins=5                  30        406.9        344.9        697.0
clear_all_globally  slots=9 wins=10                 30        752.1        661.5       1186.6
set+clear cycle  wins=1                             50         25.6         13.4        140.0
set+clear cycle  wins=5                             50         47.6         39.6         95.3
set+clear cycle  wins=10                            50         71.0         67.3         86.5
jump.next  slots=1                                 100         23.0          9.2         75.0
jump.next  slots=5                                 100       5108.5       5004.8       5598.2
jump.next  slots=9                                 100      15254.4      15040.8      16474.4
apply_cword_for_window                             200          3.4          2.1         69.8
symbol: get_symbol (on identifier)                 200         10.4          4.4         55.2
symbol: get_symbol (on keyword)                    200         17.2          5.2         91.3
symbol: set+clear cycle (source=symbol)             50         22.9         17.6        138.5
symbol: set+clear cycle (source=cword)              50         14.6         12.7         40.3
---------------------------------------------------------------------------------------------

@mhiro2
mhiro2 merged commit c380078 into main Jun 3, 2026
4 checks passed
@mhiro2
mhiro2 deleted the fix/grep-match-options-and-async-fallback branch June 3, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant