Skip to content

Prior work

Several projects already attack parts of this problem. Before building anything, we read the code of each one, not just its README, and mapped what it actually does onto our nine layers.

10projects read in code
0solve width (layer 3)
0handle multiplexers (layer 8)
2ship no license file

Layer coverage

Each row is a project; each column is one of our nine layers. Read across a row to see what a project covers, and down a column to see who has touched a layer.

SolidPartialAbsentNot in the repo
1Encoding2Input3Width4Shaping5Bidi6Cursor & copy7Fonts8Multi­plexers9Apps & TUI
RtlTerminal◐Partial◐Partial◐Partial●Solid◐Partial●Solid◐Partial·Absent◐Partial
termenal-web·Absent◐Partial◐Partial●Solid◐Partial●Solid◐Partial·Absent◐Partial
termux-app-arabic·Absent·Absent◐Partial●Solid◐Partial◐Partial·Absent·Absent·Absent
Tarminal?Not in the repo?Not in the repo?Not in the repo?Not in the repo·Absent?Not in the repo◐Partial·Absent?Not in the repo
Terminal-ar·Absent·Absent·Absent◐Partial◐Partial◐Partial◐Partial·Absent◐Partial
ar-terminal·Absent◐Partial·Absent◐Partial◐Partial◐Partial◐Partial·Absent◐Partial
estaterm·Absent◐Partial·Absent◐Partial◐Partial·Absent·Absent·Absent◐Partial
bidiscope·Absent·Absent·Absent◐Partial◐Partial◐Partial·Absent·Absent◐Partial
fa-console●Solid◐Partial·Absent◐Partial◐Partial◐Partial◐Partial·Absent·Absent
rtl-terminal·Absent·Absent·Absent·Absent◐Partial·Absent·Absent·Absent◐Partial

The projects

Logical-buffer rendererMIT

RtlTerminal

Terminal emulator · Windows (WPF + ConPTY)

Shaping
WPF, per word
Bidi
Hand-rolled heuristic

The most serious prior art: logical buffer, logical copy and visual→logical mouse mapping. But its bidi isn't UAX #9, and it squashes words into cells.

Read the notes →
Logical-buffer rendererMIT

termenal-web

Browser terminal (prototype) · Browser + Node PTY

Shaping
HarfBuzz, per bidi run
Bidi
UAX #9 levels; paragraph by majority

Best reference design: a per-row logical↔visual map with logical copy. The WASM core and WebGPU renderer it claims are not in the code.

Read the notes →
Logical-buffer rendererGPLv3

termux-app-arabic

Terminal emulator (fork) · Android

Shaping
Platform HarfBuzz, full line
Bidi
UAX #9 per row, base forced LTR

A ~300-line renderer proof of concept. Touch and selection are not mapped back, there are no tests, and it is applied unconditionally.

Read the notes →
WrapperMIT

Tarminal

Terminal emulator (SwiftTerm shell) · macOS

Shaping
None in repo
Bidi
None

A wrapper with no Arabic, bidi or width code of its own. The thing to study is SwiftTerm.

Read the notes →
Logical-buffer rendererNo license

Terminal-ar

Overlay over xterm.js (Electron) · Windows / Linux

Shaping
Chromium, per span
Bidi
Heuristic, per span

Not reusable (claims MIT, ships no license). The mirrored cursor disagrees with the text, and there are no tests.

Read the notes →
Logical-buffer rendererNo license

ar-terminal

VS Code overlay + PTY transform · VS Code

Shaping
Chromium / presentation forms
Bidi
Blink per row / bidi-js baked in

Not reusable (no license). Its main path keeps copy logical but misaligns cursor and selection; its fallback path is the visual-order hack.

Read the notes →
Text transformerApache-2.0

estaterm

PTY proxy · Linux

Shaping
FriBidi → presentation forms
Bidi
UAX #9 (FriBidi), per chunk

The textbook visual-order hack, and it steps aside on the alternate screen. Only its FriBidi call sequence is worth reusing.

Read the notes →
Text transformerMIT

bidiscope

Library + xterm.js overlay · JS / browser

Shaping
Hand table → presentation forms
Bidi
Partial UAX #9 (no BD13)

Right instinct (an overlay keeps the buffer logical), wrong execution. Its 99.91 % conformance claim is unverified.

Read the notes →
Text transformerMIT

fa-console

Python stdout wrapper · Windows console

Shaping
arabic-reshaper → presentation forms
Bidi
python-bidi or whole-line reversal

Reusable for layer 1 (UTF-8 setup, ي/ك → ی/ک folding). Its display path is a visual-order hack that corrupts ANSI.

Read the notes →
Prompt pluginMIT

rtl-terminal

Claude Code plugin (prompt only) · Claude Code

Shaping
None
Bidi
Asks the model to emit controls

Markdown only: no hook, no detection, nothing enforced. Worth taking: isolating paths with LRI…PDI, and its test corpus.

Read the notes →

What the field tells us

  1. 1

    Rewriting the text always costs

    Every tool that wrote presentation forms or visual order into the terminal broke copy, search or escape sequences, and gave up on full-screen apps. The renderers that kept a logical buffer got copy right.

  2. 2

    Width is unsolved

    No project fits shaped Persian to the cell grid. Glyphs are squashed, clipped, or allowed to overflow. This is the core research question.

  3. 3

    Multiplexers: 0 of 10

    Every terminal-side implementation treats a physical row as the bidi paragraph, so a tmux or Zellij split would merge RTL runs across pane borders. Nobody has looked.

  4. 4

    Nobody negotiates who owns bidi

    All of them apply bidi unconditionally or by guesswork, including inside full-screen apps. None uses the explicit modes of the BiDi in Terminal Emulators draft.

  5. 5

    Input is ignored

    No project handles IME composition, ZWNJ entry or logical cursor movement while typing.

  6. 6

    READMEs overstate

    Five projects claim more than their code does, and two claim MIT without a license file. Our scorecard measures; it never repeats claims, including our own.

Worth reusing

FromWhatLayers
termenal-webPer-row colToVisual / visualToCol permutation; shaping per bidi run with explicit direction5 · 6
RtlTerminalLogical selection offsets and visual→logical mouse mapping, with tests; zero width for marks and ZWNJ3 · 6
termux-app-arabicShape whole runs with full-line context; draw the cursor as an overlay; force an LTR base so reordering stays local4 · 5
fa-consoleUTF-8 setup; ي/ك → ی/ک and digit folding; the rule that program data stays logical1
estatermThe FriBidi call sequence (not its output path)5
rtl-terminalLRI…PDI isolation around paths and code; a before/after test corpus5 · tests
  • Neovim #553, “Bidi language support”: open since 2014, with 47 comments. The problem is more than a decade old.
  • BiDi in Terminal Emulators (Egmont Koblinger, 2019): the draft standard for who owns bidi, the terminal or the app. VTE implements it; none of the ten projects use it.
  • Engines: HarfBuzz for shaping; FriBidi and ICU for UAX #9. Every project that got shaping right delegated it to an engine like these.

A project by Mehdi Baneshi · mbaneshi.ir