Skip to content

feat(tui): render Read results as structured excerpts#30

Merged
hakula139 merged 6 commits intomainfrom
feat/tui-read-result-view
Apr 24, 2026
Merged

feat(tui): render Read results as structured excerpts#30
hakula139 merged 6 commits intomainfrom
feat/tui-read-result-view

Conversation

@hakula139
Copy link
Copy Markdown
Owner

@hakula139 hakula139 commented Apr 24, 2026

Summary

This PR adds the next per-tool result view after Edit diffs: successful read calls now render as styled, line-numbered excerpts in the TUI while preserving the existing model-facing tool output.

  • Adds a pure-data ReadExcerpt result view so parsing stays in the read tool and rendering stays in the TUI block layer.
  • Renders path/range context, aligned line numbers, body truncation, and empty-file context for Read results.
  • Shortens file-tool call labels and Read excerpt paths to cwd-relative paths when possible, reducing repeated absolute-path noise in the TUI.
  • Updates the roadmap so remaining result-view focus is grep grouping and glob file lists.

Changes

File Description
crates/oxide-code/src/tool.rs Adds ToolResultView::ReadExcerpt, ReadExcerptLine, cwd-relative path helpers, and registry/call-label coverage.
crates/oxide-code/src/tool/read.rs Builds structured excerpt views from successful line-numbered Read output, with cwd-relative display paths and graceful fallback for malformed output.
crates/oxide-code/src/tool/edit.rs Uses the shared cwd-relative path formatter for Edit call labels.
crates/oxide-code/src/tool/write.rs Uses the shared cwd-relative path formatter for Write call labels.
crates/oxide-code/src/tui/components/chat/blocks/tool.rs Renders Read excerpts with path/range context, aligned line numbers, wrapping, and existing truncation semantics.
crates/oxide-code/src/tui/components/chat.rs Adds chat-level assertions for Read excerpt rendering, truncation, and empty files.
docs/roadmap.md Marks styled Read excerpts as shipped and narrows remaining TUI result-view focus.

Test plan

  • cargo fmt --all --check
  • cargo build
  • cargo clippy --all-targets -- -D warnings
  • cargo test — 926 passed
  • cargo llvm-cov --ignore-filename-regex main[.]rs — 97.94% line coverage
  • pnpm lint
  • pnpm spellcheck
  • LSP diagnostics on modified Rust files — no diagnostics

Out of scope

  • Grouped grep result rendering.
  • Structured glob file-list rendering.
  • Viewport virtualization.

@hakula139 hakula139 added the enhancement New feature or request label Apr 24, 2026
@hakula139 hakula139 self-assigned this Apr 24, 2026
@hakula139 hakula139 added the enhancement New feature or request label Apr 24, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@hakula139 hakula139 force-pushed the feat/tui-read-result-view branch from 5fe24fb to a3221a3 Compare April 24, 2026 08:56
@hakula139 hakula139 merged commit 0616e02 into main Apr 24, 2026
4 checks passed
@hakula139 hakula139 deleted the feat/tui-read-result-view branch April 24, 2026 09:00
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.
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