pi-rtl
Right-to-left rendering for Pi: Arabic/Persian shaping, Unicode bidi, RTL alignment, bold text and lam-alef ligatures for terminals that have no bidi or shaping, plus a one-command Persian font setup.
Package details
$ pi install npm:pi-rtl- Package
pi-rtl- Version
0.1.1- Published
- Nov 10, 2026
- Downloads
- 328/mo · 328/wk
- Author
- co-parsa
- License
- MIT
- Types
- extension
- Size
- 332.6 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-rtl
Right-to-left support for Pi's terminal UI — Persian, Arabic and Hebrew — for terminals that do no bidi and no Arabic shaping (Windows Terminal, conhost, Windows Terminal-family, xterm, alacritty, kitty, …).
Pi stores text in logical order; terminals paint cells left to right and most of them have no shaping engine, so Persian comes out reversed and with disconnected letters. This package fixes both, everywhere Pi draws.
before: .ﺩﻮﺷﯽﻣ ﺖﺴﻳﺍ ﻪﻠﻤﺟ ﻦﻳﺍ
after: این جمله است میشود
Install
pi install npm:pi-rtl
Then restart Pi (or run /reload). Verify with /rtl test and /rtl status.
To try it without touching settings:
pi -e npm:pi-rtl
Persian font (recommended)
Most terminal fonts have no Arabic glyphs, so the shaped letters are drawn by a fallback font and look uneven. Install the bundled Persian monospace font and point your terminals at it:
npx pi-rtl font # install + configure console and Windows Terminal
npx pi-rtl font status # what is installed / configured
npx pi-rtl font revert # restore the previous terminal fonts
- Windows — copies
Vazir Codeinto%LOCALAPPDATA%\Microsoft\Windows\Fonts(per-user, no admin), registers it, setsHKCU\Consoleto it and setsprofiles.defaults.fontin Windows Terminal. Existing values are backed up to~/.pi/agent/pi-rtl-font-backup.jsonandsettings.json.bak-pi-rtl. - macOS / Linux — copies the font into your user font directory and runs
fc-cache; select the font in your terminal manually.
Close and reopen the terminal window afterwards.
What it does
Every rendered line is converted to visual order right before it is written
out, at the single point where the regular and the fullscreen renderer hand their
lines over (TuiBase.resolveFakeCursors). Nothing is patched on disk.
- Shaping — Persian/Arabic letters are mapped to their contextual
presentation forms (isolated / final / initial / medial), including lam-alef
ligatures. ZWNJ (
نیمفاصله) is honoured: the half-space blocks the join but letters keep their joined forms, the way Persian typography does it. - Bidi — a full UAX #9 implementation (P2/P3, W1–W7, N0–N2, I1–I2, L1, L2) reorders each line, mirrors brackets and keeps Latin words, numbers, emoji and punctuation where they belong.
- Presentation — right-to-left paragraphs are right-aligned to a stable right edge, RTL runs are drawn bold, and ANSI colors, hyperlinks and the editor's cursor markers travel with the characters they belong to.
The transform is width preserving: one codepoint in, one out. Wrapping, truncation, padding, block backgrounds and the hardware cursor column are exactly as Pi computed them. Lines without right-to-left characters pass through byte-identical.
Commands
| Command | Effect |
|---|---|
/rtl |
toggle on / off (also Ctrl+Alt+R) |
/rtl on / /rtl off |
enable / disable |
/rtl bidi |
reorder only, keep the disconnected letter shapes |
/rtl bold / /rtl normal |
bold RTL runs (default: bold) |
/rtl ligatures / /rtl no-ligatures |
lam-alef ligatures (default: on) |
/rtl align right / /rtl align left |
alignment of RTL paragraphs (default: right) |
/rtl auto | /rtl ltr | /rtl rtl |
paragraph direction for lines without strong text |
/rtl status |
current settings |
/rtl test |
print a Persian sample line |
Settings live in ~/.pi/agent/pi-rtl.json:
{
"mode": "on",
"baseDirection": "auto",
"align": "right",
"bold": true,
"ligatures": true
}
PI_RTL=on|bidi|off overrides the mode for one run.
Scrolling and the scrollbar
The fullscreen scrollbar is painted into the last column of every line. The transform removes that cell before deciding anything and puts it back afterwards, so a scrollbar appearing or fading never changes alignment: every RTL line ends on the same column whether you are scrolling or not.
Limitations
- Copying text copies what is on screen — presentation forms in visual order. The session, the prompts sent to the model and the files stay logical.
- Code blocks containing Persian are reordered too, because the transform
works on rendered lines. Use
/rtl offwhen reading code rather than text. - Terminals with native bidi (mlterm, konsole, GNOME Terminal) would apply bidi twice — keep the extension off there.
- Lam-alef merges two cells into one; the freed cell is returned to the line's own padding so widths never change.
How it hooks in
index.ts patches TuiBase.resolveFakeCursors on the prototype chain of
TuiMainScreen/TuiAltScreen once per process, through the module instance Pi
maps for @earendil-works/pi-tui. No files on disk are modified, so updates of Pi
cannot break the patch and a newer copy re-applies it on the next start.
Files
| Path | Purpose |
|---|---|
extensions/index.ts |
hook, /rtl command, config |
extensions/visualize.ts |
ANSI-aware logical → visual line transform |
extensions/unicode-bidi.ts |
UAX #9 implementation + mirroring |
extensions/shape.ts |
Arabic/Persian contextual shaping |
bin/pi-rtl.mjs |
font installer / status / revert |
fonts/ |
bundled Vazir Code font (see fonts/LICENSE-Vazir-Code.txt) |
test/selftest.ts |
node test/selftest.ts |
Related work
pi-bidi, pi-arabic-rtl, pi-persian-rtl, pi-persian-rtl-bundle and
pi-hebrew-rtl all reorder lines, but none of them shape Arabic letters, and
several patch a node_modules/@earendil-works/pi-tui copy that Pi's bundled
build never loads. This package does shaping, bidi, styling and alignment in one
runtime hook.
License
MIT. The bundled Vazir Code font is public domain / Bitstream Vera based; see
fonts/LICENSE-Vazir-Code.txt.