Compare commits

..

No commits in common. "cf062375564ecbdbc01bdea9d6fad731116d4134" and "eba9568ac09fc93736c07d378680e0f7351eb354" have entirely different histories.

6 changed files with 47 additions and 139 deletions

View File

@ -120,10 +120,7 @@ fn write_element(w: &mut Writer, element: &HtmlElement) -> SourceResult<()> {
/// Whether the element should be pretty-printed. /// Whether the element should be pretty-printed.
fn is_pretty(element: &HtmlElement) -> bool { fn is_pretty(element: &HtmlElement) -> bool {
matches!( tag::is_block_by_default(element.tag) || matches!(element.tag, tag::meta)
element.tag,
tag::meta | tag::table | tag::thead | tag::tbody | tag::tfoot | tag::tr
) || tag::is_block_by_default(element.tag)
} }
/// Escape a character. /// Escape a character.

View File

@ -9,9 +9,9 @@ use crate::foundations::{
cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain, cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain,
TargetElem, TargetElem,
}; };
use crate::html::{tag, HtmlAttr, HtmlAttrs, HtmlElem, HtmlTag}; use crate::html::{tag, HtmlAttr, HtmlAttrs, HtmlElem};
use crate::introspection::Locator; use crate::introspection::Locator;
use crate::layout::grid::resolve::{table_to_cellgrid, Cell, CellGrid, Entry}; use crate::layout::grid::resolve::table_to_cellgrid;
use crate::layout::{ use crate::layout::{
show_grid_cell, Abs, Alignment, BlockElem, Celled, GridCell, GridFooter, GridHLine, show_grid_cell, Abs, Alignment, BlockElem, Celled, GridCell, GridFooter, GridHLine,
GridHeader, GridVLine, Length, OuterHAlignment, OuterVAlignment, Rel, Sides, GridHeader, GridVLine, Length, OuterHAlignment, OuterVAlignment, Rel, Sides,
@ -262,61 +262,34 @@ impl TableElem {
type TableFooter; type TableFooter;
} }
fn show_cell_html(tag: HtmlTag, cell: &Cell, styles: StyleChain) -> Content {
let cell = cell.body.clone();
let Some(cell) = cell.to_packed::<TableCell>() else { return cell };
let mut attrs = HtmlAttrs::default();
let span = |n: NonZeroUsize| (n != NonZeroUsize::MIN).then(|| n.to_string());
if let Some(colspan) = span(cell.colspan(styles)) {
attrs.push(HtmlAttr::constant("colspan"), colspan);
}
if let Some(rowspan) = span(cell.rowspan(styles)) {
attrs.push(HtmlAttr::constant("rowspan"), rowspan);
}
HtmlElem::new(tag)
.with_body(Some(cell.body.clone()))
.with_attrs(attrs)
.pack()
.spanned(cell.span())
}
fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content {
let elem = |tag, body| HtmlElem::new(tag).with_body(Some(body)).pack();
let mut rows: Vec<_> = grid.entries.chunks(grid.cols.len()).collect();
let tr = |tag, row: &[Entry]| {
let row = row
.iter()
.flat_map(|entry| entry.as_cell())
.map(|cell| show_cell_html(tag, cell, styles));
elem(tag::tr, Content::sequence(row))
};
let footer = grid.footer.map(|ft| {
let rows = rows.drain(ft.unwrap().start..);
elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row))))
});
let header = grid.header.map(|hd| {
let rows = rows.drain(..hd.unwrap().end);
elem(tag::thead, Content::sequence(rows.map(|row| tr(tag::th, row))))
});
let mut body = Content::sequence(rows.into_iter().map(|row| tr(tag::td, row)));
if header.is_some() || footer.is_some() {
body = elem(tag::tbody, body);
}
let content = header.into_iter().chain(core::iter::once(body)).chain(footer);
elem(tag::table, Content::sequence(content))
}
impl Show for Packed<TableElem> { impl Show for Packed<TableElem> {
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(if TargetElem::target_in(styles).is_html() { Ok(if TargetElem::target_in(styles).is_html() {
// TODO: This is a hack, it is not clear whether the locator is actually used by HTML. // TODO: This is a hack, it is not clear whether the locator is actually used by HTML.
// How can we find out whether locator is actually used? // How can we find out whether locator is actually used?
let locator = Locator::root(); let locator = Locator::root();
show_cellgrid_html(table_to_cellgrid(self, engine, locator, styles)?, styles) let elem = |tag, body| HtmlElem::new(tag).with_body(Some(body)).pack();
let grid = table_to_cellgrid(self, engine, locator, styles)?;
let rows = grid.entries.chunks(grid.cols.len()).map(|row| {
let row = row.iter().flat_map(|entry| entry.as_cell());
elem(tag::tr, Content::sequence(row.map(|cell| cell.body.clone())))
});
let mut rows: Vec<_> = rows.collect();
let footer = grid.footer.map(|ft| {
elem(tag::tfoot, Content::sequence(rows.drain(ft.unwrap().start..)))
});
let header = grid.header.map(|hd| {
elem(tag::thead, Content::sequence(rows.drain(..hd.unwrap().end)))
});
let mut body = Content::sequence(rows);
if header.is_some() || footer.is_some() {
body = elem(tag::tbody, body);
}
let content = header.into_iter().chain(core::iter::once(body)).chain(footer);
elem(tag::table, Content::sequence(content))
} else { } else {
BlockElem::multi_layouter(self.clone(), engine.routines.layout_table).pack() BlockElem::multi_layouter(self.clone(), engine.routines.layout_table).pack()
} }
@ -764,7 +737,20 @@ cast! {
impl Show for Packed<TableCell> { impl Show for Packed<TableCell> {
fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
show_grid_cell(self.body.clone(), self.inset(styles), self.align(styles)) if TargetElem::target_in(styles).is_html() {
let mut attrs = HtmlAttrs::default();
let span = |n: NonZeroUsize| (n != NonZeroUsize::MIN).then(|| n.to_string());
if let Some(colspan) = span(self.colspan(styles)) {
attrs.push(HtmlAttr::constant("colspan"), colspan);
}
if let Some(rowspan) = span(self.rowspan(styles)) {
attrs.push(HtmlAttr::constant("rowspan"), rowspan);
}
let body = Some(self.body.clone());
Ok(HtmlElem::new(tag::td).with_body(body).with_attrs(attrs).pack())
} else {
show_grid_cell(self.body.clone(), self.inset(styles), self.align(styles))
}
} }
} }

View File

@ -228,8 +228,6 @@ static EXCEPTION_MAP: phf::Map<&'static str, Exception> = phf::phf_map! {
.style(FontStyle::Oblique), .style(FontStyle::Oblique),
"NewCMSans10-Regular" => Exception::new() "NewCMSans10-Regular" => Exception::new()
.family("New Computer Modern Sans"), .family("New Computer Modern Sans"),
"NewCMSansMath-Regular" => Exception::new()
.family("New Computer Modern Sans Math"),
"NewCMUncial08-Bold" => Exception::new() "NewCMUncial08-Bold" => Exception::new()
.family("New Computer Modern Uncial 08"), .family("New Computer Modern Uncial 08"),
"NewCMUncial08-Book" => Exception::new() "NewCMUncial08-Book" => Exception::new()

View File

@ -1605,12 +1605,10 @@ impl AtNewline {
_ => true, _ => true,
}, },
AtNewline::StopParBreak => parbreak, AtNewline::StopParBreak => parbreak,
AtNewline::RequireColumn(min_col) => { AtNewline::RequireColumn(min_col) => match column {
// Don't stop if this newline doesn't start a column (this may Some(column) => column <= min_col,
// be checked on the boundary of lexer modes, since we only None => false, // Don't stop if we had no column.
// report a column in Markup). },
column.is_some_and(|column| column <= min_col)
}
} }
} }
} }
@ -1705,13 +1703,10 @@ impl<'s> Parser<'s> {
self.token.newline.is_some() self.token.newline.is_some()
} }
/// The number of characters until the most recent newline from the start of /// The number of characters until the most recent newline from the current
/// the current token. Uses a cached value from the newline mode if present. /// token, or 0 if it did not follow a newline.
fn current_column(&self) -> usize { fn current_column(&self) -> usize {
self.token self.token.newline.and_then(|newline| newline.column).unwrap_or(0)
.newline
.and_then(|newline| newline.column)
.unwrap_or_else(|| self.lexer.column(self.token.start))
} }
/// The current token's text. /// The current token's text.

View File

@ -5,31 +5,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
</head> </head>
<body> <body>
<table> <table><thead><tr><td>The</td><td>first</td><td>and</td></tr><tr><td>the</td><td>second</td><td>row</td></tr></thead><tbody><tr><td>Foo</td><td rowspan="2">Baz</td><td>Bar</td></tr><tr><td>1</td><td>2</td></tr><tr><td colspan="2">3</td><td>4</td></tr></tbody><tfoot><tr><td>The</td><td>last</td><td>row</td></tr></tfoot></table>
<thead>
<tr>
<th>The</th><th>first</th><th>and</th>
</tr>
<tr>
<th>the</th><th>second</th><th>row</th>
</tr>
</thead>
<tbody>
<tr>
<td>Foo</td><td rowspan="2">Baz</td><td>Bar</td>
</tr>
<tr>
<td>1</td><td>2</td>
</tr>
<tr>
<td colspan="2">3</td><td>4</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>The</td><td>last</td><td>row</td>
</tr>
</tfoot>
</table>
</body> </body>
</html> </html>

View File

@ -77,49 +77,6 @@ _Shopping list_
#test(indented, manual) #test(indented, manual)
--- list-indent-bracket-nesting ---
// Test list indent nesting behavior when directly at a starting bracket.
#let indented = {
[- indented
- less
]
[- indented
- same
- then less
- then same
]
[- indented
- more
- then same
- then less
]
}
#let item = list.item
#let manual = {
{
item[indented]; [ ]
item[less]; [ ]
}
{
item[indented]; [ ]
item[same]; [ ]
item[then less #{
item[then same]
}]; [ ]
}
{
item[indented #{
item[more]
}]; [ ]
item[then same]; [ ]
item[then less]; [ ]
}
}
#test(indented, manual)
--- list-tabs --- --- list-tabs ---
// This works because tabs are used consistently. // This works because tabs are used consistently.
- A with 1 tab - A with 1 tab