hermes-agent/ui-tui/src/components
brooklyn! 9fb40e6a3d
fix(tui): restrict fast-echo bypass to ASCII so Vietnamese/CJK/IME input renders correctly (#26011)
* fix(tui): restrict fast-echo bypass to ASCII so Vietnamese/CJK/IME input renders correctly

The composer's fast-echo path (canFastAppend / canFastBackspace) writes
characters straight to stdout to skip an Ink re-render on the hot
typing path. The previous guard only checked
'stringWidth(text) === text.length', which lets a lot of non-ASCII
through:

  - Vietnamese precomposed letters (ề, ắ, ờ, ự, ...) report width 1 and
    length 1, but a Vietnamese Telex / IME stack produces them across
    multiple keystrokes; the intermediate composition state must be
    drawn by Ink so the rendered cell, the stored value, and the
    cursor column stay in lockstep when the final commit replaces the
    preview.
  - NFD combining marks (U+0300..U+036F) are zero-width but length 1,
    so even a passing equality lets them slip and silently desync the
    cell column.
  - CJK/East-Asian wide and emoji rejected only because their length
    differs, but the boundary was shape-shaped, not intent-shaped.

User-visible bug from the original report:
  Example: eê noiói nge neène
  -> the bypass committed the IME preview char before the diacritic
     replaced it, leaving doubled letters on screen.

Fix: gate fast-echo on pure printable ASCII (0x20-0x7e). The
performance-critical English typing path is unchanged; everything else
goes through the normal Ink render path so layout stays accurate.

Also extracts the shape preconditions as pure exported helpers
(canFastAppendShape / canFastBackspaceShape) so the regression matrix
is testable without spinning up a TextInput.

Tests: ui-tui/src/__tests__/textInputFastEcho.test.ts adds 20 cases
covering ASCII still works, Vietnamese precomposed + NFD, CJK, emoji,
NBSP / Latin-1, ANSI / control bytes, multi-line, and end-of-line
preconditions. Verified RED on the previous guard (11 of 20 fail) and
GREEN on the new guard.

Refs: #5221, #7443, #17602, #17603 (similar wide-char rendering bugs).

* docs(tui): clarify Vietnamese char terminology in regression comment

Address Copilot review: 'single byte width' implied UTF-8 byte semantics,
but the relevant property is JS code units (`text.length === 1`) and
display width (`stringWidth === 1`). Reworded to match.
2026-05-15 09:41:50 -05:00
..
agentsOverlay.tsx style(tui): apply npm run fix 2026-04-28 22:18:26 -05:00
appChrome.tsx feat(tui): segment turns with rule above non-first user msgs; trim ticker dead space (#21846) 2026-05-08 05:12:09 -07:00
appLayout.tsx feat(tui): segment turns with rule above non-first user msgs; trim ticker dead space (#21846) 2026-05-08 05:12:09 -07:00
appOverlays.tsx fix(tui): honor skin highlight colors (#20895) 2026-05-06 14:01:56 -07:00
branding.tsx feat(tui): collapsible sections in startup banner (skills, system prompt, MCP) 2026-05-06 03:34:00 -07:00
fpsOverlay.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
helpHint.tsx feat(tui): add a mini help menu when u write ? in the input field 2026-04-30 13:37:12 -04:00
markdown.tsx feat(ui-tui): resolve markdown links to readable page titles (#24013) 2026-05-11 14:16:31 -07:00
maskedPrompt.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
messageLine.tsx fix(tui): collapse long system messages in transcript with expand toggle 2026-05-06 03:34:00 -07:00
modelPicker.tsx fix(tui): address remaining review feedback — ordering and digit shortcuts 2026-04-30 23:41:19 -04:00
overlayControls.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
prompts.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
queuedMessages.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
sessionPicker.tsx fix(tui): require double-tap d to confirm session delete 2026-04-29 20:21:16 -07:00
skillsHub.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
streamingAssistant.tsx fix(tui): inline todo in transcript, group across thinking 2026-04-26 16:09:28 -05:00
streamingMarkdown.tsx docs: clarify wrapForFrac and streaming math-fence rationale 2026-04-28 21:43:32 -04:00
textInput.tsx fix(tui): restrict fast-echo bypass to ASCII so Vietnamese/CJK/IME input renders correctly (#26011) 2026-05-15 09:41:50 -05:00
themed.tsx refactor(tui): /clean pass across ui-tui — 49 files, −217 LOC 2026-04-16 22:32:53 -05:00
thinking.tsx chore(salvage): strip duplicated/merge-corrupted blocks from PR #17664 2026-04-29 21:56:51 -07:00
todoPanel.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00