create RowGroupData struct

This commit is contained in:
PgBiel 2025-03-05 16:29:04 -03:00
parent 9da25616a9
commit 2d4a81ec24

View File

@ -908,6 +908,26 @@ struct CellGridResolver<'a, 'b, 'x> {
span: Span, span: Span,
} }
enum RowGroupKind {
Header,
Footer,
}
struct RowGroupData {
/// The range of rows of cells inside this grid row group. The
/// first and last rows are guaranteed to have cells (an exception
/// is made when there is gutter, in which case the group range may
/// be expanded to include an additional gutter row when there is a
/// repeatable header or footer). This is `None` until the first
/// cell of the row group is placed, then it is continually adjusted
/// to fit the cells inside the row group.
///
/// This stays as `None` for fully empty headers and footers.
range: Option<Range<usize>>,
span: Span,
kind: RowGroupKind,
}
impl<'x> CellGridResolver<'_, '_, 'x> { impl<'x> CellGridResolver<'_, '_, 'x> {
fn resolve<T, C, I>(mut self, children: C) -> SourceResult<CellGrid<'x>> fn resolve<T, C, I>(mut self, children: C) -> SourceResult<CellGrid<'x>>
where where
@ -1209,11 +1229,12 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
T: ResolvableCell + Default, T: ResolvableCell + Default,
I: Iterator<Item = ResolvableGridItem<T>>, I: Iterator<Item = ResolvableGridItem<T>>,
{ {
let mut is_header = false; // Data for the row group in this iteration.
let mut is_footer = false; //
// Note that cells outside headers and footers are grid children
// This is true for any header or footer. // with a single cell inside, and thus not considered row groups,
let mut is_row_group = false; // in which case this variable remains 'None'.
let mut row_group_data: Option<RowGroupData> = None;
// The normal auto index should only be stepped (upon placing an // The normal auto index should only be stepped (upon placing an
// automatically-positioned cell, to indicate the position of the // automatically-positioned cell, to indicate the position of the
@ -1227,20 +1248,6 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
// instead, and use a separate counter outside them. // instead, and use a separate counter outside them.
let mut local_auto_index = *auto_index; let mut local_auto_index = *auto_index;
// The range of rows of cells inside this grid row group. The
// first and last rows are guaranteed to have cells (an exception
// is made when there is gutter, in which case the group range may
// be expanded to include an additional gutter row when there is a
// repeatable header or footer). This is 'None' until the first
// cell of the row group is placed, then it is continually adjusted
// to fit the cells inside the row group.
//
// Note that cells outside headers and footers are grid children
// with a single cell inside, and thus not considered row groups,
// in which case this variable remains 'None'.
let mut group_range: Option<Range<usize>> = None;
let mut group_span = Span::detached();
// The first row in which this table group can fit. // The first row in which this table group can fit.
// //
// Within headers and footers, this will correspond to the first // Within headers and footers, this will correspond to the first
@ -1255,9 +1262,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
bail!(span, "cannot have more than one header"); bail!(span, "cannot have more than one header");
} }
is_header = true; row_group_data =
is_row_group = true; Some(RowGroupData { range: None, span, kind: RowGroupKind::Header });
group_span = span;
*repeat_header = repeat; *repeat_header = repeat;
first_available_row = first_available_row =
@ -1281,9 +1288,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
bail!(span, "cannot have more than one footer"); bail!(span, "cannot have more than one footer");
} }
is_footer = true; row_group_data =
is_row_group = true; Some(RowGroupData { range: None, span, kind: RowGroupKind::Footer });
group_span = span;
*repeat_footer = repeat; *repeat_footer = repeat;
first_available_row = first_available_row =
@ -1418,7 +1425,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
&mut local_auto_index, &mut local_auto_index,
first_available_row, first_available_row,
c, c,
is_row_group, row_group_data.is_some(),
) )
.at(cell_span)? .at(cell_span)?
}; };
@ -1449,10 +1456,10 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
// Cell's header or footer must expand to include the cell's // Cell's header or footer must expand to include the cell's
// occupied positions, if possible. // occupied positions, if possible.
if is_row_group { if let Some(RowGroupData { range: group_range, .. }) = &mut row_group_data {
group_range = Some( *group_range = Some(
expand_row_group( expand_row_group(
&*resolved_cells, resolved_cells,
group_range.as_ref(), group_range.as_ref(),
first_available_row, first_available_row,
y, y,
@ -1534,8 +1541,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
} }
} }
} }
if is_row_group {
let group_range = match group_range { if let Some(row_group) = row_group_data {
let group_range = match row_group.range {
Some(group_range) => group_range, Some(group_range) => group_range,
None => { None => {
@ -1572,40 +1580,42 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
} }
}; };
if is_header { match row_group.kind {
if group_range.start != 0 { RowGroupKind::Header => {
bail!( if group_range.start != 0 {
group_span, bail!(
"header must start at the first row"; row_group.span,
hint: "remove any rows before the header" "header must start at the first row";
); hint: "remove any rows before the header"
);
}
*header = Some(Header {
// Later on, we have to correct this number in case there
// is gutter. But only once all cells have been analyzed
// and the header has fully expanded in the fixup loop
// below.
end: group_range.end,
});
} }
*header = Some(Header { RowGroupKind::Footer => {
// Later on, we have to correct this number in case there // Only check if the footer is at the end later, once we know
// is gutter. But only once all cells have been analyzed // the final amount of rows.
// and the header has fully expanded in the fixup loop *footer = Some((
// below. group_range.end,
end: group_range.end, row_group.span,
}); Footer {
} // Later on, we have to correct this number in case there
// is gutter, but only once all cells have been analyzed
if is_footer { // and the header's and footer's exact boundaries are
// Only check if the footer is at the end later, once we know // known. That is because the gutter row immediately
// the final amount of rows. // before the footer might not be included as part of
*footer = Some(( // the footer if it is contained within the header.
group_range.end, start: group_range.start,
group_span, },
Footer { ));
// Later on, we have to correct this number in case there }
// is gutter, but only once all cells have been analyzed
// and the header's and footer's exact boundaries are
// known. That is because the gutter row immediately
// before the footer might not be included as part of
// the footer if it is contained within the header.
start: group_range.start,
},
));
} }
} else { } else {
// The child was a single cell outside headers or footers. // The child was a single cell outside headers or footers.
@ -1848,7 +1858,7 @@ fn resolve_cell_position(
auto_index: &mut usize, auto_index: &mut usize,
first_available_row: usize, first_available_row: usize,
columns: usize, columns: usize,
is_row_group: bool, in_row_group: bool,
) -> HintedStrResult<usize> { ) -> HintedStrResult<usize> {
// Translates a (x, y) position to the equivalent index in the final cell vector. // Translates a (x, y) position to the equivalent index in the final cell vector.
// Errors if the position would be too large. // Errors if the position would be too large.
@ -1925,7 +1935,7 @@ fn resolve_cell_position(
// Ensure it doesn't conflict with an existing header or // Ensure it doesn't conflict with an existing header or
// footer (but only if it isn't already in one, otherwise there // footer (but only if it isn't already in one, otherwise there
// will already be a separate check). // will already be a separate check).
if !is_row_group { if !in_row_group {
check_for_conflicting_cell_row(header, footer, cell_y, rowspan)?; check_for_conflicting_cell_row(header, footer, cell_y, rowspan)?;
} }
@ -1987,7 +1997,7 @@ fn resolve_cell_position(
// Ensure it doesn't conflict with an existing header or // Ensure it doesn't conflict with an existing header or
// footer (but only if it isn't already in one, otherwise there // footer (but only if it isn't already in one, otherwise there
// will already be a separate check). // will already be a separate check).
if !is_row_group { if !in_row_group {
check_for_conflicting_cell_row(header, footer, cell_y, rowspan)?; check_for_conflicting_cell_row(header, footer, cell_y, rowspan)?;
} }