Add --filter and --filter-regex flags to restrict project scan scope#28
Merged
Conversation
…ring
Standalone module providing the data type behind the upcoming `--filter`
and `--filter-regex` CLI flags. No CLI wiring yet — that lands in a
follow-up commit so the filter semantics can be reviewed in isolation.
`PathFilter` has two variants:
- `Literal(Vec<String>)` — a project-relative subpath stored as
normalized path components. `src/parser` and `/src/parser` both
parse to `["src", "parser"]`. Matching is path-component-aware so
`src/parser` matches `src/parser/rust.rs` but NOT
`src/parser_extra.rs` — avoiding the silent prefix-match footgun.
An empty literal (`""` or `"/"`) degenerates to "no filter".
- `Regex(regex::Regex)` — compiled regex matched (unanchored, caller
anchors with `^...$`) against the slash-normalized project-relative
path. Portable across platforms because `\` is converted to `/`
before matching.
Construction is split from validation:
- `literal()` is infallible (only normalization).
- `regex()` errors with a clear "invalid filter regex" message.
- `validate(&project_root)` exists separately so the CLI can produce
a precise "filter path … is not accessible from project root …"
error before any scan work begins. Regex validation is a no-op (a
regex is "valid" iff it compiled; empty match sets aren't an
error).
`display()` provides a user-facing form for upcoming title/header
rendering.
Test coverage (19 new tests, all green) covers: leading-slash
normalization, separator collapsing, component-aware vs prefix-only
matching, exact-file match, deeper-vs-shallower path handling, the
designed-against `src/parser` vs `src/parser_extra.rs` distinction,
empty-filter degeneration, validation success/failure with tempfile,
regex compile errors, unanchored substring matching, and display
formatting.
Adds `regex = "1"` as a normal dependency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend `ParserRegistry::scan_project` and `serena::scan_project_serena` to accept an optional `&PathFilter`. When provided, files whose project-relative path does not satisfy the filter are skipped: - `scan_project` checks the filter inside the `WalkBuilder` loop *before* reading the file from disk, so excluded files cost only a directory entry traversal. - `scan_project_serena` retains only matching files after pickle parse; the cache layout is opaque so the filter is applied post-load, but before the tree is assembled. All three production call sites (`main.rs` × 2, the TUI cache-rescan in `tui.rs`) pass `None` for now — behavior is unchanged. CLI flag and display wiring follow in subsequent commits. 284 lib tests + 37 integration tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add two mutually exclusive clap args on top of the existing scan plumbing: - `--filter <PATH>` — project-relative literal subpath. Leading slash accepted but optional. Path-component matching (so `src/parser` does NOT silently include `src/parser_extra.rs`). The path must exist under --project; otherwise the program exits with `filter path "<p>" is not accessible from project root <root>` before any scan work begins. - `--filter-regex <PATTERN>` — regex over the slash-normalized project-relative path. Unanchored by default; users anchor with `^...$` as needed. Invalid regex syntax surfaces as `invalid filter regex "<p>": <details>` at CLI parse time. Mutual exclusion enforced by clap (`conflicts_with`) — passing both fails with a clear message before main() runs. The constructed `PathFilter` is passed through to both `ParserRegistry::scan_project` and `serena::scan_project_serena` so the tree-sitter and Serena-cache code paths share a single filter implementation. Smoke-tested locally: ambits --project . --filter src/filter.rs --coverage ambits --project . --filter-regex '^src/parser/.*\.rs$' --coverage ambits --project . --filter src/does_not_exist # errors clearly ambits --project . --filter src --filter-regex foo # clap rejects TUI re-parse and report-header display land in subsequent commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #28 +/- ##
==========================================
+ Coverage 73.78% 74.14% +0.36%
==========================================
Files 24 25 +1
Lines 6766 6965 +199
Branches 6766 6965 +199
==========================================
+ Hits 4992 5164 +172
- Misses 1666 1693 +27
Partials 108 108 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PathFiltermodule (src/filter.rs) — two filter variants:Literal(component-prefix path matching, sosrc/parsermatchessrc/parser/rust.rsbut notsrc/parser_extra.rs) andRegex(compiled, unanchored regex matched against the slash-normalised project-relative path). Construction is infallible for literals; regex compilation errors surface immediately with the offending pattern in the message. Existence validation for literal paths is a separatevalidate()step so the CLI can emit a clear error before any scan work begins.--filter <path>— restrict the project scan to a subpath. Leading slash is accepted and normalised away. Errors at startup if the path does not exist under--project.--filter-regex <pattern>— restrict to files matching a regex. Mutually exclusive with--filter(enforced by clapconflicts_with).Scanner integration — both
ParserRegistry::scan_projectandscan_project_serenaacceptOption<&PathFilter>. In the tree-walker path, non-matching files are skipped before disk I/O. In the Serena path, files are dropped after pickle parse (cache layout is fixed) but before any downstream consumer sees the list.Test plan
cargo testpasses —src/filter.rshas 23 unit tests covering literal normalisation, component-prefix semantics, regex matching, validate edge cases, and display formattingambits --project . --filter src/parser— TUI shows onlysrc/parser/*filesambits --project . --filter-regex '^src/.*\.rs$'— matches expected filesambits --project . --filter nonexistent— exits with a clear path error before scanningambits --project . --filter src/foo --filter-regex bar— clap rejects with conflict error🤖 Generated with [Claude Code