feat(tui): native Arabic and RTL (bidi) support for prompts and messages - #48753
Open
muhamedbeshir wants to merge 10 commits into
Open
feat(tui): native Arabic and RTL (bidi) support for prompts and messages#48753muhamedbeshir wants to merge 10 commits into
muhamedbeshir wants to merge 10 commits into
Conversation
Render Arabic, Persian, Urdu and Hebrew text correctly in the native TUI using UAX anomalyco#9, without terminal-side bidi support or destructive text rewriting. - Add bidi-js based layout engine (direction detection via first strong char, LRI/PDI isolation for URLs/paths/numbers/code spans, grapheme- and width-aware wrapping, logical<->visual caret maps). - Add BidiTextareaRenderable for the prompt: visual caret placement and visual arrow-key motion while the edit buffer stays logical Unicode. - Add a markdown renderNode hook for assistant paragraphs/headings; fenced code, tables and diffs keep the stock LTR renderer. - Add BidiTextRenderable for user message echoes. - English-only content takes the stock render path unchanged; selection/copy return logical text. - Tests: engine unit tests, real test-renderer component tests, and an app-level e2e that types Arabic via real key presses and streams an assistant reply.
… scripts Document the native bidi/RTL TUI support in English (docs/rtl/README.md) and Arabic (docs/rtl/README.ar.md), and add install-windows.ps1 / restore-windows.ps1 to swap the dev build over the npm-installed opencode binaries.
The TUI cannot select fonts; the terminal does. Document recommended Arabic fonts and add a safe, backed-up script that adds Arabic font fallbacks to Windows Terminal without changing the monospaced main face.
The TUI cannot render with its own font, so /fonts is an application-level bridge: it lists installed font families (recommended Arabic fonts first) and writes the choice into Windows Terminal or the VS Code terminal settings, keeping a timestamped backup. It never installs fonts.
- Wrap the /fonts dialog footer in <text> so the dialog no longer crashes with an orphan-text error and actually opens. - Register BidiTextRenderable as the global ext component so RTL ordering/alignment works in dialogs, lists, tool output and toasts, not only in the prompt and message bodies. English-only content still takes the stock paint path. - Detect the hosting terminal (Windows Terminal vs VS Code) before writing the Arabic font, and preserve existing fallbacks instead of replacing them. - Add e2e coverage for the dialog and host detection.
- Paint reasoning prose through the bidi code renderer so Arabic thinking blocks reorder RTL while code lines without Arabic stay LTR. - Extend the e2e tests to assert right alignment for assistant paragraphs and dialog list rows, not just the presence of the visual order.
Windows Terminal has no font.fallbacks setting; it resolves a comma-separated font.face chain instead. The previous writer stored an array the terminal silently ignored, so picking a font never changed anything. The writer now builds 'Mono, <pick>, <arabic...>' preserving the user's faces, and removes any stale fallbacks key.
Windows Terminal warns about every missing family in the face chain. Limit the tail to families that resolve on this machine (the picked font is always kept); the dialog already labels the rest as not installed.
Drop the /fonts command, its dialog, the settings writer, docs and tests. Font selection stays where it belongs: the terminal's own settings. Bidi rendering itself is unchanged.
Contributor
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate PRs FoundPR #48590 - PR #48587 - These two PRs appear to address the same feature: native RTL/bidi support for the TUI with nearly identical titles and scope (bidi-textarea, bidi-markdown, bidi-text components). PR #48590 mentions "opencode2 beta" while your current PR (48753) and #48587 have identical titles. Recommend reviewing the status and approach of #48590 and #48587 to avoid duplicate work. |
- Apply UAX anomalyco#9 L2 flips over the full augmented stream including isolate controls, matching the reference application instead of clamping them away. Clamping rotated words and detached punctuation in mixed runs. - Expand each island across adjacent Latin/digit words so one isolate covers every maximal LTR run; sibling sub-flips plus the whole-line flip otherwise swap neighboring runs. - Broaden island seeds: markdown code spans, spaced Windows paths and key:line references. Code spans containing RTL prose stay natural. - Prefer wrapping outside LTR islands so tokens are not split across visual lines unless unavoidable. - Paint multi-unit graphemes with drawText: native setCell drops Arabic tashkeel. Shared paintBidiCell helper for text, textarea and markdown. - Install markdown bidi paint on CodeRenderable itself so list items, blockquotes and streaming updates inherit it; fenced code and English keep the stock painter. Drop the now-redundant renderNode hook. - Regression tests for mixed Arabic/English/code/path/URL/number runs, lists, links, diffs, wrapping and tashkeel in all three paint paths.
malek262
pushed a commit
to malek262/opencode
that referenced
this pull request
Sep 13, 2026
…op markdown TUI (review findings on the anomalyco#48753 port): - visualStep: strictly progress across hard-wrapped shared boundaries (caret froze at long-token wraps) - RTL probe: cover Thaana/NKo/Samaritan/Mandaic (U+0780-085F) and RLO - unlabeled fenced code keeps the stock LTR path (filetype must be markdown prose) - URL islands stop at strong RTL characters instead of swallowing them - memoize the RTL probe per content so English-only repaints pay no regex scan Desktop: block wrappers render display:contents so the existing '> * plaintext' rule never applied; set unicode-bidi on the real text blocks (paragraphs, headings, list items, quotes) and on agent question/answer copy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #38524
Closes #40004
Closes #39525
Closes #32984
Type of change
What does this PR do?
All four linked issues have the same root cause: nothing in the TUI render path applies the Unicode Bidirectional Algorithm. Arabic/Persian/Urdu/Hebrew words come out in logical (left-to-right) order, mixed English identifiers scramble the sentence order, RTL paragraphs stay left-aligned, wrapping reorders lines, and the prompt caret moves on an LTR assumption.
OpenTUI does wrapping, layout and cell painting in a native library with no bidi support and no JS fallback, so this cannot be fixed by patching OpenTUI. This PR subclasses its public renderables and overrides only the paint and caret entry points:
Why it works: the bidi algorithm only runs for paragraphs containing strong RTL characters. Isolates live in a layout-only stream and are never written to any buffer, so selection/copy stays logical. Wrapped logical text is synced into the native buffer so measurement and selection keep working.
How did you verify your code works?
On Windows 11, from a build of this branch:
bun test --cwd packages/tui ./test/util/bidi.test.ts
bun test --cwd packages/tui ./test/component/bidi-render.test.tsx
bun test --cwd packages/tui ./test/bidi-e2e.test.tsx
bun run --cwd packages/tui typecheck
Screenshots / recordings
Text-only change, so here are two of the exact cell-order frames the component tests assert (a real terminal renders these right-to-left correctly because the cells are already in visual order).
Arabic on its own, right-aligned:
Mixed Arabic + English, with the English run kept intact:
Checklist