mirror of
https://github.com/typst/typst
synced 2025-07-15 16:42:53 +08:00
detect short lived headers and footers at the table edges
even if headers and footers are interleaved
This commit is contained in:
parent
f3cc3bdae7
commit
315612b1f7
@ -1042,9 +1042,11 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
let mut headers: Vec<Repeatable<Header>> = vec![];
|
||||
let mut footers: Vec<Repeatable<Footer>> = vec![];
|
||||
|
||||
// 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;
|
||||
// The first and last rows containing a cell outside a row group, that
|
||||
// is, outside a header or footer. Headers after the last such row and
|
||||
// footers before the first such row have no "children" cells and thus
|
||||
// are not repeated.
|
||||
let mut first_last_cell_rows = None;
|
||||
|
||||
// We can't just use the cell's index in the 'cells' vector to
|
||||
// determine its automatic position, since cells could have arbitrary
|
||||
@ -1094,7 +1096,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
&mut next_header,
|
||||
&mut next_footer,
|
||||
&mut resolved_cells,
|
||||
&mut at_least_one_cell,
|
||||
&mut first_last_cell_rows,
|
||||
child,
|
||||
)?;
|
||||
}
|
||||
@ -1115,7 +1117,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
&mut headers,
|
||||
&mut footers,
|
||||
row_amount,
|
||||
at_least_one_cell,
|
||||
first_last_cell_rows,
|
||||
)?;
|
||||
|
||||
Ok(CellGrid::new_internal(
|
||||
@ -1149,7 +1151,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
next_header: &mut usize,
|
||||
next_footer: &mut usize,
|
||||
resolved_cells: &mut Vec<Option<Entry<'x>>>,
|
||||
at_least_one_cell: &mut bool,
|
||||
first_last_cell_rows: &mut Option<(usize, usize)>,
|
||||
child: ResolvableGridChild<T, I>,
|
||||
) -> SourceResult<()>
|
||||
where
|
||||
@ -1260,13 +1262,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
|
||||
(Some(items), None)
|
||||
}
|
||||
ResolvableGridChild::Item(item) => {
|
||||
if matches!(item, ResolvableGridItem::Cell(_)) {
|
||||
*at_least_one_cell = true;
|
||||
}
|
||||
|
||||
(None, Some(item))
|
||||
}
|
||||
ResolvableGridChild::Item(item) => (None, Some(item)),
|
||||
};
|
||||
|
||||
let items = header_footer_items.into_iter().flatten().chain(simple_item);
|
||||
@ -1448,6 +1444,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
// no longer appear at the top.
|
||||
*top_hlines_end = Some(pending_hlines.len());
|
||||
}
|
||||
} else {
|
||||
// This is a cell outside a row group.
|
||||
*first_last_cell_rows = Some(
|
||||
first_last_cell_rows
|
||||
.map(|(first, last)| (first.min(y), last.max(y)))
|
||||
.unwrap_or((y, y)),
|
||||
);
|
||||
}
|
||||
|
||||
// Let's resolve the cell so it can determine its own fields
|
||||
@ -1788,42 +1791,41 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
/// an adjacent gutter row to be repeated alongside that header or
|
||||
/// footer, if there is gutter;
|
||||
/// 3. Wrap headers and footers in the correct [`Repeatable`] variant.
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn finalize_headers_and_footers(
|
||||
&self,
|
||||
has_gutter: bool,
|
||||
headers: &mut [Repeatable<Header>],
|
||||
footers: &mut [Repeatable<Footer>],
|
||||
row_amount: usize,
|
||||
at_least_one_cell: bool,
|
||||
first_last_cell_rows: Option<(usize, usize)>,
|
||||
) -> 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.
|
||||
// footers at the end, 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.
|
||||
//
|
||||
// TODO: interleaved headers and footers?
|
||||
let mut first_end_footer = row_amount;
|
||||
for end_footer in footers.iter().rev() {
|
||||
if end_footer.range.end != first_end_footer {
|
||||
break;
|
||||
// Same for consecutive footers right after the start of the table or
|
||||
// any initial headers.
|
||||
if let Some((first_cell_row, last_cell_row)) = first_last_cell_rows {
|
||||
for header in
|
||||
headers.iter_mut().rev().take_while(|h| h.range.start > last_cell_row)
|
||||
{
|
||||
header.short_lived = true;
|
||||
}
|
||||
|
||||
first_end_footer = end_footer.range.start;
|
||||
}
|
||||
|
||||
let mut consecutive_header_start = first_end_footer;
|
||||
for header_at_the_end in headers.iter_mut().rev().take_while(move |h| {
|
||||
let at_the_end = h.range.end == consecutive_header_start;
|
||||
|
||||
consecutive_header_start = h.range.start;
|
||||
at_the_end
|
||||
}) {
|
||||
header_at_the_end.short_lived = true;
|
||||
for footer in footers.iter_mut().take_while(|f| f.range.end <= first_cell_row)
|
||||
{
|
||||
// TODO(subfooters): short lived
|
||||
footer.repeated = false;
|
||||
}
|
||||
} else {
|
||||
// No cells outside headers or footers, so nobody repeats!
|
||||
for header in &mut *headers {
|
||||
header.short_lived = true;
|
||||
}
|
||||
for footer in &mut *footers {
|
||||
// TODO(subfooters): short lived
|
||||
footer.repeated = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Repeat the gutter below a header (hence why we don't
|
||||
@ -1891,11 +1893,6 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
// It also keeps us within the total amount of rows, so we
|
||||
// don't need to '.min()' later.
|
||||
footer.range.end = (2 * footer.range.end).saturating_sub(1);
|
||||
|
||||
if !at_least_one_cell {
|
||||
// TODO: short-lived (and remove this?)
|
||||
footer.repeated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user