Skip to content

Fix Arabic / RTL text rendering in terminal output Closes #10355#10809

Open
BSN4 wants to merge 1 commit into
warpdotdev:masterfrom
BSN4:bader/fix-arabic-rtl-terminal-output
Open

Fix Arabic / RTL text rendering in terminal output Closes #10355#10809
BSN4 wants to merge 1 commit into
warpdotdev:masterfrom
BSN4:bader/fix-arabic-rtl-terminal-output

Conversation

@BSN4
Copy link
Copy Markdown

@BSN4 BSN4 commented May 13, 2026

Description

Terminal output rendered Arabic and other RTL scripts left-to-right with isolated (unjoined) forms, while the input editor rendered the same text correctly. The two paths diverged at the painter, not at the shaper:

  • The input editor renders through TextLayoutSystem::layout_text, which runs BidiParagraphs + ShapeLine with Shaping::Advanced — bidi reorder and rustybuzz Arabic shaping both apply.
  • The terminal grid had two paths and both broke that:
    • Without ligatures (default): render_grid_without_ligatures walks cells one by one and calls glyph_for_char per codepoint — no shaping, no bidi.
    • With ligatures: render_grid_with_ligatures does call layout_line, but paint_line then discarded the shaper's glyph.x and forced every glyph back to original_logical_column * cell_width, undoing the bidi reorder and disconnecting joined glyphs.

This change keeps the existing fast cell-by-cell path for plain LTR rows and only diverts rows that need bidi + shaping:

  • is_complex_script_char covers Arabic (all blocks), Hebrew, Syriac, Thaana, NKo, Arabic Presentation Forms A/B.
  • row_needs_complex_layout (row predicate) and frame_contains_complex_script (frame pre-scan, short-circuits).
  • When the frame contains any complex-script char, the dispatcher forces the ligature path so RTL rows reach layout_line.
  • Complex-script rows are routed to a new paint_complex_line that positions glyphs at glyph.position_along_baseline — the shaper-produced visual x — preserving bidi reorder and contextual joining.
  • Non-RTL rows continue through paint_line unchanged.

Deferred (separate change): cursor placement, selection highlight rect, mouse hit-testing, and per-cell backgrounds on RTL rows still use logical cell coordinates and will be visually offset from the shaped glyphs. Most visible in alt-screen apps (vim/less/htop). Fixing it correctly needs a visual↔logical cell map shared between the renderer and those consumers; bundling it here would balloon the diff and risks regressing non-RTL behaviour.

Linked Issue

Fixes #10355RTL (Right-to-Left) text direction support for Hebrew, Arabic, and other languages (rendering subset; cursor / selection / hit-test on RTL rows tracked as a follow-up; see Deferred note above). Also addresses #3589, #279, #125, #7889 (the recurring "RTL works in command line but not in result blocks" symptom).

  • The linked issue is labeled `ready-to-spec` or `ready-to-implement`.

    Note: RTL (Right-to-Left) text direction support for Hebrew, Arabic, and other languages #10355 is currently labeled `enhancement, needs-info, triaged, accessibility`. The narrow inconsistency this PR fixes — input editor renders Arabic correctly, terminal output does not — reads as a bug rather than a feature ask. Flagging @oss-maintainers to confirm the right readiness label here, or to point me at a separate bug issue to link instead.

  • Screenshots of the implementation are included below.

Testing

  • I have manually tested my changes locally with `./script/run` (built via `target/debug/bundle/osx/WarpOss.app`, verified `echo "مرحبا بالعالم"` renders RTL and joined).
  • Unit tests added in `grid_renderer_tests.rs`:
    • `test_is_complex_script_char_detects_rtl_scripts` / `test_is_complex_script_char_excludes_simple_scripts`
    • `test_row_needs_complex_layout_positive` / `test_row_needs_complex_layout_negative`
    • `test_frame_contains_complex_script_pure_latin` / `_arabic` / `_respects_range`
  • Presubmit (Rust portions) clean locally: `cargo fmt --check`, `cargo clippy --workspace --exclude warp_completer --all-targets --tests -- -D warnings` and `cargo clippy -p warp_completer ...`, `cargo nextest run --workspace`, `cargo test --doc`. (clang-format / wgslfmt not run locally; no C/Obj-C/WGSL files touched in this diff.)

Screenshots / Videos

Before

image

After

image

Agent Mode

  • Warp Agent Mode

CHANGELOG-BUG-FIX: Fix Arabic / RTL text in terminal output being rendered left-to-right with unjoined letter forms.

@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 13, 2026

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @BSN4 on file. In order for us to review and merge your code, each contributor must visit https://cla.warp.dev to read and agree to our CLA. Once you have done so, please comment @cla-bot check to trigger another check.

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 13, 2026

@BSN4

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

Readiness check:

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

@BSN4

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

  • Associated same-repo issues checked: none

  • Required readiness label: ready-to-implement

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 13, 2026
@BSN4 BSN4 changed the title Fix Arabic / RTL text rendering in terminal output Fix Arabic / RTL text rendering in terminal output Closes #10355 May 13, 2026
@BSN4
Copy link
Copy Markdown
Author

BSN4 commented May 13, 2026

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed label May 13, 2026
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 13, 2026

The cla-bot has been summoned, and re-checked this pull request!

@BSN4
Copy link
Copy Markdown
Author

BSN4 commented May 13, 2026

/oz-review

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

@BSN4

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

  • Associated same-repo issues checked: #10355

  • Required readiness label: ready-to-implement

Readiness check:

  • #10355: missing ready-to-implement; readiness labels present: none

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 5, 2026

Hi @BSN4 — a reviewer requested changes on this PR and it hasn't had activity from you in 23 days. When you get a chance, please push updates or reply to the review so a reviewer can take another look. Without activity, this PR will be automatically closed after 30 days of inactivity.

Terminal output rendered Arabic (and other complex / RTL scripts) left
to right with isolated letter forms, while the input editor rendered
the same text correctly. The two paths diverged at the painter, not at
the shaper.

The input editor renders through `TextLayoutSystem::layout_text`, which
runs `BidiParagraphs` + `ShapeLine` with `Shaping::Advanced`, so bidi
reorder and rustybuzz Arabic shaping both apply. The terminal grid had
two paths, and both broke that:

* Without ligatures (default), `render_grid_without_ligatures` walks
  cells one by one and calls `glyph_for_char` per codepoint — no
  shaping, no bidi, single isolated glyph per cell.
* With ligatures, `render_grid_with_ligatures` does call `layout_line`,
  but `paint_line` then discarded the shaper's `glyph.x` and forced
  every glyph back to `original_logical_column * cell_width`. That
  undid the bidi reorder and disconnected joined glyphs.

This change keeps the existing fast cell-by-cell path for plain LTR
rows and only diverts rows that need bidi + shaping:

* Add `is_complex_script_char` covering Arabic (all blocks), Hebrew,
  Syriac, Thaana, NKo, and Arabic Presentation Forms A/B.
* Add `row_needs_complex_layout` (row predicate) and
  `frame_contains_complex_script` (frame pre-scan, short-circuits).
* When the frame contains any complex-script char, the dispatcher
  forces the ligature path so RTL rows reach `layout_line`.
* Inside `render_grid_with_ligatures`, complex-script rows are routed
  to a new `paint_complex_line` that positions glyphs at
  `glyph.position_along_baseline` — the shaper-produced visual x —
  preserving bidi reorder and contextual joining. Non-RTL rows
  continue through `paint_line` unchanged.

Regression tests cover the three predicates against representative
RTL and non-RTL inputs, including the short-circuit on row range.

Deferred (separate change): cursor placement, selection highlight
rect, mouse hit-testing, and per-cell backgrounds on RTL rows still
use logical cell coordinates and will be visually offset from the
shaped glyphs. This is most visible in alt-screen apps (vim, less,
htop) where the cursor lives inside terminal output. Fixing it
correctly needs a visual<->logical cell map shared between the
renderer and those consumers; doing it in this PR would balloon the
diff and risks regressing non-RTL behaviour.

Refs: warpdotdev#10355, warpdotdev#3589, warpdotdev#279, warpdotdev#125
@BSN4 BSN4 force-pushed the bader/fix-arabic-rtl-terminal-output branch from 67d0d2e to e80814d Compare June 7, 2026 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RTL (Right-to-Left) text direction support for Hebrew, Arabic, and other languages

1 participant