fix(ui): wrap draft notes by terminal cells so long CJK input stays visible - #682
fix(ui): wrap draft notes by terminal cells so long CJK input stays visible#682IAMLEIzZ wants to merge 2 commits into
Conversation
|
PR author is not in the allowed authors list. |
|
@IAMLEIzZ is attempting to deploy a commit to the Modem Team on Vercel. A member of the Team first needs to authorize it. |
benvinegar
left a comment
There was a problem hiding this comment.
Requesting changes: bulk paste can re-enter onContentChange through flushSync, hit “Maximum update depth exceeded,” and truncate the draft. Please make the update non-reentrant and add bracketed-paste coverage.
This comment was generated by Pi using GPT-5.6 Sol
05650f0 to
0d14df7
Compare
Fixed — dropped the per-keystroke |
|
Both red checks look unrelated to this change:
Thanks!!! |
…isible The draft composer estimated its row count with String#length (UTF-16 code units) while the textarea wraps by terminal cells. For CJK text (two cells per code unit) the estimate stayed at one row, and the editor clamps its wrap count to the viewport height, so the one-row composer never started wrapping and scrolled everything before the cursor out of view. Give the composer wrapMode="char" so the wrap count is computable exactly, count rows by packing grapheme clusters into terminal cells, drop the stale line-count hint state, and resize the composer in the same frame as each edit. Add editor-parity, component, stream, and PTY coverage.
0d14df7 to
2e84b84
Compare
benvinegar
left a comment
There was a problem hiding this comment.
Requesting changes: draftVisualLineCount still does not exactly match the textarea's width semantics for some grapheme clusters. It measures clusters through measureClusterWidth/string-width, while OpenTUI's native editor uses Bun's width result. For a 24-cell textarea, this input reproduces the undercount:
"HEAD-" + ("🇺🇸\u0301").repeat(10) + "-TAIL"draftVisualLineCount returns 1, but a real TextareaRenderable reports 2 rows. Mounting AgentInlineNote at that width allocates one row and omits -TAIL from the frame. Keycap and heart emoji with an attached combining mark show the same mismatch (string-width reports 1 cell for the cluster while Bun/OpenTUI reports 2).
Please measure with the editor's width semantics and add this input to both the editor-parity table and a mounted visibility regression. Ordinary CJK wrapping, burst input, and bracketed paste otherwise worked in my validation, including the full unit, PTY integration, and TTY smoke suites on a merge with fresh main.
This comment was generated by Pi using GPT-5.6 Sol
Confirmed and reproduced — thanks. |
Fixes #681
Summary
The draft review-note composer estimates its height with
String#length(UTF-16 code units) indraftVisualLineCount, while the textarea wraps by terminal cells. For CJK text (1 code unit = 2 cells) the estimate stays at one row — and since the editor clamps its wrap count to the viewport height, a one-row-high composer never starts wrapping at all: the text scrolls horizontally and everything before the cursor disappears (see the issue for screenshots). English escapes this because code units == cells, so the estimate grows in step and un-clamps the editor.wrapMode="char"so the wrapped row count is computable exactly (the default word wrap follows UAX Automate prebuilt npm releases #14 — e.g. kinsoku punctuation rules — which a small estimator cannot mirror)draftVisualLineCountto pack grapheme clusters into terminal cells (a tab counts as 2 cells, matching the editor), with a fast path for printable ASCII linesflushSyncaroundonInput), so the editor never sits in a content-taller-than-viewport statePlanned heights (
measureAgentInlineNoteHeight) and mounted heights now come from the same exact function, keeping the row-windowed stream in lockstep.One behavior change to call out: in the composer, English text now wraps at the exact box width (mid-word if needed) instead of at word boundaries.Saved note cards are unchanged — they still word-wrap via
wrapText.Repro
With a ~76-cell composer box and a 60-char / 120-cell CJK draft:
ceil(60/76)= 1Testing
bun run typecheckbun run lintbun run format:checkbun test ./src ./packages ./scripts ./test/cli ./test/session— 1970 pass; the one failure (src/ui/AppHost.watch.test.tsx) also fails on a clean checkout of the base commit, unrelated to this changebun test test/pty/notes.test.ts— 15/15, including a new real-PTY case: type 86 cells of CJK, assert head and tail stay visible, save with Ctrl-SNew coverage:
AgentInlineNote.test.tsx: table-driven estimator cases (CJK, emoji, ZWJ sequences, combining marks, tabs, hard newlines, odd widths), plus parity tests that mount a realTextareaRenderableand assert itsvirtualLineCountequals the estimator for 23 inputs × 4 widthsc, type long CJK, assert the head of the text stays visible