Skip to content

refactor(terminal): split message rendering#75

Merged
omarluq merged 3 commits into
mainfrom
refactor/terminal-message-render-split
Jun 1, 2026
Merged

refactor(terminal): split message rendering#75
omarluq merged 3 commits into
mainfrom
refactor/terminal-message-render-split

Conversation

@omarluq

@omarluq omarluq commented Jun 1, 2026

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f8c6659-0562-4e6f-8c91-36138aae52cf

📥 Commits

Reviewing files that changed from the base of the PR and between fa7cb65 and 26fa618.

📒 Files selected for processing (1)
  • internal/terminal/render_test.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Thinking messages can be hidden or shown with formatted placeholders
    • Improved streaming message rendering with smarter caching
    • Consistent styling, boxed headers, and word-wrapping across message types
  • Bug Fixes

    • More accurate scrolling and viewport calculations for long conversations
  • Tests

    • Added coverage for rendering behaviors, boxed layouts, queued messages, and scroll stability
  • Refactor

    • Internal message rendering reorganized for performance and maintainability

Walkthrough

Refactors terminal message rendering into three focused pieces: cache orchestration (cache state and warm-up), role-specific rendering (per-role formatters and streaming cache), and layout/scrolling (compose static + dynamic groups and compute viewport slices).

Changes

Terminal message rendering refactor

Layer / File(s) Summary
Message-line cache orchestration
internal/terminal/render_messages.go
Retains message-line cache accessors and prefix-sum/warm-up helpers (cachedMessageLines, currentLineCacheState, rebuildMessageRowPrefixSums, warmMessageLineCache, warmMessageLineCacheStep) after removing in-file rendering/scrolling logic.
Role-based message rendering
internal/terminal/message_render.go
Adds streaming-block caching, a role-dispatcher renderMessage, and multiple role-specific renderers (user, assistant, queued, streaming variants, thinking, tool/custom/summary) plus boxedLines and style-merge utilities for consistent styled output.
Message layout and viewport scrolling
internal/terminal/message_layout.go
Implements composition of cached static groups with dynamic groups, tail-backed warm-cache rendering, prefix-sum binary-search mapping of global rows to message groups, and slicing/flattening helpers (allMessageLines, bottomMessageLines, scrolledMessageLines, staticMessageLinesForRows, sliceStyledLineGroups, etc.).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • omarluq/librecode#62: Related changes treat expanded tool output specially for bottom-tail rendering and interact with the layout/slicing logic.
  • omarluq/librecode#64: Introduces or modifies the message-line cache and prefix-sum model that this refactor consumes.
  • omarluq/librecode#65: Adds tests around warm-cache behavior that are related to the cache warm-up logic changed here.

Poem

🐰 I hop through code, I slice and stack,

Static lines and streaming track.
Cache warmed quick, the viewport sings,
Roles boxed neat with tiny wings.
A joyful hop for render things!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess relevance to the changeset. Add a pull request description explaining the refactoring rationale, file organization changes, and any architectural improvements achieved.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main refactoring: splitting message rendering logic across multiple terminal files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/terminal-message-render-split

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter

codecov-commenter commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.56250% with 59 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.18%. Comparing base (af77032) to head (26fa618).

Files with missing lines Patch % Lines
internal/terminal/message_layout.go 80.47% 22 Missing and 11 partials ⚠️
internal/terminal/message_render.go 82.78% 19 Missing and 7 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #75      +/-   ##
==========================================
+ Coverage   65.96%   66.18%   +0.21%     
==========================================
  Files         205      207       +2     
  Lines       17828    17850      +22     
==========================================
+ Hits        11761    11814      +53     
+ Misses       4976     4940      -36     
- Partials     1091     1096       +5     
Flag Coverage Δ
unittests 66.18% <81.56%> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/terminal/message_layout.go`:
- Around line 220-225: The helper visibleMessageLineGroups (used by
drawRuntimeTextBuffer and message windows) must not mutate app.scrollOffset;
remove the side-effecting assignments and clamping lines and instead only
compute and return the sliced/flattened groups. Specifically, in the block where
you check if maxRows < 0 || totalRows <= maxRows and where you compute maxOffset
and clamp app.scrollOffset, eliminate any writes to app.scrollOffset and just
return flattenStyledLineGroups(groups, totalRows) or the properly sliced result
based on maxRows/totalRows; keep all scroll bookkeeping (setting or clamping
app.scrollOffset) in the message-specific callers (e.g., the chat rendering
code) not in visibleMessageLineGroups.

In `@internal/terminal/message_render.go`:
- Around line 154-156: The loop that currently does for _, line := range
markdownLines { lines = append(lines, newStyledLine(style, line.Text)) }
discards per-line Spans and any line-level styling produced by renderMarkdown;
instead, preserve the original styledLine data by appending the existing line
(or a shallow copy) and merge the desired container style only into its
Style/Spans rather than reconstructing from Text. Locate markdownLines and
newStyledLine usage in message_render.go and replace constructing a new styled
line from line.Text with either lines = append(lines, line) or by copying line
and applying/combining the outer style onto line.Style/Spans so Spans and
line-level attributes from renderMarkdown are retained for thinking output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bd3cc542-75d0-4bfb-850b-3571dae5733c

📥 Commits

Reviewing files that changed from the base of the PR and between af77032 and b2a887c.

📒 Files selected for processing (3)
  • internal/terminal/message_layout.go
  • internal/terminal/message_render.go
  • internal/terminal/render_messages.go
💤 Files with no reviewable changes (1)
  • internal/terminal/render_messages.go

Comment thread internal/terminal/message_layout.go Outdated
Comment thread internal/terminal/message_render.go
@omarluq omarluq force-pushed the refactor/terminal-message-render-split branch from 629a0bb to e0dee94 Compare June 1, 2026 14:52
@omarluq omarluq force-pushed the refactor/terminal-message-render-split branch from e0dee94 to fa7cb65 Compare June 1, 2026 14:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/terminal/render_test.go (1)

158-170: ⚡ Quick win

Consider table-driving these rendering-variant assertions.

These tests cover closely related renderer variants with repeated setup/assert patterns. A table-driven structure would make it easier to add new role/layout variants and keep expectations aligned.

As per coding guidelines, "**/*_test.go: Prefer table-driven tests for core behavior and regression tests for terminal rendering bugs".

Also applies to: 172-181

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/render_test.go` around lines 158 - 170, This test
(TestRenderQueuedMessagesRendersHeadersAndBody) repeats similar setup/assert
patterns; convert it and the neighboring related test(s) into a table-driven
test that iterates variants (e.g., different queuedMessages, widths, expected
text slices) to reduce duplication; structure a slice of cases with name,
queuedMessages, width, and expectedLines, and inside the loop call
renderQueuedMessages and lineTexts and run assertions (assert.Contains or
assert.Equal as appropriate) using t.Run for each case to preserve isolation;
reference the existing functions renderQueuedMessages and lineTexts to locate
where to adapt the assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/terminal/render_test.go`:
- Around line 62-67: The test TestRenderThinkingMessagePreservesMarkdownSpans
indexes lines[2] without verifying the slice length which can cause a panic;
before accessing lines[2] in the test that calls app.renderThinkingMessage, add
a guard assertion (e.g., require.GreaterOrEqual(t, len(lines), 3, "expected
thinking content line")) to ensure at least three lines are present, then
proceed to set content := lines[2] and assert on content.Spans.

---

Nitpick comments:
In `@internal/terminal/render_test.go`:
- Around line 158-170: This test (TestRenderQueuedMessagesRendersHeadersAndBody)
repeats similar setup/assert patterns; convert it and the neighboring related
test(s) into a table-driven test that iterates variants (e.g., different
queuedMessages, widths, expected text slices) to reduce duplication; structure a
slice of cases with name, queuedMessages, width, and expectedLines, and inside
the loop call renderQueuedMessages and lineTexts and run assertions
(assert.Contains or assert.Equal as appropriate) using t.Run for each case to
preserve isolation; reference the existing functions renderQueuedMessages and
lineTexts to locate where to adapt the assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 168629bd-4343-4e5a-9b1b-e73ba0464509

📥 Commits

Reviewing files that changed from the base of the PR and between b2a887c and fa7cb65.

📒 Files selected for processing (3)
  • internal/terminal/message_layout.go
  • internal/terminal/message_render.go
  • internal/terminal/render_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/terminal/message_render.go
  • internal/terminal/message_layout.go

Comment thread internal/terminal/render_test.go
@sonarqubecloud

sonarqubecloud Bot commented Jun 1, 2026

Copy link
Copy Markdown

@omarluq omarluq merged commit aaf375d into main Jun 1, 2026
13 checks passed
@omarluq omarluq deleted the refactor/terminal-message-render-split branch June 1, 2026 16:54
@coderabbitai coderabbitai Bot mentioned this pull request Jun 1, 2026
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.

2 participants