Compare commits

..

No commits in common. "1e3719a9ba19a9736fe05049baa90b2a7d3b0330" and "13b4677270d61341ff946aa27df28a47a83ae287" have entirely different histories.

6 changed files with 66 additions and 156 deletions

View File

@ -481,7 +481,6 @@ pub enum Repeatable<T> {
impl<T> Repeatable<T> { impl<T> Repeatable<T> {
/// Gets the value inside this repeatable, regardless of whether /// Gets the value inside this repeatable, regardless of whether
/// it repeats. /// it repeats.
#[inline]
pub fn unwrap(&self) -> &T { pub fn unwrap(&self) -> &T {
match self { match self {
Self::Repeated(repeated) => repeated, Self::Repeated(repeated) => repeated,
@ -489,18 +488,7 @@ impl<T> Repeatable<T> {
} }
} }
/// Gets the value inside this repeatable, regardless of whether
/// it repeats.
#[inline]
pub fn unwrap_mut(&mut self) -> &mut T {
match self {
Self::Repeated(repeated) => repeated,
Self::NotRepeated(not_repeated) => not_repeated,
}
}
/// Returns `Some` if the value is repeated, `None` otherwise. /// Returns `Some` if the value is repeated, `None` otherwise.
#[inline]
pub fn as_repeated(&self) -> Option<&T> { pub fn as_repeated(&self) -> Option<&T> {
match self { match self {
Self::Repeated(repeated) => Some(repeated), Self::Repeated(repeated) => Some(repeated),
@ -986,9 +974,6 @@ struct RowGroupData {
span: Span, span: Span,
kind: RowGroupKind, kind: RowGroupKind,
/// Whether this header or footer may repeat.
repeat: bool,
/// Level of this header or footer. /// Level of this header or footer.
repeatable_level: NonZeroU32, repeatable_level: NonZeroU32,
@ -1039,7 +1024,8 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
let mut pending_vlines: Vec<(Span, Line)> = vec![]; let mut pending_vlines: Vec<(Span, Line)> = vec![];
let has_gutter = self.gutter.any(|tracks| !tracks.is_empty()); let has_gutter = self.gutter.any(|tracks| !tracks.is_empty());
let mut headers: Vec<Repeatable<Header>> = vec![]; let mut headers: Vec<Header> = vec![];
let mut repeat_header = false;
// Stores where the footer is supposed to end, its span, and the // Stores where the footer is supposed to end, its span, and the
// actual footer structure. // actual footer structure.
@ -1083,6 +1069,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
&mut pending_hlines, &mut pending_hlines,
&mut pending_vlines, &mut pending_vlines,
&mut headers, &mut headers,
&mut repeat_header,
&mut footer, &mut footer,
&mut repeat_footer, &mut repeat_footer,
&mut auto_index, &mut auto_index,
@ -1102,9 +1089,10 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
row_amount, row_amount,
)?; )?;
let footer = self.finalize_headers_and_footers( let (headers, footer) = self.finalize_headers_and_footers(
has_gutter, has_gutter,
&mut headers, headers,
repeat_header,
footer, footer,
repeat_footer, repeat_footer,
row_amount, row_amount,
@ -1135,7 +1123,8 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
columns: usize, columns: usize,
pending_hlines: &mut Vec<(Span, Line, bool)>, pending_hlines: &mut Vec<(Span, Line, bool)>,
pending_vlines: &mut Vec<(Span, Line)>, pending_vlines: &mut Vec<(Span, Line)>,
headers: &mut Vec<Repeatable<Header>>, headers: &mut Vec<Header>,
repeat_header: &mut bool,
footer: &mut Option<(usize, Span, Footer)>, footer: &mut Option<(usize, Span, Footer)>,
repeat_footer: &mut bool, repeat_footer: &mut bool,
auto_index: &mut usize, auto_index: &mut usize,
@ -1179,12 +1168,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
range: None, range: None,
span, span,
kind: RowGroupKind::Header, kind: RowGroupKind::Header,
repeat,
repeatable_level: level, repeatable_level: level,
top_hlines_start: pending_hlines.len(), top_hlines_start: pending_hlines.len(),
top_hlines_end: None, top_hlines_end: None,
}); });
*repeat_header = repeat;
first_available_row = first_available_row =
find_next_empty_row(resolved_cells, local_auto_index, columns); find_next_empty_row(resolved_cells, local_auto_index, columns);
@ -1209,13 +1199,14 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
row_group_data = Some(RowGroupData { row_group_data = Some(RowGroupData {
range: None, range: None,
span, span,
repeat,
kind: RowGroupKind::Footer, kind: RowGroupKind::Footer,
repeatable_level: NonZeroU32::ONE, repeatable_level: NonZeroU32::ONE,
top_hlines_start: pending_hlines.len(), top_hlines_start: pending_hlines.len(),
top_hlines_end: None, top_hlines_end: None,
}); });
*repeat_footer = repeat;
first_available_row = first_available_row =
find_next_empty_row(resolved_cells, local_auto_index, columns); find_next_empty_row(resolved_cells, local_auto_index, columns);
@ -1530,7 +1521,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
match row_group.kind { match row_group.kind {
RowGroupKind::Header => { RowGroupKind::Header => {
let data = Header { headers.push(Header {
start: group_range.start, start: group_range.start,
// Later on, we have to correct this number in case there // Later on, we have to correct this number in case there
@ -1540,12 +1531,6 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
end: group_range.end, end: group_range.end,
level: row_group.repeatable_level.get(), level: row_group.repeatable_level.get(),
};
headers.push(if row_group.repeat {
Repeatable::Repeated(data)
} else {
Repeatable::NotRepeated(data)
}); });
} }
@ -1567,8 +1552,6 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
level: 1, level: 1,
}, },
)); ));
*repeat_footer = row_group.repeat;
} }
} }
} else { } else {
@ -1742,43 +1725,53 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
fn finalize_headers_and_footers( fn finalize_headers_and_footers(
&self, &self,
has_gutter: bool, has_gutter: bool,
headers: &mut [Repeatable<Header>], headers: Vec<Header>,
repeat_header: bool,
footer: Option<(usize, Span, Footer)>, footer: Option<(usize, Span, Footer)>,
repeat_footer: bool, repeat_footer: bool,
row_amount: usize, row_amount: usize,
) -> SourceResult<Option<Repeatable<Footer>>> { ) -> SourceResult<(Vec<Repeatable<Header>>, Option<Repeatable<Footer>>)> {
// Repeat the gutter below a header (hence why we don't let headers: Vec<Repeatable<Header>> = headers
// subtract 1 from the gutter case). .into_iter()
// Don't do this if there are no rows under the header. .map(|mut header| {
if has_gutter { // Repeat the gutter below a header (hence why we don't
for header in &mut *headers { // subtract 1 from the gutter case).
let header = header.unwrap_mut(); // Don't do this if there are no rows under the header.
if has_gutter {
// Index of first y is doubled, as each row before it
// receives a gutter row below.
header.start *= 2;
// Index of first y is doubled, as each row before it // - 'header.end' is always 'last y + 1'. The header stops
// receives a gutter row below. // before that row.
header.start *= 2; // - Therefore, '2 * header.end' will be 2 * (last y + 1),
// which is the adjusted index of the row before which the
// header stops, meaning it will still stop right before it
// even with gutter thanks to the multiplication below.
// - This means that it will span all rows up to
// '2 * (last y + 1) - 1 = 2 * last y + 1', which equates
// to the index of the gutter row right below the header,
// which is what we want (that gutter spacing should be
// repeated across pages to maintain uniformity).
header.end *= 2;
// - 'header.end' is always 'last y + 1'. The header stops // If the header occupies the entire grid, ensure we don't
// before that row. // include an extra gutter row when it doesn't exist, since
// - Therefore, '2 * header.end' will be 2 * (last y + 1), // the last row of the header is at the very bottom,
// which is the adjusted index of the row before which the // therefore '2 * last y + 1' is not a valid index.
// header stops, meaning it will still stop right before it let row_amount = (2 * row_amount).saturating_sub(1);
// even with gutter thanks to the multiplication below. header.end = header.end.min(row_amount);
// - This means that it will span all rows up to }
// '2 * (last y + 1) - 1 = 2 * last y + 1', which equates header
// to the index of the gutter row right below the header, })
// which is what we want (that gutter spacing should be .map(|header| {
// repeated across pages to maintain uniformity). if repeat_header {
header.end *= 2; Repeatable::Repeated(header)
} else {
// If the header occupies the entire grid, ensure we don't Repeatable::NotRepeated(header)
// include an extra gutter row when it doesn't exist, since }
// the last row of the header is at the very bottom, })
// therefore '2 * last y + 1' is not a valid index. .collect();
let row_amount = (2 * row_amount).saturating_sub(1);
header.end = header.end.min(row_amount);
}
}
let footer = footer let footer = footer
.map(|(footer_end, footer_span, mut footer)| { .map(|(footer_end, footer_span, mut footer)| {
@ -1826,7 +1819,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
} }
}); });
Ok(footer) Ok((headers, footer))
} }
/// Resolves the cell's fields based on grid-wide properties. /// Resolves the cell's fields based on grid-wide properties.
@ -1997,7 +1990,7 @@ fn expand_row_group(
/// Check if a cell's fixed row would conflict with a header or footer. /// Check if a cell's fixed row would conflict with a header or footer.
fn check_for_conflicting_cell_row( fn check_for_conflicting_cell_row(
headers: &[Repeatable<Header>], headers: &[Header],
footer: Option<&(usize, Span, Footer)>, footer: Option<&(usize, Span, Footer)>,
cell_y: usize, cell_y: usize,
rowspan: usize, rowspan: usize,
@ -2008,9 +2001,10 @@ fn check_for_conflicting_cell_row(
// `y + 1 = header.start` holds, that means `y < header.start`, and it // `y + 1 = header.start` holds, that means `y < header.start`, and it
// only occupies one row (`y`), so the cell is actually not in // only occupies one row (`y`), so the cell is actually not in
// conflict. // conflict.
if headers.iter().any(|header| { if headers
cell_y < header.unwrap().end && cell_y + rowspan > header.unwrap().start .iter()
}) { .any(|header| cell_y < header.end && cell_y + rowspan > header.start)
{
bail!( bail!(
"cell would conflict with header spanning the same position"; "cell would conflict with header spanning the same position";
hint: "try moving the cell or the header" hint: "try moving the cell or the header"
@ -2044,7 +2038,7 @@ fn resolve_cell_position(
cell_y: Smart<usize>, cell_y: Smart<usize>,
colspan: usize, colspan: usize,
rowspan: usize, rowspan: usize,
headers: &[Repeatable<Header>], headers: &[Header],
footer: Option<&(usize, Span, Footer)>, footer: Option<&(usize, Span, Footer)>,
resolved_cells: &[Option<Entry>], resolved_cells: &[Option<Entry>],
auto_index: &mut usize, auto_index: &mut usize,
@ -2175,7 +2169,7 @@ fn resolve_cell_position(
/// have cells specified by the user) as well as any headers and footers. /// have cells specified by the user) as well as any headers and footers.
#[inline] #[inline]
fn find_next_available_position<const SKIP_ROWS: bool>( fn find_next_available_position<const SKIP_ROWS: bool>(
headers: &[Repeatable<Header>], headers: &[Header],
footer: Option<&(usize, Span, Footer)>, footer: Option<&(usize, Span, Footer)>,
resolved_cells: &[Option<Entry<'_>>], resolved_cells: &[Option<Entry<'_>>],
columns: usize, columns: usize,
@ -2202,13 +2196,9 @@ fn find_next_available_position<const SKIP_ROWS: bool>(
// would become impractically large before this overflows. // would become impractically large before this overflows.
resolved_index += 1; resolved_index += 1;
} }
// TODO: consider keeping vector of upcoming headers to make this check } else if let Some(header) = headers.iter().find(|header| {
// non-quadratic (O(cells) instead of O(headers * cells)). (header.start * columns..header.end * columns).contains(&resolved_index)
} else if let Some(header) = }) {
headers.iter().map(Repeatable::unwrap).find(|header| {
(header.start * columns..header.end * columns).contains(&resolved_index)
})
{
// Skip header (can't place a cell inside it from outside it). // Skip header (can't place a cell inside it from outside it).
resolved_index = header.end * columns; resolved_index = header.end * columns;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 964 B

View File

@ -414,86 +414,6 @@
..([z],) * 10, ..([z],) * 10,
) )
--- grid-subheaders-non-repeat ---
#set page(height: 8em)
#grid(
grid.header(
[a],
repeat: false,
),
[x],
grid.header(
level: 2,
repeat: false,
[b]
),
..([y],) * 10,
)
--- grid-subheaders-non-repeat-replace ---
#set page(height: 8em)
#grid(
grid.header(
[a]
),
[x],
grid.header(
level: 2,
[b]
),
grid.header(
level: 3,
[c]
),
..([y],) * 9,
grid.header(
level: 2,
[d],
repeat: false,
),
..([z],) * 6,
)
--- grid-subheaders-non-repeating-replace-orphan ---
#set page(height: 8em)
#grid(
grid.header(
[a]
),
[x],
grid.header(
level: 2,
[b]
),
..([y],) * 12,
grid.header(
level: 2,
repeat: false,
[c]
),
..([z],) * 10,
)
--- grid-subheaders-non-repeating-replace-didnt-fit-once ---
#set page(height: 8em)
#grid(
grid.header(
[a]
),
[x],
grid.header(
level: 2,
[b]
),
..([y],) * 10,
grid.header(
level: 2,
repeat: false,
[c\ c\ c]
),
..([z],) * 4,
)
--- grid-subheaders-multi-page-rowspan --- --- grid-subheaders-multi-page-rowspan ---
#set page(height: 8em) #set page(height: 8em)
#grid( #grid(