diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index 6b6d7cae0..b0505bc32 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -219,21 +219,47 @@ impl<'a> GridLayouter<'a> { if first_header.unwrap().range().contains(&y) { consecutive_header_count += 1; - if self.upcoming_headers.get(consecutive_header_count).is_none_or( - |h| { - h.unwrap().start > first_header.unwrap().end - || h.unwrap().level <= first_header.unwrap().level - }, - ) { - // Next row either isn't a header. or is in a - // conflicting one, which is the sign that we need to go. - self.place_new_headers( - first_header, - consecutive_header_count, - engine, - )?; - consecutive_header_count = 0; + // TODO: surely there is a better way to do this + match self.upcoming_headers.get(consecutive_header_count) { + // No more headers, so place the latest headers. + None => { + self.place_new_headers( + consecutive_header_count, + None, + engine, + )?; + consecutive_header_count = 0; + } + // Next header is not consecutive, so place the latest headers. + Some(next_header) + if next_header.unwrap().start > first_header.unwrap().end => + { + self.place_new_headers( + consecutive_header_count, + None, + engine, + )?; + consecutive_header_count = 0; + } + // Next header is consecutive and conflicts with one or + // more of the latest consecutive headers, so we must + // place them before proceeding. + Some(next_header) + if next_header.unwrap().level + <= first_header.unwrap().level => + { + self.place_new_headers( + consecutive_header_count, + Some(next_header), + engine, + )?; + consecutive_header_count = 0; + } + // Next header is a non-conflicting consecutive header. + // Keep collecting more headers. + _ => {} } + y = first_header.unwrap().end; // Skip header rows during normal layout. continue; diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index 98eb7f77f..6ba023fe7 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -24,28 +24,21 @@ pub enum HeadersToLayout<'a> { impl<'a> GridLayouter<'a> { pub fn place_new_headers( &mut self, - first_header: &Repeatable
, consecutive_header_count: usize, + conflicting_header: Option<&Repeatable
>, engine: &mut Engine, ) -> SourceResult<()> { - // Next row either isn't a header. or is in a - // conflicting one, which is the sign that we need to go. let (consecutive_headers, new_upcoming_headers) = self.upcoming_headers.split_at(consecutive_header_count); self.upcoming_headers = new_upcoming_headers; - let (non_conflicting_headers, conflicting_headers) = match self - .upcoming_headers - .get(consecutive_header_count) - .map(Repeatable::unwrap) - { - Some(next_header) if next_header.level <= first_header.unwrap().level => { + let (non_conflicting_headers, conflicting_headers) = match conflicting_header { + Some(conflicting_header) => { // All immediately conflicting headers will // be placed as normal rows. - consecutive_headers.split_at( - consecutive_headers - .partition_point(|h| next_header.level > h.unwrap().level), - ) + consecutive_headers.split_at(consecutive_headers.partition_point(|h| { + conflicting_header.unwrap().level > h.unwrap().level + })) } _ => (consecutive_headers, Default::default()), };