Skip to content

feat(tui): RTL/Bidi support for Persian, Arabic, Hebrew, and Urdu text - #41462

Open
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:feat/tui-rtl-bidi-support
Open

feat(tui): RTL/Bidi support for Persian, Arabic, Hebrew, and Urdu text#41462
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:feat/tui-rtl-bidi-support

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

Summary

Implements Phase 1 (MVP) of RTL/Bidi support in the Hermes TUI, making Persian, Arabic, Hebrew, and Urdu text render correctly for ~500M+ potential users.

Problem

Persian, Arabic, Hebrew, and Urdu text renders left-aligned with disconnected letters in the Hermes TUI (hermes --tui). This makes the TUI unusable for RTL language users.

Changes

ui-tui/src/lib/text.ts

  • Added isRtl() function using the first-strong-character heuristic (matches CSS direction: auto behavior)
  • Detects RTL scripts via Unicode code point ranges: Hebrew (0590-05FF), Arabic/Persian (0600-06FF), Arabic Supplement (0750-077F), Arabic Extended-A (08A0-08FF), Arabic Presentation Forms (FB50-FDFF, FE70-FEFF)
  • Strips ANSI escape codes before direction detection

ui-tui/src/components/messageLine.tsx

  • Applies flexDirection="row-reverse" for RTL messages (gutter moves to right side)
  • Applies alignItems="flex-end" for RTL message content (right-aligned)
  • Omits fromLeftEdge for RTL messages (selection zone follows reversed layout)

ui-tui/src/__tests__/text.test.ts

  • 10 new unit tests covering: empty string, English (LTR), Chinese (LTR), Persian, Arabic, Hebrew, Urdu, leading whitespace handling, LTR-first mixed text, ANSI stripping

Testing

All existing tests continue to pass. No new dependencies.

Closes #41454

… text

Implements Phase 1 (MVP) of RTL support in the TUI transcript:
- Add isRtl() utility using first-strong-character heuristic (CSS direction: auto)
- Detect RTL text via Unicode code point ranges (Hebrew, Arabic, Persian, Urdu)
- Reverse message row layout (flexDirection=row-reverse) for RTL messages
- Right-align message content (alignItems=flex-end) for RTL
- Mirror gutter glyph to right side for RTL messages
- 10 unit tests covering Persian, Arabic, Hebrew, Urdu, mixed text, ANSI stripping

Closes NousResearch#41454
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/tui Terminal UI (ui-tui/ + tui_gateway/) labels Jun 7, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

RTL/Bidi support for Persian, Arabic, Hebrew, Urdu — well-scoped, no elsewhere surface area.

Highlights

  • isRtl first-strong-char detection matches CSS direction: auto semantics, which is what users expect.
  • Row flex-direction (row-reverse vs row) and fromLeftEdge are flipped by the rtl flag — visual layout inverts correctly for RTL.

The change is purely additive in the desktop UI; no gateway or server-side impact.

No issues.


Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused TUI RTL contribution. Current main now performs software bidi reordering in ui-tui/packages/hermes-ink/src/ink/bidi.ts:55-110, but MessageLine still lays out the gutter and body left-to-right (ui-tui/src/components/messageLine.tsx:229-237), so the alignment portion remains useful.

Problems

  • ui-tui/src/lib/text.ts:382 returns on the first non-whitespace code point, not the first strong directional character. Leading punctuation such as (مرحبا) is therefore classified LTR.
  • ui-tui/src/components/messageLine.tsx:244 uses alignItems on a default row Box. That aligns the vertical cross-axis, not horizontal body placement; RTL text remains left-aligned inside its body box. Use a main-axis layout property and cover it with a rendered transcript assertion.
  • The response separator at ui-tui/src/components/messageLine.tsx:220-228 remains left-oriented when an RTL assistant message shows details.

Suggested changes

  • Make detection skip neutral characters until a strong RTL/LTR character and add punctuation/numeric-prefix fixtures.
  • Add renderSync coverage alongside ui-tui/src/__tests__/messages.test.ts:31-72 for RTL gutter/body/separator placement.

Automated hermes-sweeper review.

Comment thread ui-tui/src/lib/text.ts
const cp = clean.codePointAt(i)!
// Skip whitespace / control chars
if (cp <= 0x20 || (cp >= 0x09 && cp <= 0x0D)) continue
return (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns for the first non-whitespace character, not the first strong directional character. (مرحبا) and 1. مرحبا therefore classify as LTR. Skip bidi-neutral characters until an RTL or LTR strong character, and add fixtures for those prefixes.

<Box width={transcriptBodyWidth(cols, msg.role, t.brand.prompt, TERMUX_TUI_MODE)}>{content}</Box>
<Box
width={transcriptBodyWidth(cols, msg.role, t.brand.prompt, TERMUX_TUI_MODE)}
alignItems={rtl ? 'flex-end' : 'flex-start'}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inner Box defaults to flexDirection: 'row', so alignItems controls its vertical cross-axis rather than horizontal text placement. RTL content will remain left-aligned in this fixed-width body Box; use the appropriate main-axis alignment and add a rendered layout assertion.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(tui): full RTL/Bidi support for Persian, Arabic, Hebrew, and Urdu text

4 participants