Skip to content

fix(at-mention): nested .gitignore via shared util#129

Merged
esengine merged 1 commit intomainfrom
fix/128-at-picker-gitignore
May 2, 2026
Merged

fix(at-mention): nested .gitignore via shared util#129
esengine merged 1 commit intomainfrom
fix/128-at-picker-gitignore

Conversation

@esengine
Copy link
Copy Markdown
Owner

@esengine esengine commented May 2, 2026

Closes #128.

Why

@paulo70015 reported that on macOS Flutter projects every @ query (@lib/main.dart, @lib, @test, @pubspec.yaml) returned "no files match" — even though the files existed and weren't gitignored.

Diagnosis

The picker walker did not honor .gitignore. The 500-result cap filled with ios/Pods/ (alphabetically before lib/) before the walk reached the user's source code.

Fix — trust the project's own ignore rules, not a hardcoded list

Rather than grow DEFAULT_PICKER_IGNORE_DIRS per-framework (Pods, DerivedData, target, vendor, _build, …), trust the project's .gitignore. Same source of truth that fzf, ripgrep, fd, and the rest of the ecosystem use.

  • New src/gitignore.ts lifts loadGitignoreAt + ignoredByLayers out of the semantic chunker, so the @ picker walker and the indexer share one nested-gitignore implementation
  • listFilesWithStats(Sync|Async) push a layer per directory's .gitignore as they descend
  • statBatch checks the merged layer set before stat'ing — no syscalls for files we'll drop
  • Default maxResults bumped from 500 → 2000
  • respectGitignore: false opt-out for raw walks
  • chunker.ts switches to the shared util — no behavior change there

No git binary required (we just read .gitignore files via the existing ignore npm package). Works in projects without git, in containers, on first launch — same correctness as git ls-files for typical projects.

Verification

  • npm run verify — typecheck, lint, build, 1817 tests all green
  • New tests cover root + nested .gitignore, negation patterns (!keep.log), and the opt-out path

Out of scope

  • Global ~/.config/git/ignore and .git/info/exclude — easy follow-up if anyone reports needing them; the layer model already supports it

@paulo70015 reported every @ query returning "no files match" on
Flutter projects. Diagnosis: the picker walker did not honor
.gitignore, so the 500-result cap filled with ios/Pods/ before the
alphabetical walk reached lib/.

Rather than grow the hardcoded ignore list per framework (Pods,
DerivedData, target, vendor, …), trust the project's own
.gitignore — same source of truth fzf, ripgrep, and the rest of
the ecosystem use.

  - new `src/gitignore.ts` lifts loadGitignoreAt + ignoredByLayers
    out of the semantic chunker, so the @ picker walker and the
    indexer share one nested-gitignore implementation
  - `listFilesWithStats(Sync|Async)` push a layer per directory's
    .gitignore as it descends; statBatch checks the merged layer
    set before stat'ing
  - default maxResults bumped 500 → 2000
  - opt-out via `respectGitignore: false` on ListFilesOptions
  - `chunker.ts` switches to the shared util — no behavior change

Tests cover root + nested .gitignore, negation (`!keep.log`),
opt-out, and the existing skip / cap / DFS-order contracts.
@esengine esengine force-pushed the fix/128-at-picker-gitignore branch from c95a21b to 84fa813 Compare May 2, 2026 13:23
@esengine esengine changed the title fix(at-mention): honor .gitignore + add Pods/DerivedData fix(at-mention): nested .gitignore via shared util May 2, 2026
@esengine esengine merged commit fee58f1 into main May 2, 2026
1 check passed
@esengine esengine deleted the fix/128-at-picker-gitignore branch May 2, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: @ autocomplete returns "no files match" for all project files

1 participant