Compare commits

...

3 Commits

Author SHA1 Message Date
PgBiel
9c49bd507a remove redundant check for short-lived footers
Now it is all handled at the resolving stage.
2025-04-20 19:22:19 -03:00
PgBiel
03118678b5 tests for short-lived footer 2025-04-20 19:18:48 -03:00
PgBiel
63b34cfe0a make footer short-lived when there are no regular cells 2025-04-20 19:18:18 -03:00
5 changed files with 44 additions and 5 deletions

View File

@ -1486,12 +1486,18 @@ impl<'a> GridLayouter<'a> {
} else { } else {
false false
} }
} else if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { } else if let Some(Repeatable::Repeated(_)) = &self.grid.footer {
// If no rows other than the footer have been laid out so far, // If no rows other than the footer have been laid out so far,
// and there are rows beside the footer, then don't lay it out // and there are rows beside the footer, then don't lay it out
// at all. (Similar check from above, but for the case without // at all. (Similar check from above, but for the case without
// headers.) // headers.)
// TODO: widow prevention for non-repeated footers with a //
// It is worth noting that the footer is made non-repeatable at
// the grid resolving stage if it is short-lived, that is, if
// it is at the start of the table (or right after headers at
// the start of the table).
// TODO(subfooters): explicitly check for short-lived footers.
// TODO(subfooters): widow prevention for non-repeated footers with a
// similar mechanism / when implementing multiple footers. // similar mechanism / when implementing multiple footers.
self.lrows.is_empty() self.lrows.is_empty()
&& may_progress_with_offset( && may_progress_with_offset(
@ -1502,7 +1508,6 @@ impl<'a> GridLayouter<'a> {
// zero anyway. // zero anyway.
self.current.header_height + self.current.footer_height, self.current.header_height + self.current.footer_height,
) )
&& footer.start != 0
} else { } else {
false false
}; };

View File

@ -1063,6 +1063,10 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
let mut footer: Option<(usize, Span, Footer)> = None; let mut footer: Option<(usize, Span, Footer)> = None;
let mut repeat_footer = false; let mut repeat_footer = false;
// If true, there has been at least one cell besides headers and
// footers. When false, footers at the end are forced to not repeat.
let mut at_least_one_cell = false;
// We can't just use the cell's index in the 'cells' vector to // We can't just use the cell's index in the 'cells' vector to
// determine its automatic position, since cells could have arbitrary // determine its automatic position, since cells could have arbitrary
// positions, so the position of a cell in 'cells' can differ from its // positions, so the position of a cell in 'cells' can differ from its
@ -1104,6 +1108,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
&mut repeat_footer, &mut repeat_footer,
&mut auto_index, &mut auto_index,
&mut resolved_cells, &mut resolved_cells,
&mut at_least_one_cell,
child, child,
)?; )?;
} }
@ -1125,6 +1130,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
footer, footer,
repeat_footer, repeat_footer,
row_amount, row_amount,
at_least_one_cell,
)?; )?;
Ok(CellGrid::new_internal( Ok(CellGrid::new_internal(
@ -1157,6 +1163,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
repeat_footer: &mut bool, repeat_footer: &mut bool,
auto_index: &mut usize, auto_index: &mut usize,
resolved_cells: &mut Vec<Option<Entry<'x>>>, resolved_cells: &mut Vec<Option<Entry<'x>>>,
at_least_one_cell: &mut bool,
child: ResolvableGridChild<T, I>, child: ResolvableGridChild<T, I>,
) -> SourceResult<()> ) -> SourceResult<()>
where where
@ -1240,7 +1247,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
(Some(items), None) (Some(items), None)
} }
ResolvableGridChild::Item(item) => (None, Some(item)), ResolvableGridChild::Item(item) => {
if matches!(item, ResolvableGridItem::Cell(_)) {
*at_least_one_cell = true;
}
(None, Some(item))
}
}; };
let items = header_footer_items.into_iter().flatten().chain(simple_item); let items = header_footer_items.into_iter().flatten().chain(simple_item);
@ -1784,6 +1797,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
footer: Option<(usize, Span, Footer)>, footer: Option<(usize, Span, Footer)>,
repeat_footer: bool, repeat_footer: bool,
row_amount: usize, row_amount: usize,
at_least_one_cell: bool,
) -> SourceResult<Option<Repeatable<Footer>>> { ) -> SourceResult<Option<Repeatable<Footer>>> {
// Repeat the gutter below a header (hence why we don't // Repeat the gutter below a header (hence why we don't
// subtract 1 from the gutter case). // subtract 1 from the gutter case).
@ -1856,7 +1870,11 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
}) })
.transpose()? .transpose()?
.map(|footer| { .map(|footer| {
if repeat_footer { // Don't repeat footers when the table only has headers and
// footers.
// TODO(subfooters): Switch this to marking the last N
// consecutive footers as short lived.
if repeat_footer && at_least_one_cell {
Repeatable::Repeated(footer) Repeatable::Repeated(footer)
} else { } else {
Repeatable::NotRepeated(footer) Repeatable::NotRepeated(footer)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 B

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

View File

@ -788,3 +788,19 @@
[a], [a],
) )
) )
--- grid-subheaders-alone-with-gutter-and-footer-no-orphan-prevention ---
#set page(height: 5.5em)
#table(
gutter: 4pt,
table.header(
[L1]
),
table.header(
level: 2,
[L2]
),
table.footer(
[a],
)
)