mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-20 05:01:30 +00:00
* 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.
|
||
|---|---|---|
| .. | ||
| asCommandDispatch.test.ts | ||
| clipboard.test.ts | ||
| constants.test.ts | ||
| createGatewayEventHandler.test.ts | ||
| createSlashHandler.test.ts | ||
| details.test.ts | ||
| emoji.test.ts | ||
| externalLink.test.ts | ||
| forceTruecolor.test.ts | ||
| gatewayClient.test.ts | ||
| markdown.test.ts | ||
| mathUnicode.test.ts | ||
| messages.test.ts | ||
| osc52.test.ts | ||
| paths.test.ts | ||
| platform.test.ts | ||
| precisionWheel.test.ts | ||
| providers.test.ts | ||
| reasoning.test.ts | ||
| rpc.test.ts | ||
| scroll.test.ts | ||
| slashParity.test.ts | ||
| stateIsolation.test.ts | ||
| statusBarTicker.test.ts | ||
| streamingMarkdown.test.ts | ||
| subagentTree.test.ts | ||
| syntax.test.ts | ||
| terminalModes.test.ts | ||
| terminalParity.test.ts | ||
| terminalSetup.test.ts | ||
| text.test.ts | ||
| textInputFastEcho.test.ts | ||
| textInputLineNav.test.ts | ||
| textInputPassThrough.test.ts | ||
| textInputRightClick.test.ts | ||
| textInputWrap.test.ts | ||
| theme.test.ts | ||
| turnStore.test.ts | ||
| useCompletion.test.ts | ||
| useComposerState.test.ts | ||
| useConfigSync.test.ts | ||
| useInputHandlers.test.ts | ||
| useQueue.test.ts | ||
| useSessionLifecycle.test.ts | ||
| useVirtualHistoryHeights.test.ts | ||
| viewport.test.ts | ||
| viewportStore.test.ts | ||
| virtualHeights.test.ts | ||
| virtualHistoryClamp.test.ts | ||
| virtualHistoryOffsetCache.test.ts | ||
| wheelAccel.test.ts | ||