mirror of
https://github.com/typst/typst
synced 2025-07-16 00:52:54 +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 headers: Vec<Repeatable<Header>> = vec![];
|
||||||
let mut footers: Vec<Repeatable<Footer>> = vec![];
|
let mut footers: Vec<Repeatable<Footer>> = vec![];
|
||||||
|
|
||||||
// If true, there has been at least one cell besides headers and
|
// The first and last rows containing a cell outside a row group, that
|
||||||
// footers. When false, footers at the end are forced to not repeat.
|
// is, outside a header or footer. Headers after the last such row and
|
||||||
let mut at_least_one_cell = false;
|
// 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
|
// 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
|
||||||
@ -1094,7 +1096,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
&mut next_header,
|
&mut next_header,
|
||||||
&mut next_footer,
|
&mut next_footer,
|
||||||
&mut resolved_cells,
|
&mut resolved_cells,
|
||||||
&mut at_least_one_cell,
|
&mut first_last_cell_rows,
|
||||||
child,
|
child,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -1115,7 +1117,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
&mut headers,
|
&mut headers,
|
||||||
&mut footers,
|
&mut footers,
|
||||||
row_amount,
|
row_amount,
|
||||||
at_least_one_cell,
|
first_last_cell_rows,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(CellGrid::new_internal(
|
Ok(CellGrid::new_internal(
|
||||||
@ -1149,7 +1151,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
next_header: &mut usize,
|
next_header: &mut usize,
|
||||||
next_footer: &mut usize,
|
next_footer: &mut usize,
|
||||||
resolved_cells: &mut Vec<Option<Entry<'x>>>,
|
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>,
|
child: ResolvableGridChild<T, I>,
|
||||||
) -> SourceResult<()>
|
) -> SourceResult<()>
|
||||||
where
|
where
|
||||||
@ -1260,13 +1262,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
|
|
||||||
(Some(items), None)
|
(Some(items), None)
|
||||||
}
|
}
|
||||||
ResolvableGridChild::Item(item) => {
|
ResolvableGridChild::Item(item) => (None, Some(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);
|
||||||
@ -1448,6 +1444,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
// no longer appear at the top.
|
// no longer appear at the top.
|
||||||
*top_hlines_end = Some(pending_hlines.len());
|
*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
|
// 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
|
/// an adjacent gutter row to be repeated alongside that header or
|
||||||
/// footer, if there is gutter;
|
/// footer, if there is gutter;
|
||||||
/// 3. Wrap headers and footers in the correct [`Repeatable`] variant.
|
/// 3. Wrap headers and footers in the correct [`Repeatable`] variant.
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn finalize_headers_and_footers(
|
fn finalize_headers_and_footers(
|
||||||
&self,
|
&self,
|
||||||
has_gutter: bool,
|
has_gutter: bool,
|
||||||
headers: &mut [Repeatable<Header>],
|
headers: &mut [Repeatable<Header>],
|
||||||
footers: &mut [Repeatable<Footer>],
|
footers: &mut [Repeatable<Footer>],
|
||||||
row_amount: usize,
|
row_amount: usize,
|
||||||
at_least_one_cell: bool,
|
first_last_cell_rows: Option<(usize, usize)>,
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
// Mark consecutive headers right before the end of the table, or the
|
// Mark consecutive headers right before the end of the table, or the
|
||||||
// final footer, as short lived, given that there are no normal rows
|
// footers at the end, as short lived, given that there are no normal
|
||||||
// after them, so repeating them is pointless.
|
// rows after them, so repeating them is pointless.
|
||||||
//
|
//
|
||||||
// TODO(subfooters): take the last footer if it is at the end and
|
// Same for consecutive footers right after the start of the table or
|
||||||
// backtrack through consecutive footers until the first one in the
|
// any initial headers.
|
||||||
// sequence is found. If there is no footer at the end, there are no
|
if let Some((first_cell_row, last_cell_row)) = first_last_cell_rows {
|
||||||
// haeders to turn short-lived.
|
for header in
|
||||||
//
|
headers.iter_mut().rev().take_while(|h| h.range.start > last_cell_row)
|
||||||
// TODO: interleaved headers and footers?
|
{
|
||||||
let mut first_end_footer = row_amount;
|
header.short_lived = true;
|
||||||
for end_footer in footers.iter().rev() {
|
|
||||||
if end_footer.range.end != first_end_footer {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
first_end_footer = end_footer.range.start;
|
for footer in footers.iter_mut().take_while(|f| f.range.end <= first_cell_row)
|
||||||
}
|
{
|
||||||
|
// TODO(subfooters): short lived
|
||||||
let mut consecutive_header_start = first_end_footer;
|
footer.repeated = false;
|
||||||
for header_at_the_end in headers.iter_mut().rev().take_while(move |h| {
|
}
|
||||||
let at_the_end = h.range.end == consecutive_header_start;
|
} else {
|
||||||
|
// No cells outside headers or footers, so nobody repeats!
|
||||||
consecutive_header_start = h.range.start;
|
for header in &mut *headers {
|
||||||
at_the_end
|
header.short_lived = true;
|
||||||
}) {
|
}
|
||||||
header_at_the_end.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
|
// 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
|
// It also keeps us within the total amount of rows, so we
|
||||||
// don't need to '.min()' later.
|
// don't need to '.min()' later.
|
||||||
footer.range.end = (2 * footer.range.end).saturating_sub(1);
|
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