feat(tui): render Read results as structured excerpts#30
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
5fe24fb to
a3221a3
Compare
6 tasks
hakula139
added a commit
that referenced
this pull request
Apr 25, 2026
## Summary Adds the next per-tool result view after Edit (#24) and Read (#30): successful `grep` calls in content mode now render as per-file groups of line-numbered match rows in the TUI, while the model-facing tool output stays unchanged. - Adds a pure-data `ToolResultView::GrepMatches` (`Vec<GrepFileGroup>` + `truncated` flag) so parsing stays in the `grep` tool and rendering stays in the TUI block layer. - `GrepTool::result_view` parses content mode only; non-content modes (`files_with_matches`, `count`), outputs with skipped-large-file warnings, and any line the parser doesn't fully recognise fall through to the default `Text` body — preferring "user sees raw output" over "user sees a partial structured render that silently drops information". - Per-file path headers + line-numbered match rows; context lines (the `-` separator in grep's text output) render dim so match rows stand out at a glance. - Match-line styling is fg-only (no background tint) — leaves the design space open for an upcoming GitHub-block diff redesign tracked separately. - Renderer mirrors `read_excerpt`'s row shape so a future shared `numbered_row` primitive can hoist both call sites cleanly. ## Changes | File | Description | | ---- | ----------- | | `tool.rs` | Adds `ToolResultView::GrepMatches`, `GrepFileGroup`, `GrepMatchLine`. New registry-routing test pins the full structured shape so a mutation returning empty groups or flipping `is_match` doesn't sneak through. | | `tool/grep.rs` | `GrepTool::result_view` for content mode; `parse_content_view` + `parse_match_line` parsers with fall-through-on-failure semantics; tests cover empty / single-file / multi-file / context / `--` separator / truncation footer / skipped-warning / invalid-line paths. | | `tui/components/chat/blocks/tool.rs` | New `mod grep` declaration + dispatch arm in `ToolResultBlock::render`. Module-level doc updated to list grep in the structured-output set. | | `tui/components/chat/blocks/tool/grep.rs` (new) | Per-file groups with line-numbered match rows; uniform line-number column width across groups so a 4-digit number doesn't shift the column under a 1-digit sibling group above it. `footer_text` helper handles all four `(hidden, truncated)` combinations. Renderer-level unit tests cover the empty-groups guard and the path-boundary budget guard. | | `tui/components/chat.rs` | Three render tests covering path-header + numbered rows, body-budget truncation with `+N lines` footer, and the server-side `(limit reached)` truncation marker without a phantom hidden-row count. | | `CLAUDE.md` | Crate tree picks up the new renderer module. | ## Test plan - [x] `cargo fmt --all --check` - [x] `cargo build` compiles cleanly - [x] `cargo clippy --all-targets -- -D warnings` — zero warnings - [x] `cargo test` — 990 passed (was 985 pre-PR; +5 tests) - [x] `pnpm spellcheck` — clean - [x] `cargo llvm-cov --ignore-filename-regex 'main\.rs'` — 97.84% line coverage (was 97.35% pre-PR), per-file: - `tool/grep.rs` — 98.29% region, 98.60% line - `tui/components/chat/blocks/tool/grep.rs` — 100% region, 99.58% line ## Out of scope Address in separate PRs: - Inter-tool spacing — borderless spacer line between a tool result and the next non-result block. - Inline code style — drop background tint, use a Catppuccin accent fg. - GitHub-block diff redesign — line numbers in a left column + full-width red / green background tint per row. Splits into three sub-PRs (data shape, numbers column, bg tint). - DRY refactor — extract a shared `numbered_row` primitive used by `read_excerpt`, `grep`, and the future diff renderer. Pure refactor; no visual change.
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
This PR adds the next per-tool result view after Edit diffs: successful
readcalls now render as styled, line-numbered excerpts in the TUI while preserving the existing model-facing tool output.ReadExcerptresult view so parsing stays in thereadtool and rendering stays in the TUI block layer.grepgrouping andglobfile lists.Changes
crates/oxide-code/src/tool.rsToolResultView::ReadExcerpt,ReadExcerptLine, cwd-relative path helpers, and registry/call-label coverage.crates/oxide-code/src/tool/read.rscrates/oxide-code/src/tool/edit.rscrates/oxide-code/src/tool/write.rscrates/oxide-code/src/tui/components/chat/blocks/tool.rscrates/oxide-code/src/tui/components/chat.rsdocs/roadmap.mdTest plan
cargo fmt --all --checkcargo buildcargo clippy --all-targets -- -D warningscargo test— 926 passedcargo llvm-cov --ignore-filename-regex main[.]rs— 97.94% line coveragepnpm lintpnpm spellcheckOut of scope
grepresult rendering.globfile-list rendering.