grid: decide whether to fold Indic conjuncts (UAX#29 GB9c) #25

Open
opened 2026-10-04 19:01:30 +09:00 by natsukium · 0 comments
Owner

UAX#29 GB9c (Unicode 15.1) makes an Indic conjunct one grapheme: InCB=Consonant [Extend|Linker]* Linker [Extend|Linker]* × InCB=Consonant, e.g. क्ख (U+0915 U+094D U+0916) and the ZWJ half-form क्‍ख. felis does not fold it, so a conjunct lands one cell per consonant and the client shapes each cell apart (no joined glyph). REQ-602 records the exception.

The decision is the width of a folded conjunct under the 2-cell cluster cap:

Terminal Clusters GB9c क्ख स्त्र
Ghostty yes, cap 2 (test pins the ZWJ form at 2) 2 2
Windows Terminal yes (Linker × Consonant), sum capped at 2 2 2
WezTerm sum of widths, min(2) 2 2
foot with utf8proc ≥ 2.12; double-width default caps at 2 2 2
kitty 0.49 yes, width of the first scalar 1 1
Alacritty, VTE no clustering 2 3
glibc wcswidth — 2 3
felis no 2 3

Folding with a 2-cell cap (Ghostty / Windows Terminal) gives correct shaping but drifts from wcswidth for chains of three or more consonants; staying unfolded keeps the cursor in sync and gives up conjunct shaping. Folding needs the Indic_Conjunct_Break property (Consonant, Linker, Extend) from DerivedCoreProperties.txt.

Sources: ghostty src/unicode/grapheme.zig and the "print Devanagari grapheme should be wide" test in src/terminal/Terminal.zig; wezterm wezterm-cell/src/lib.rs grapheme_column_width; foot foot.ini(5) grapheme-width-method; microsoft/terminal src/tools/GraphemeTableGen/Program.cs; kitty text-sizing protocol docs.

UAX#29 GB9c (Unicode 15.1) makes an Indic conjunct one grapheme: `InCB=Consonant [Extend|Linker]* Linker [Extend|Linker]* × InCB=Consonant`, e.g. `क्ख` (U+0915 U+094D U+0916) and the ZWJ half-form `क्‍ख`. felis does not fold it, so a conjunct lands one cell per consonant and the client shapes each cell apart (no joined glyph). REQ-602 records the exception. The decision is the width of a folded conjunct under the 2-cell cluster cap: | Terminal | Clusters GB9c | `क्ख` | `स्त्र` | |---|---|---|---| | Ghostty | yes, cap 2 (test pins the ZWJ form at 2) | 2 | 2 | | Windows Terminal | yes (Linker × Consonant), sum capped at 2 | 2 | 2 | | WezTerm | sum of widths, `min(2)` | 2 | 2 | | foot | with utf8proc ≥ 2.12; `double-width` default caps at 2 | 2 | 2 | | kitty 0.49 | yes, width of the first scalar | 1 | 1 | | Alacritty, VTE | no clustering | 2 | 3 | | glibc `wcswidth` | — | 2 | 3 | | felis | no | 2 | 3 | Folding with a 2-cell cap (Ghostty / Windows Terminal) gives correct shaping but drifts from `wcswidth` for chains of three or more consonants; staying unfolded keeps the cursor in sync and gives up conjunct shaping. Folding needs the `Indic_Conjunct_Break` property (Consonant, Linker, Extend) from `DerivedCoreProperties.txt`. Sources: ghostty `src/unicode/grapheme.zig` and the "print Devanagari grapheme should be wide" test in `src/terminal/Terminal.zig`; wezterm `wezterm-cell/src/lib.rs` `grapheme_column_width`; foot `foot.ini(5)` `grapheme-width-method`; microsoft/terminal `src/tools/GraphemeTableGen/Program.cs`; kitty text-sizing protocol docs.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
felis-terminal/felis#25
No description provided.