Repository navigation
Conversation
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
22fffff to
c2ae82e
Compare
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
|
I refreshed this in #32470 against current The old patch was aimed at the right bug, but the active locale helpers now live under This keeps the scope narrow: fix the rendered-width math in the TUI, not agent ordering or plugin naming policy. |
Issue for this PR
Closes #23376
Type of change
What does this PR do?
Fixes the agent label rendering corruption I reported in #23376.
The TUI's
truncateandtruncateMiddlehelpers inpackages/opencode/src/util/locale.tsusedstr.lengthto decide whether to truncate. That counts invisible codepoints (U+200B,U+200C,U+200D,U+FEFF) as one UTF 16 code unit each, even though they render as zero columns on screen. When a string fit in real rendered width but exceeded the limit in code unit count, the helper chopped visible letters and appended an ellipsis, producing labels likeSisyphus: ltraworker.This PR switches the width check and the per character walk to
Bun.stringWidth, which is already idiomatic in this repo for cursor math. Examples of existingBun.stringWidthcallers:packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx:172packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx:373packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:389Why it works:
Bun.stringWidthreports 0 columns for the four zero width codepoints named above and 2 columns for wide graphemes like emoji, which matches the Unicode spec for terminal rendering width. Using it here makes both helpers correct for any string, not just ASCII.Input strings without invisible codepoints behave identically to the old implementation. That is covered by the first test case in the new test file.
How did you verify your code works?
Added a new co located test file
packages/opencode/src/util/locale.test.tswith 11 cases. Ran it locally:Test cases covered:
U+200Bprefixed string whose rendered width equals the limit is NOT truncated (repro of bug(tui): agent label rendering corrupts when name contains invisible Unicode codepoints #23376).U+200Bprefixed string whose rendered width exceeds the limit gets truncated at the visible boundary.U+200B,U+200C,U+200D,U+FEFF) are handled identically.truncateMiddlereturns the input unchanged when rendered width is withinmaxLength.truncateMiddleat exact width with a ZWSP prefix is NOT truncated.truncateMiddleon a long ZWSP bearing string producesstartOut + "…" + endOutwith correct widths againstkeepStartandkeepEnd.truncateMiddledefaultmaxLengthof 35 is preserved.truncateMiddleon plain ASCII returns the same shape as before.Typecheck note: the monorepo uses
bun turbo typecheck. My sandbox could not complete the full workspace install cleanly (bun installstalled on the dep graph in my environment), so I limited automated verification to the targeted test file. The change is scoped to one module with no new imports and no new type surface. Happy to run any additional verification a maintainer wants.Byte level evidence for the bug is in issue #23376.
Screenshots / recordings
This is not a UI change in the visual sense, but the bug is a visible rendering defect. The simplest reproduction is the hex dump included in issue #23376:
That decodes to
U+200Bfollowed bySisyphus : Ultraworker. With the oldtruncate, feeding that string atlen=22returned"\u200BSisyphus: Ultraworke…"becausestr.lengthwas 23. With the newtruncate,Bun.stringWidth(str)is 22 so the string is returned unchanged. No ellipsis, no chopped letter.Checklist