fix(llm): chat panel UX — divider repaint on cycle + drop 3-row truncation#176
Merged
Conversation
The chat panel divider renders the active provider name via `resolveProviderForMode(.chat, …)` on every paint, but the cycle action only nudged `current_provider_idx` and emitted a statusbar hint — neither chat surface's paint latch was armed, so the divider's `lo-qwen` (or whatever the previous provider) stayed visible until some other event triggered a repaint. The user saw the cycle reflected in the statusbar but not in the panel chrome. Now sets `chat_inline_paint_pending` / `chat_overlay_paint_pending` on every successful cycle so the next term-bytes tick re-emits the divider with the new label. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…istory The hardcoded `per_turn_max_rows = 3` truncated long replies with a dim `[…]` marker even when the scrollback budget had plenty of room. We already shipped PageUp/PageDown scrollback in #175 — truncation on top of it is just a wart that hides content the user came to see. Removed: each turn now renders its full wrap-chunk count, capped only by the scrollback budget. The back-walk's `oldest_turn_cap` path still handles the natural panel boundary when total demand exceeds budget — the OLDEST visible turn gets clipped (with the `[…]` marker), the newest always renders in full. `countTurnRows` now receives `scrollback_budget` as the upper bound instead of a fixed 3. The marker logic in `renderWrappedRaw` stays exactly the same — it just fires far less often. Regression test asserts the LAST sentinel of a 5-chunk turn lands in the paint output. Verified fail-without/pass-with (had the hardcoded 3-row cap, marker `EEEE-LAST-CHUNK-MARKER` was dropped). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Owner
Author
|
Folded a second fix in: the "no wrap, it cuts of |
…on bytes Em-dash `—` (U+2014 = E2 80 94) and other 3- or 4-byte UTF-8 sequences with continuation bytes in 0x80..0x9F were getting corrupted: the C1-control filter dropped those continuation bytes as if they were bare C1 controls, leaving an orphan leading byte that the terminal rendered as `�`. The 2-byte special case for `C2 + 80..9F` covered NBSP-region pairs but nothing wider. Rewrote `writeSanitized` to walk codepoints via `pw.utf8Iter` and check the C1 range against the DECODED codepoint, not the raw bytes. Multi-byte sequences re-emit verbatim; only actual C0/C1 controls + DEL get dropped (TAB still passes through, CR/LF still collapse to a single space). Regression test pins em-dash, bullet (U+2022), sparkle emoji, and a CJK glyph through the inline-panel paint path and asserts each survives intact with no U+FFFD replacement char in the output. Verified fail-without/pass-with. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Bug
User reported: cycling providers with Alt+M updates the statusbar hint ("provider: lo-qwen (2/3)") but the chat panel header still shows the OLD provider name (e.g.
✨ atty chat · lo-qwen ──────).Root cause
hooks.zigcycle handler bumpsrt.current_provider_idxand callslatchHint, but never armschat_inline_paint_pending/chat_overlay_paint_pending. The divider's label is computed byresolveProviderForMode(.chat, …)on every paint, so the stale name persists until some unrelated event triggers a repaint.Fix
Arm whichever chat surface's paint latch is active after a successful cycle. One-line per surface.
Test plan
hooks_tests.zig—Alt+M cycle arms chat panel repaint so divider shows the new provider. Verified fails without fix (794 pass, 1 fail), passes with fix (795/795).zig build test— 795/795 unit tests greenzig fmt --check src/— clean🤖 Generated with Claude Code