From eb932941715f56297d9c5093b70b6d1d3e88d7c0 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 21 Aug 2025 14:50:16 +0200 Subject: [PATCH] Fix logical order in bidirectional lines (#6796) --- crates/typst-layout/src/inline/line.rs | 2 +- crates/typst-layout/src/inline/prepare.rs | 18 +++++++++++++----- tests/ref/counter-rtl.png | Bin 0 -> 1609 bytes tests/suite/introspection/counter.typ | 9 +++++++++ 4 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 tests/ref/counter-rtl.png diff --git a/crates/typst-layout/src/inline/line.rs b/crates/typst-layout/src/inline/line.rs index 311dc7c69..ba48bfe59 100644 --- a/crates/typst-layout/src/inline/line.rs +++ b/crates/typst-layout/src/inline/line.rs @@ -271,7 +271,7 @@ fn collect_range<'a>( items: &mut Items<'a>, fallback: &mut Option>, ) { - for (idx, (subrange, item)) in p.slice(range.clone()).enumerate() { + for (idx, (subrange, item)) in p.slice(range.clone()) { // All non-text items are just kept, they can't be split. let Item::Text(shaped) = item else { items.push(item, idx); diff --git a/crates/typst-layout/src/inline/prepare.rs b/crates/typst-layout/src/inline/prepare.rs index ab39bdb14..1c876ca94 100644 --- a/crates/typst-layout/src/inline/prepare.rs +++ b/crates/typst-layout/src/inline/prepare.rs @@ -34,8 +34,12 @@ impl<'a> Preparation<'a> { &self.items[idx] } - /// Iterate over the items that intersect the given `sliced` range. - pub fn slice(&self, sliced: Range) -> impl Iterator)> { + /// Iterate over the items that intersect the given `sliced` range alongside + /// their indices in `self.items` and their ranges in the paragraph's text. + pub fn slice( + &self, + sliced: Range, + ) -> impl Iterator))> { // Usually, we don't want empty-range items at the start of the line // (because they will be part of the previous line), but for the first // line, we need to keep them. @@ -43,9 +47,13 @@ impl<'a> Preparation<'a> { 0 => 0, n => self.indices.get(n).copied().unwrap_or(0), }; - self.items[start..].iter().take_while(move |(range, _)| { - range.start < sliced.end || range.end <= sliced.end - }) + self.items + .iter() + .enumerate() + .skip(start) + .take_while(move |(_, (range, _))| { + range.start < sliced.end || range.end <= sliced.end + }) } } diff --git a/tests/ref/counter-rtl.png b/tests/ref/counter-rtl.png new file mode 100644 index 0000000000000000000000000000000000000000..9fc57c2364284f63187abc6f3c041f7dbcf251e2 GIT binary patch literal 1609 zcmV-P2DbT$P)jQROE|*kdVd~ zO%O;04TBWFaU8-SUyg%=j5Ufvw_f zY!ntoVoM0bhB56B*h;vCjl?`tl_$`hc_<6ez1etk|2)v; z%Z&)@yI%YNSlfhX`|ogPs#`iH*D(-W^#BJOfWN~LDFR?L;?)2Xy9km|@t2_?cE} z-C7BpNq;ZiJYH+jVjb--Uj|asBXpo&?|=R0B%t>7HL(f1Hu{B*p583os{W|oLeCNC zduLZjJs5obq7&k_e&KaKAorBg2e`WRmoaPqB)-QUNqowJk8nTP^(k&EB| z3?O4oWnmFelbg2AH6SBgq5|6@k*LR7T`p|uy0a90Pw zgKmJH))u)D(U7eDd1rwW0K2C*W6#b)fVx>p*wZy1U~JW#zR8_iK`DTyb`-lR=k$VB zF2la*Wguw(5SZLn&FVKjUXNlTSuM6`tfxTvUHqz7^{e>-BQHC6F3010XkXRHtU0DPf(IQ-a2 z4_!0bq22^PSFu(Fc=TfqdIT^Mq8zvNhY%I@KF5KrhYkSh@TED&nt`FU&eL2x+=DCF zREj8AcEM-Pet?pE08Y)GHq+h1H{Q^^7*Xx!fne9=U4ZPnV;w;2QYU9uPmi!B{AB n + 2) #context test(c.get(), (100000000004,)) + +--- counter-rtl --- +#set page(width: auto) +#let c = counter("c") +#let s = context c.display() + c.step() +#let tree = [درخت] +#let line = [A #s B #tree #s #tree #s #tree C #s D #s] +#line \ +#line