diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index a8b5a2c9c..d659702fe 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -1827,6 +1827,28 @@ impl<'x> CellGridResolver<'_, '_, 'x> { row_amount: usize, at_least_one_cell: bool, ) -> SourceResult>> { + // Mark consecutive headers right before the end of the table, or the + // final footer, as short lived, given that there are no normal rows + // after them, so repeating them is pointless. + // + // It is important to do this BEFORE we update header and footer ranges + // due to gutter below as 'row_amount' doesn't consider gutter. + // + // TODO(subfooters): take the last footer if it is at the end and + // backtrack through consecutive footers until the first one in the + // sequence is found. If there is no footer at the end, there are no + // haeders to turn short-lived. + let mut consecutive_header_start = + footer.as_ref().map(|(_, _, f)| f.start).unwrap_or(row_amount); + for header_at_the_end in headers.iter_mut().rev().take_while(move |h| { + let at_the_end = h.end == consecutive_header_start; + + consecutive_header_start = h.start; + at_the_end + }) { + header_at_the_end.unwrap_mut().short_lived = true; + } + // Repeat the gutter below a header (hence why we don't // subtract 1 from the gutter case). // Don't do this if there are no rows under the header. @@ -1917,25 +1939,6 @@ impl<'x> CellGridResolver<'_, '_, 'x> { } }); - // Mark consecutive headers right before the end of the table, or the - // final footer, as short lived, given that there are no normal rows - // after them, so repeating them is pointless. - // - // TODO(subfooters): take the last footer if it is at the end and - // backtrack through consecutive footers until the first one in the - // sequence is found. If there is no footer at the end, there are no - // haeders to turn short-lived. - let mut consecutive_header_start = - footer.as_ref().map(|f| f.start).unwrap_or(row_amount); - for header_at_the_end in headers.iter_mut().rev().take_while(move |h| { - let at_the_end = h.end == consecutive_header_start; - - consecutive_header_start = h.start; - at_the_end - }) { - header_at_the_end.unwrap_mut().short_lived = true; - } - Ok(footer) } diff --git a/tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.png b/tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.png new file mode 100644 index 000000000..17bf3fe4f Binary files /dev/null and b/tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.png differ diff --git a/tests/suite/layout/grid/subheaders.typ b/tests/suite/layout/grid/subheaders.typ index 24b88f8ac..760809d74 100644 --- a/tests/suite/layout/grid/subheaders.typ +++ b/tests/suite/layout/grid/subheaders.typ @@ -824,6 +824,22 @@ ), ) +--- grid-subheaders-alone-with-gutter-no-orphan-prevention --- +#set page(height: 5.3em) +#v(2em) +#grid( + gutter: 3pt, + grid.header( + // ( + [L1] + ), + grid.header( + // ( + level: 2, + [L2] + ), +) + --- grid-subheaders-alone-with-footer --- #table( table.header(