From 28aa52de207263b37e31b3526aee8f9df203b412 Mon Sep 17 00:00:00 2001 From: mingrath Date: Mon, 27 Jul 2026 11:37:23 +0700 Subject: [PATCH] test(terminal): pin that a base keeps every stacked combining mark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The combining-mark cases carry exactly one mark — `e` + U+0301, and ❤ + U+FE0F. Thai routinely stacks two on one consonant: `ที่` is U+0E17 with an above-base vowel and a tone mark both sitting on it, and Devanagari, Arabic and Hebrew stack the same way. Nothing pinned that. Truncating the mark iterator to its first element leaves all thirteen `segment_row` tests green — the cluster still forms, still spans one column, and still leaves its neighbour intact. Only the trailing codepoint goes missing, which in Thai is the one carrying the tone: ไม่ (not) and ไม้ (wood) both collapse to ไม. Co-Authored-By: Claude Opus 5 (1M context) --- src/terminal/element.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/terminal/element.rs b/src/terminal/element.rs index 5773955d..5e18f837 100644 --- a/src/terminal/element.rs +++ b/src/terminal/element.rs @@ -2146,6 +2146,15 @@ mod tests { let mut row = wide_cells("\u{2764}"); row[0].marks = Some(Box::from(['\u{FE0F}'])); assert_eq!(segment_row(&row), [cluster(0, 2, "\u{2764}\u{FE0F}")]); + + // Several marks on one base: an above-base vowel and a tone mark both + // sit on the consonant (ที่ = ท U+0E17 + ◌ี U+0E35 + ◌่ U+0E48). + let mut row = vec![cell('\u{0E17}'), cell('a')]; + row[0].marks = Some(Box::from(['\u{0E35}', '\u{0E48}'])); + assert_eq!( + segment_row(&row), + [cluster(0, 1, "\u{0E17}\u{0E35}\u{0E48}"), run(1, 1, "a")] + ); } /// A marked cell never joins a batch: marks add characters without adding