Skip to content

fix: report match counts in --stats for the local-index and brute-force paths - #149

Merged
Shengyu Fu (shengyfu) merged 5 commits into
microsoft:mainfrom
thecolourfoundation:fix/stats-match-counts
Sep 10, 2026
Merged

Shengyu Fu (shengyfu) merged 5 commits into
microsoft:mainfrom
thecolourfoundation:fix/stats-match-counts

Conversation

@thecolourfoundation

Copy link
Copy Markdown
Contributor

--stats reports a match count on the server-delegated search path, but the
local-index and brute-force paths — which cover the common case of an
unindexed or single-machine search — only ever printed timing, with no match
or line count. Confirmed against current main:

$ tgrep hello . --stats
Query plan: AND(3 trigrams) (candidates: 1/5)
Search completed in 0.3ms

vs. the server path's

2 matches (2 matched lines) in 0.3ms (via server)

This adds a format-agnostic match/line counter to OutputWriter (separate
from the JSON Stats/file_stats accounting already used for --json's
summary event, so that path is untouched), and reports it from all three
--stats print sites in search.rs. All three now agree:

Search completed in 0.3ms: 2 matches (2 matched lines)
Brute-force search completed in 0.2ms (1 file): 2 matches (2 matched lines)
2 matches (2 matched lines) in 0.3ms (via server)

Related to #145 — #146 fixed the print-ordering half of that issue; this
addresses the "more stats like rg supplies" half, which was still open
after #146.

Tested: cargo test --workspace (623 tests, 0 failures), manual verification
of all three search paths against ripgrep-style stats output.

Copilot AI balanced review requested due to automatic review settings September 9, 2026 11:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Match totals can be incorrect across paths, output modes, and trimmed matches; coverage should be expanded.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds match and matched-line totals to local-index and brute-force --stats output.

Changes:

  • Tracks totals in OutputWriter.
  • Reports totals across search summaries.
  • Preserves existing JSON statistics handling.
File summaries
File Description
tgrep-cli/src/search.rs Prints totals in local and brute-force summaries.
tgrep-cli/src/output.rs Adds match accounting; currently mishandles multiple paths, non-line modes, and trimmed matches.
Review details

Suppressed comments (1)

tgrep-cli/src/output.rs:305

  • The existing --stats integration tests only verify output ordering and do not assert the newly added totals. Please add brute-force and local-index assertions for multiple matches on one line and for a non-line output mode such as --count; a multiple-path case is also needed to catch counter leakage between runs.
    pub fn match_totals(&self) -> (u64, u64) {
        (self.total_matches, self.total_matched_lines)
  • Files reviewed: 2/2 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tgrep-cli/src/output.rs Outdated
Comment thread tgrep-cli/src/output.rs
Comment thread tgrep-cli/src/output.rs Outdated
@thecolourfoundation

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@thecolourfoundation

Copy link
Copy Markdown
Contributor Author

Fixed — now counting m.spans.len() (the original match spans) instead of
the post-trim spans, so --trim no longer undercounts.

You're right that --files-with-matches, --count/--count-matches, and binary
matches don't go through write_match, so --stats under those modes will
still under-report right now. That's a real gap rather than out of scope —
happy to follow up with counting hooks for those paths here if useful, or
keep this PR scoped to the local-index/brute-force fix and open a follow-up.
Let me know which you'd prefer.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Match statistics can be incorrect across several supported search and output modes.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

tgrep-cli/src/output.rs:569

  • The totals are only updated by write_match, but several successful local-search output modes return before calling it: -l at search.rs:1724, -c/--count-matches at search.rs:1729, quiet mode at search.rs:1719, and non-JSON binary output at search.rs:1742. Those commands now print 0 matches (0 matched lines) despite finding matches (for example, --no-index -c --stats). Record the FileMatches totals before the presentation-specific early returns, with the appropriate mode limits, rather than deriving stats solely from rendered match rows.
        self.total_matches += m.spans.len() as u64;

tgrep-cli/src/output.rs:305

  • OutputWriter is shared across every command-line target (main.rs:1339-1351), so these totals are cumulative, while each local/brute-force target prints a stats line immediately. With two path arguments, the second summary therefore includes matches from the first; server-delegated summaries remain per-target because they count only that response. Reset or snapshot/delta the counters per search::run, or defer reporting to one invocation-level summary.
    pub fn match_totals(&self) -> (u64, u64) {
        (self.total_matches, self.total_matched_lines)

tgrep-cli/src/search.rs:1222

  • The existing --stats integration tests only assert output ordering, so the newly reported values are untested. Add local-index and --no-index assertions covering multiple matches on one line, multiple positional paths, count/file-only output, inverted matches, and a multiline match; these cases exercise the counter semantics and would catch the incorrect totals above.
        let (matches, matched_lines) = writer.match_totals();
        eprintln!(
            "Search completed in {:.1}ms: {matches} matches ({matched_lines} matched lines)",
            elapsed.as_secs_f64() * 1000.0
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tgrep-cli/src/output.rs Outdated
@shengyfu

Copy link
Copy Markdown
Member

thanks North research (@thecolourfoundation) for contributing, could you resolve the CCR comments?

Count original matches independently of output modes and scope text statistics to each search root. Carry optional per-file server totals while preserving existing match rows and JSON output semantics.

Co-authored-by: Copilot App <[email protected]>
Copilot AI review requested due to automatic review settings September 10, 2026 20:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Binary totals can include content past the NUL cutoff, and files-only server stats can create match-proportional RPC payloads.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread tgrep-cli/src/search.rs
Comment thread tgrep-cli/src/serve.rs
Return one compact marker per matching file when files-only statistics are requested, retaining exact totals and binary markers without rendering match rows. Add bounded-payload regressions and clarify binary byte-count semantics.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 9676a521-6e9e-45aa-879e-e00d51714daa
Copilot AI review requested due to automatic review settings September 10, 2026 21:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Legacy-server fallbacks can report incorrect files-only and quiet totals.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tgrep-cli/src/search.rs:1122

  • When an older server omits file_stats, its rendered rows are insufficient for -l --stats and -q --stats. The old files_only path clamps every file to one matching line, while quiet sends max_count: 1 per file but receives rows from every matching file; counting all those rows therefore undercounts files-only searches and overcounts quiet searches versus the local and new-server paths. If file_stats is absent for either mode, retry without truncation and apply first-file filtering, or bypass the server rather than printing an incorrect total.
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 9676a521-6e9e-45aa-879e-e00d51714daa
Copilot AI review requested due to automatic review settings September 10, 2026 21:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The legacy-server fallback can report incorrect totals because rendered rows do not preserve complete match statistics.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tgrep-cli/src/search.rs:1122

  • This fallback cannot reconstruct the promised totals from an older server response. Before this change, a files-only request forced max_count to 1, so an upgraded CLI connected to a still-running old daemon reports only the first matching line for -l --stats (and multiline rows can likewise split one regex match across lines). Detect the missing file_stats before rendering and retry via the local path, or otherwise treat that server as incompatible, rather than emitting an incorrect total.
  • Files reviewed: 6/8 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@shengyfu
Shengyu Fu (shengyfu) merged commit ca04d17 into microsoft:main Sep 10, 2026
1 check passed
@thecolourfoundation

Copy link
Copy Markdown
Contributor Author

Thanks for picking this up and pushing it the rest of the way — appreciate
you fixing the remaining issues Copilot flagged and getting it merged.

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.

3 participants