From 240f238eee4d6dfce7e3c4cabb9315ad052ca230 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Sun, 23 Feb 2025 08:26:14 -0300 Subject: [PATCH 01/12] Fix HTML export of table with gutter (#5920) --- .../typst-library/src/layout/grid/resolve.rs | 21 +++++++++++---- crates/typst-library/src/model/table.rs | 2 +- tests/ref/html/col-gutter-table.html | 26 ++++++++++++++++++ tests/ref/html/col-row-gutter-table.html | 26 ++++++++++++++++++ tests/ref/html/row-gutter-table.html | 26 ++++++++++++++++++ tests/suite/layout/grid/html.typ | 27 +++++++++++++++++++ 6 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 tests/ref/html/col-gutter-table.html create mode 100644 tests/ref/html/col-row-gutter-table.html create mode 100644 tests/ref/html/row-gutter-table.html diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index f6df57a37..762f94ed0 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -1526,11 +1526,7 @@ impl<'a> CellGrid<'a> { self.entry(x, y).map(|entry| match entry { Entry::Cell(_) => Axes::new(x, y), Entry::Merged { parent } => { - let c = if self.has_gutter { - 1 + self.cols.len() / 2 - } else { - self.cols.len() - }; + let c = self.non_gutter_column_count(); let factor = if self.has_gutter { 2 } else { 1 }; Axes::new(factor * (*parent % c), factor * (*parent / c)) } @@ -1602,6 +1598,21 @@ impl<'a> CellGrid<'a> { cell.rowspan.get() } } + + #[inline] + pub fn non_gutter_column_count(&self) -> usize { + if self.has_gutter { + // Calculation: With gutters, we have + // 'cols = 2 * (non-gutter cols) - 1', since there is a gutter + // column between each regular column. Therefore, + // 'floor(cols / 2)' will be equal to + // 'floor(non-gutter cols - 1/2) = non-gutter-cols - 1', + // so 'non-gutter cols = 1 + floor(cols / 2)'. + 1 + self.cols.len() / 2 + } else { + self.cols.len() + } + } } /// Given a cell's requested x and y, the vector with the resolved cell diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs index 82c1cc08b..6f4461bd4 100644 --- a/crates/typst-library/src/model/table.rs +++ b/crates/typst-library/src/model/table.rs @@ -282,7 +282,7 @@ fn show_cell_html(tag: HtmlTag, cell: &Cell, styles: StyleChain) -> Content { 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 mut rows: Vec<_> = grid.entries.chunks(grid.non_gutter_column_count()).collect(); let tr = |tag, row: &[Entry]| { let row = row diff --git a/tests/ref/html/col-gutter-table.html b/tests/ref/html/col-gutter-table.html new file mode 100644 index 000000000..54170f534 --- /dev/null +++ b/tests/ref/html/col-gutter-table.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + +
abc
def
ghi
+ + diff --git a/tests/ref/html/col-row-gutter-table.html b/tests/ref/html/col-row-gutter-table.html new file mode 100644 index 000000000..54170f534 --- /dev/null +++ b/tests/ref/html/col-row-gutter-table.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + +
abc
def
ghi
+ + diff --git a/tests/ref/html/row-gutter-table.html b/tests/ref/html/row-gutter-table.html new file mode 100644 index 000000000..54170f534 --- /dev/null +++ b/tests/ref/html/row-gutter-table.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + +
abc
def
ghi
+ + diff --git a/tests/suite/layout/grid/html.typ b/tests/suite/layout/grid/html.typ index 2a7dfc2ce..10345cb06 100644 --- a/tests/suite/layout/grid/html.typ +++ b/tests/suite/layout/grid/html.typ @@ -30,3 +30,30 @@ [row], ), ) + +--- col-gutter-table html --- +#table( + columns: 3, + column-gutter: 3pt, + [a], [b], [c], + [d], [e], [f], + [g], [h], [i] +) + +--- row-gutter-table html --- +#table( + columns: 3, + row-gutter: 3pt, + [a], [b], [c], + [d], [e], [f], + [g], [h], [i] +) + +--- col-row-gutter-table html --- +#table( + columns: 3, + gutter: 3pt, + [a], [b], [c], + [d], [e], [f], + [g], [h], [i] +) From 55bc5f4c940c86377f1ffe25b42fdb01a6827358 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 23 Feb 2025 11:28:24 +0000 Subject: [PATCH 02/12] Make math shorthands noncontinuable (#5925) --- crates/typst-syntax/src/parser.rs | 9 +++++---- tests/ref/math-shorthands-noncontinuable.png | Bin 0 -> 475 bytes tests/suite/math/syntax.typ | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 tests/ref/math-shorthands-noncontinuable.png diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs index e187212da..c5d13c8b3 100644 --- a/crates/typst-syntax/src/parser.rs +++ b/crates/typst-syntax/src/parser.rs @@ -271,10 +271,11 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { } SyntaxKind::Text | SyntaxKind::MathText | SyntaxKind::MathShorthand => { - continuable = matches!( - math_class(p.current_text()), - None | Some(MathClass::Alphabetic) - ); + continuable = !p.at(SyntaxKind::MathShorthand) + && matches!( + math_class(p.current_text()), + None | Some(MathClass::Alphabetic) + ); if !maybe_delimited(p) { p.eat(); } diff --git a/tests/ref/math-shorthands-noncontinuable.png b/tests/ref/math-shorthands-noncontinuable.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1ad1d14e0ebda63769157fe6a64631dfe58a31 GIT binary patch literal 475 zcmV<10VMv3P)LBEL@~mBuQWyMo>h%CY9761u02MG_@Qx zNm5Z8=fpv+UoiJT-FGuDvw0Smd+zA~qI7VW!yM)?CG6I?KurPr7jBGuE$I%VUVB2D(T@AvTS9$n7S&jjwZk@Yt{W{Hq;&9BN(G8cHT|SwLGrPxe zP=(}Hk1U(3c-niIlHzCF1FwJy%pZIKrjfx&3d5s9fAkE?u2W_@GSiPaKVXVkjKqFc zUs^FK+Sf_)K$--$8)y6^F!)?R0^j&+&lGTQePXOa0oS0ympu;uF}NYrp+Es2nVj_j z3RoOTxR!_(`ju-EcqGtSWd>hWerhD<9tURd%c|j{Rrhx`^UA{)jyrp^<@7qS*~$#= zv5?eSw%SmpD+~Z~9@9`5mS9k9)#A1`h2N?PQ&JcXOI_f_BI-BtEJvo=GJ6=ra{fs) ztDQznf<0WXV2Gc^=wwtNfqmKO0tpPZERew3w}%h~?DLK5`Lf4h4s-Y)z~4s$EOM5) RtCj!&002ovPDHLkV1k2W)8YUC literal 0 HcmV?d00001 diff --git a/tests/suite/math/syntax.typ b/tests/suite/math/syntax.typ index cd1124c37..7091d908c 100644 --- a/tests/suite/math/syntax.typ +++ b/tests/suite/math/syntax.typ @@ -13,6 +13,11 @@ $ underline(f' : NN -> RR) \ 1 - 0 thick &..., ) $ +--- math-shorthands-noncontinuable --- +// Test that shorthands are not continuable. +$ x >=(y) / z \ + x >= (y) / z $ + --- math-common-symbols --- // Test common symbols. $ dot \ dots \ ast \ tilde \ star $ From 56f4fa2b4d4d772c5b19c9842419dcc4e078744b Mon Sep 17 00:00:00 2001 From: Malo <57839069+MDLC01@users.noreply.github.com> Date: Sun, 23 Feb 2025 12:31:28 +0100 Subject: [PATCH 03/12] Documentation improvements (#5888) --- crates/typst-library/src/foundations/symbol.rs | 1 + crates/typst-library/src/visualize/color.rs | 2 +- crates/typst-library/src/visualize/gradient.rs | 11 +++++------ docs/reference/groups.yml | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/typst-library/src/foundations/symbol.rs b/crates/typst-library/src/foundations/symbol.rs index 8a80506fe..2c391ee4c 100644 --- a/crates/typst-library/src/foundations/symbol.rs +++ b/crates/typst-library/src/foundations/symbol.rs @@ -21,6 +21,7 @@ use crate::foundations::{ /// be accessed using [field access notation]($scripting/#fields): /// /// - General symbols are defined in the [`sym` module]($category/symbols/sym) +/// and are accessible without the `sym.` prefix in math mode. /// - Emoji are defined in the [`emoji` module]($category/symbols/emoji) /// /// Moreover, you can define custom symbols with this type's constructor diff --git a/crates/typst-library/src/visualize/color.rs b/crates/typst-library/src/visualize/color.rs index b14312513..20b0f5719 100644 --- a/crates/typst-library/src/visualize/color.rs +++ b/crates/typst-library/src/visualize/color.rs @@ -130,7 +130,7 @@ static TO_SRGB: LazyLock = LazyLock::new(|| { /// /// # Predefined color maps /// Typst also includes a number of preset color maps that can be used for -/// [gradients]($gradient.linear). These are simply arrays of colors defined in +/// [gradients]($gradient/#stops). These are simply arrays of colors defined in /// the module `color.map`. /// /// ```example diff --git a/crates/typst-library/src/visualize/gradient.rs b/crates/typst-library/src/visualize/gradient.rs index d6530dd09..1a723a9f5 100644 --- a/crates/typst-library/src/visualize/gradient.rs +++ b/crates/typst-library/src/visualize/gradient.rs @@ -70,6 +70,9 @@ use crate::visualize::{Color, ColorSpace, WeightedColor}; /// the offsets when defining a gradient. In this case, Typst will space all /// stops evenly. /// +/// Typst predefines color maps that you can use as stops. See the +/// [`color`]($color/#predefined-color-maps) documentation for more details. +/// /// # Relativeness /// The location of the `{0%}` and `{100%}` stops depends on the dimensions /// of a container. This container can either be the shape that it is being @@ -157,10 +160,6 @@ use crate::visualize::{Color, ColorSpace, WeightedColor}; /// ) /// ``` /// -/// # Presets -/// Typst predefines color maps that you can use with your gradients. See the -/// [`color`]($color/#predefined-color-maps) documentation for more details. -/// /// # Note on file sizes /// /// Gradients can be quite large, especially if they have many stops. This is @@ -288,7 +287,7 @@ impl Gradient { /// )), /// ) /// ``` - #[func] + #[func(title = "Radial Gradient")] fn radial( span: Span, /// The color [stops](#stops) of the gradient. @@ -402,7 +401,7 @@ impl Gradient { /// )), /// ) /// ``` - #[func] + #[func(title = "Conic Gradient")] pub fn conic( span: Span, /// The color [stops](#stops) of the gradient. diff --git a/docs/reference/groups.yml b/docs/reference/groups.yml index 961d675dc..8fea3a1f2 100644 --- a/docs/reference/groups.yml +++ b/docs/reference/groups.yml @@ -170,8 +170,8 @@ category: symbols path: ["emoji"] details: | - Named emoji. + Named emojis. For example, `#emoji.face` produces the 😀 emoji. If you frequently use certain emojis, you can also import them from the `emoji` module (`[#import - emoji: face]`) to use them without the `#emoji.` prefix. + emoji: face]`) to use them without the `emoji.` prefix. From ebe25432641a729780578a2440eaf9fb07c80e38 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 24 Feb 2025 12:17:31 +0100 Subject: [PATCH 04/12] Fix comparison of `Func` and `NativeFuncData` (#5943) --- crates/typst-library/src/foundations/func.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/typst-library/src/foundations/func.rs b/crates/typst-library/src/foundations/func.rs index 3ed1562f6..66c6b70a5 100644 --- a/crates/typst-library/src/foundations/func.rs +++ b/crates/typst-library/src/foundations/func.rs @@ -437,10 +437,10 @@ impl PartialEq for Func { } } -impl PartialEq<&NativeFuncData> for Func { - fn eq(&self, other: &&NativeFuncData) -> bool { +impl PartialEq<&'static NativeFuncData> for Func { + fn eq(&self, other: &&'static NativeFuncData) -> bool { match &self.repr { - Repr::Native(native) => native.function == other.function, + Repr::Native(native) => *native == Static(*other), _ => false, } } From 69c3f957051358eff961addbcae4ff02448513dc Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 24 Feb 2025 13:28:01 +0100 Subject: [PATCH 05/12] Bump MSRV to 1.83 and Rust in CI to 1.85 (#5946) --- .github/workflows/ci.yml | 6 +++--- .github/workflows/release.yml | 2 +- Cargo.toml | 2 +- crates/typst-cli/src/compile.rs | 2 +- crates/typst-ide/src/complete.rs | 2 +- crates/typst-layout/src/grid/layouter.rs | 8 ++++---- crates/typst-layout/src/grid/lines.rs | 2 +- crates/typst-layout/src/grid/rowspans.rs | 2 +- crates/typst-layout/src/inline/line.rs | 4 ++-- crates/typst-layout/src/inline/linebreak.rs | 4 ++-- crates/typst-layout/src/inline/shaping.rs | 6 +++--- crates/typst-library/src/foundations/symbol.rs | 2 +- crates/typst-library/src/layout/grid/resolve.rs | 2 +- crates/typst-library/src/text/font/book.rs | 2 +- crates/typst-library/src/text/shift.rs | 2 +- crates/typst-pdf/src/outline.rs | 4 ++-- crates/typst-syntax/src/node.rs | 2 +- crates/typst-syntax/src/package.rs | 4 ++-- crates/typst-utils/src/scalar.rs | 13 +------------ flake.lock | 6 +++--- flake.nix | 2 +- tests/src/collect.rs | 4 ++-- tests/src/run.rs | 2 +- 23 files changed, 37 insertions(+), 48 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01b3e8c3a..9f0ada9f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.83.0 + - uses: dtolnay/rust-toolchain@1.85.0 - uses: Swatinem/rust-cache@v2 - run: cargo test --workspace --no-run - run: cargo test --workspace --no-fail-fast @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.83.0 + - uses: dtolnay/rust-toolchain@1.85.0 with: components: clippy, rustfmt - uses: Swatinem/rust-cache@v2 @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.80.0 + - uses: dtolnay/rust-toolchain@1.83.0 - uses: Swatinem/rust-cache@v2 - run: cargo check --workspace diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5be6bfa2c..0d235aec5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.83.0 + - uses: dtolnay/rust-toolchain@1.85.0 with: target: ${{ matrix.target }} diff --git a/Cargo.toml b/Cargo.toml index 198aff3c6..36195230e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ resolver = "2" [workspace.package] version = "0.13.0" -rust-version = "1.80" # also change in ci.yml +rust-version = "1.83" # also change in ci.yml authors = ["The Typst Project Developers"] edition = "2021" homepage = "https://typst.app" diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs index 2b6a7d820..ae71e298c 100644 --- a/crates/typst-cli/src/compile.rs +++ b/crates/typst-cli/src/compile.rs @@ -350,7 +350,7 @@ fn export_image( .iter() .enumerate() .filter(|(i, _)| { - config.pages.as_ref().map_or(true, |exported_page_ranges| { + config.pages.as_ref().is_none_or(|exported_page_ranges| { exported_page_ranges.includes_page_index(*i) }) }) diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs index 564b97bd7..e3dcc442e 100644 --- a/crates/typst-ide/src/complete.rs +++ b/crates/typst-ide/src/complete.rs @@ -1455,7 +1455,7 @@ impl<'a> CompletionContext<'a> { let mut defined = BTreeMap::>::new(); named_items(self.world, self.leaf.clone(), |item| { let name = item.name(); - if !name.is_empty() && item.value().as_ref().map_or(true, filter) { + if !name.is_empty() && item.value().as_ref().is_none_or(filter) { defined.insert(name.clone(), item.value()); } diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index 1f9cf6796..af47ff72f 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -1377,7 +1377,7 @@ impl<'a> GridLayouter<'a> { .footer .as_ref() .and_then(Repeatable::as_repeated) - .map_or(true, |footer| footer.start != header.end) + .is_none_or(|footer| footer.start != header.end) && self.lrows.last().is_some_and(|row| row.index() < header.end) && !in_last_with_offset( self.regions, @@ -1446,7 +1446,7 @@ impl<'a> GridLayouter<'a> { .iter_mut() .filter(|rowspan| (rowspan.y..rowspan.y + rowspan.rowspan).contains(&y)) .filter(|rowspan| { - rowspan.max_resolved_row.map_or(true, |max_row| y > max_row) + rowspan.max_resolved_row.is_none_or(|max_row| y > max_row) }) { // If the first region wasn't defined yet, it will have the @@ -1494,7 +1494,7 @@ impl<'a> GridLayouter<'a> { // laid out at the first frame of the row). // Any rowspans ending before this row are laid out even // on this row's first frame. - if laid_out_footer_start.map_or(true, |footer_start| { + if laid_out_footer_start.is_none_or(|footer_start| { // If this is a footer row, then only lay out this rowspan // if the rowspan is contained within the footer. y < footer_start || rowspan.y >= footer_start @@ -1580,5 +1580,5 @@ pub(super) fn points( /// our case, headers). pub(super) fn in_last_with_offset(regions: Regions<'_>, offset: Abs) -> bool { regions.backlog.is_empty() - && regions.last.map_or(true, |height| regions.size.y + offset == height) + && regions.last.is_none_or(|height| regions.size.y + offset == height) } diff --git a/crates/typst-layout/src/grid/lines.rs b/crates/typst-layout/src/grid/lines.rs index 1227953d1..7549673f1 100644 --- a/crates/typst-layout/src/grid/lines.rs +++ b/crates/typst-layout/src/grid/lines.rs @@ -463,7 +463,7 @@ pub fn hline_stroke_at_column( // region, we have the last index, and (as a failsafe) we don't have the // last row of cells above us. let use_bottom_border_stroke = !in_last_region - && local_top_y.map_or(true, |top_y| top_y + 1 != grid.rows.len()) + && local_top_y.is_none_or(|top_y| top_y + 1 != grid.rows.len()) && y == grid.rows.len(); let bottom_y = if use_bottom_border_stroke { grid.rows.len().saturating_sub(1) } else { y }; diff --git a/crates/typst-layout/src/grid/rowspans.rs b/crates/typst-layout/src/grid/rowspans.rs index 5039695d8..21992ed02 100644 --- a/crates/typst-layout/src/grid/rowspans.rs +++ b/crates/typst-layout/src/grid/rowspans.rs @@ -588,7 +588,7 @@ impl GridLayouter<'_> { measurement_data: &CellMeasurementData<'_>, ) -> bool { if sizes.len() <= 1 - && sizes.first().map_or(true, |&first_frame_size| { + && sizes.first().is_none_or(|&first_frame_size| { first_frame_size <= measurement_data.height_in_this_region }) { diff --git a/crates/typst-layout/src/inline/line.rs b/crates/typst-layout/src/inline/line.rs index bd08f30ef..659d33f4a 100644 --- a/crates/typst-layout/src/inline/line.rs +++ b/crates/typst-layout/src/inline/line.rs @@ -154,7 +154,7 @@ pub fn line<'a>( let mut items = collect_items(engine, p, range, trim); // Add a hyphen at the line start, if a previous dash should be repeated. - if pred.map_or(false, |pred| should_repeat_hyphen(pred, full)) { + if pred.is_some_and(|pred| should_repeat_hyphen(pred, full)) { if let Some(shaped) = items.first_text_mut() { shaped.prepend_hyphen(engine, p.config.fallback); } @@ -406,7 +406,7 @@ fn should_repeat_hyphen(pred_line: &Line, text: &str) -> bool { // // See § 4.1.1.1.2.e on the "Ortografía de la lengua española" // https://www.rae.es/ortografía/como-signo-de-división-de-palabras-a-final-de-línea - Lang::SPANISH => text.chars().next().map_or(false, |c| !c.is_uppercase()), + Lang::SPANISH => text.chars().next().is_some_and(|c| !c.is_uppercase()), _ => false, } diff --git a/crates/typst-layout/src/inline/linebreak.rs b/crates/typst-layout/src/inline/linebreak.rs index a9f21188b..31512604f 100644 --- a/crates/typst-layout/src/inline/linebreak.rs +++ b/crates/typst-layout/src/inline/linebreak.rs @@ -290,7 +290,7 @@ fn linebreak_optimized_bounded<'a>( } // If this attempt is better than what we had before, take it! - if best.as_ref().map_or(true, |best| best.total >= total) { + if best.as_ref().is_none_or(|best| best.total >= total) { best = Some(Entry { pred: pred_index, total, line: attempt, end }); } } @@ -423,7 +423,7 @@ fn linebreak_optimized_approximate( let total = pred.total + line_cost; // If this attempt is better than what we had before, take it! - if best.as_ref().map_or(true, |best| best.total >= total) { + if best.as_ref().is_none_or(|best| best.total >= total) { best = Some(Entry { pred: pred_index, total, diff --git a/crates/typst-layout/src/inline/shaping.rs b/crates/typst-layout/src/inline/shaping.rs index b688981ae..159619eb3 100644 --- a/crates/typst-layout/src/inline/shaping.rs +++ b/crates/typst-layout/src/inline/shaping.rs @@ -465,7 +465,7 @@ impl<'a> ShapedText<'a> { None }; let mut chain = families(self.styles) - .filter(|family| family.covers().map_or(true, |c| c.is_match("-"))) + .filter(|family| family.covers().is_none_or(|c| c.is_match("-"))) .map(|family| book.select(family.as_str(), self.variant)) .chain(fallback_func.iter().map(|f| f())) .flatten(); @@ -570,7 +570,7 @@ impl<'a> ShapedText<'a> { // for the next line. let dec = if ltr { usize::checked_sub } else { usize::checked_add }; while let Some(next) = dec(idx, 1) { - if self.glyphs.get(next).map_or(true, |g| g.range.start != text_index) { + if self.glyphs.get(next).is_none_or(|g| g.range.start != text_index) { break; } idx = next; @@ -812,7 +812,7 @@ fn shape_segment<'a>( .nth(1) .map(|(i, _)| offset + i) .unwrap_or(text.len()); - covers.map_or(true, |cov| cov.is_match(&text[offset..end])) + covers.is_none_or(|cov| cov.is_match(&text[offset..end])) }; // Collect the shaped glyphs, doing fallback and shaping parts again with diff --git a/crates/typst-library/src/foundations/symbol.rs b/crates/typst-library/src/foundations/symbol.rs index 2c391ee4c..50fcfb403 100644 --- a/crates/typst-library/src/foundations/symbol.rs +++ b/crates/typst-library/src/foundations/symbol.rs @@ -411,7 +411,7 @@ fn find<'a>( } let score = (matching, Reverse(total)); - if best_score.map_or(true, |b| score > b) { + if best_score.is_none_or(|b| score > b) { best = Some(candidate.1); best_score = Some(score); } diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index 762f94ed0..08d0130da 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -1387,7 +1387,7 @@ impl<'a> CellGrid<'a> { // Include the gutter right before the footer, unless there is // none, or the gutter is already included in the header (no // rows between the header and the footer). - if header_end.map_or(true, |header_end| header_end != footer.start) { + if header_end != Some(footer.start) { footer.start = footer.start.saturating_sub(1); } } diff --git a/crates/typst-library/src/text/font/book.rs b/crates/typst-library/src/text/font/book.rs index 23e27f64c..9f8acce87 100644 --- a/crates/typst-library/src/text/font/book.rs +++ b/crates/typst-library/src/text/font/book.rs @@ -160,7 +160,7 @@ impl FontBook { current.variant.weight.distance(variant.weight), ); - if best_key.map_or(true, |b| key < b) { + if best_key.is_none_or(|b| key < b) { best = Some(id); best_key = Some(key); } diff --git a/crates/typst-library/src/text/shift.rs b/crates/typst-library/src/text/shift.rs index 3eec0758b..dbf1be8a1 100644 --- a/crates/typst-library/src/text/shift.rs +++ b/crates/typst-library/src/text/shift.rs @@ -159,7 +159,7 @@ fn is_shapable(engine: &Engine, text: &str, styles: StyleChain) -> bool { { let covers = family.covers(); return text.chars().all(|c| { - covers.map_or(true, |cov| cov.is_match(c.encode_utf8(&mut [0; 4]))) + covers.is_none_or(|cov| cov.is_match(c.encode_utf8(&mut [0; 4]))) && font.ttf().glyph_index(c).is_some() }); } diff --git a/crates/typst-pdf/src/outline.rs b/crates/typst-pdf/src/outline.rs index ff72eb86a..eff1182c1 100644 --- a/crates/typst-pdf/src/outline.rs +++ b/crates/typst-pdf/src/outline.rs @@ -70,7 +70,7 @@ pub(crate) fn write_outline( // (not exceeding whichever is the most restrictive depth limit // of those two). while children.last().is_some_and(|last| { - last_skipped_level.map_or(true, |l| last.level < l) + last_skipped_level.is_none_or(|l| last.level < l) && last.level < leaf.level }) { children = &mut children.last_mut().unwrap().children; @@ -83,7 +83,7 @@ pub(crate) fn write_outline( // needed, following the usual rules listed above. last_skipped_level = None; children.push(leaf); - } else if last_skipped_level.map_or(true, |l| leaf.level < l) { + } else if last_skipped_level.is_none_or(|l| leaf.level < l) { // Only the topmost / lowest-level skipped heading matters when you // have consecutive skipped headings (since none of them are being // added to the bookmark tree), hence the condition above. diff --git a/crates/typst-syntax/src/node.rs b/crates/typst-syntax/src/node.rs index b7e1809d7..fde2eaca0 100644 --- a/crates/typst-syntax/src/node.rs +++ b/crates/typst-syntax/src/node.rs @@ -753,7 +753,7 @@ impl<'a> LinkedNode<'a> { // sibling's span number is larger than the target span's number. if children .peek() - .map_or(true, |next| next.span().number() > span.number()) + .is_none_or(|next| next.span().number() > span.number()) { if let Some(found) = child.find(span) { return Some(found); diff --git a/crates/typst-syntax/src/package.rs b/crates/typst-syntax/src/package.rs index 387057f37..aa537863d 100644 --- a/crates/typst-syntax/src/package.rs +++ b/crates/typst-syntax/src/package.rs @@ -327,8 +327,8 @@ impl PackageVersion { /// missing in the bound are ignored. pub fn matches_eq(&self, bound: &VersionBound) -> bool { self.major == bound.major - && bound.minor.map_or(true, |minor| self.minor == minor) - && bound.patch.map_or(true, |patch| self.patch == patch) + && bound.minor.is_none_or(|minor| self.minor == minor) + && bound.patch.is_none_or(|patch| self.patch == patch) } /// Performs a `>` match with the given version bound. The match only diff --git a/crates/typst-utils/src/scalar.rs b/crates/typst-utils/src/scalar.rs index 4036c2310..6d84fbfdf 100644 --- a/crates/typst-utils/src/scalar.rs +++ b/crates/typst-utils/src/scalar.rs @@ -28,7 +28,7 @@ impl Scalar { /// /// If the value is NaN, then it is set to `0.0` in the result. pub const fn new(x: f64) -> Self { - Self(if is_nan(x) { 0.0 } else { x }) + Self(if x.is_nan() { 0.0 } else { x }) } /// Gets the value of this [`Scalar`]. @@ -37,17 +37,6 @@ impl Scalar { } } -// We have to detect NaNs this way since `f64::is_nan` isn’t const -// on stable yet: -// ([tracking issue](https://github.com/rust-lang/rust/issues/57241)) -#[allow(clippy::unusual_byte_groupings)] -const fn is_nan(x: f64) -> bool { - // Safety: all bit patterns are valid for u64, and f64 has no padding bits. - // We cannot use `f64::to_bits` because it is not const. - let x_bits = unsafe { std::mem::transmute::(x) }; - (x_bits << 1 >> (64 - 12 + 1)) == 0b0_111_1111_1111 && (x_bits << 12) != 0 -} - impl Numeric for Scalar { fn zero() -> Self { Self(0.0) diff --git a/flake.lock b/flake.lock index c02466422..ad47d29cd 100644 --- a/flake.lock +++ b/flake.lock @@ -112,13 +112,13 @@ "rust-manifest": { "flake": false, "locked": { - "narHash": "sha256-Yqu2/i9170R7pQhvOCR1f5SyFr7PcFbO6xcMr9KWruQ=", + "narHash": "sha256-irgHsBXecwlFSdmP9MfGP06Cbpca2QALJdbN4cymcko=", "type": "file", - "url": "https://static.rust-lang.org/dist/channel-rust-1.83.0.toml" + "url": "https://static.rust-lang.org/dist/channel-rust-1.85.0.toml" }, "original": { "type": "file", - "url": "https://static.rust-lang.org/dist/channel-rust-1.83.0.toml" + "url": "https://static.rust-lang.org/dist/channel-rust-1.85.0.toml" } }, "systems": { diff --git a/flake.nix b/flake.nix index abdad27aa..6938f6e57 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,7 @@ inputs.nixpkgs.follows = "nixpkgs"; }; rust-manifest = { - url = "https://static.rust-lang.org/dist/channel-rust-1.83.0.toml"; + url = "https://static.rust-lang.org/dist/channel-rust-1.85.0.toml"; flake = false; }; }; diff --git a/tests/src/collect.rs b/tests/src/collect.rs index c6deba77b..33f4f7366 100644 --- a/tests/src/collect.rs +++ b/tests/src/collect.rs @@ -149,7 +149,7 @@ impl Collector { for entry in walkdir::WalkDir::new(crate::SUITE_PATH).sort_by_file_name() { let entry = entry.unwrap(); let path = entry.path(); - if !path.extension().is_some_and(|ext| ext == "typ") { + if path.extension().is_none_or(|ext| ext != "typ") { continue; } @@ -168,7 +168,7 @@ impl Collector { for entry in walkdir::WalkDir::new(crate::REF_PATH).sort_by_file_name() { let entry = entry.unwrap(); let path = entry.path(); - if !path.extension().is_some_and(|ext| ext == "png") { + if path.extension().is_none_or(|ext| ext != "png") { continue; } diff --git a/tests/src/run.rs b/tests/src/run.rs index f9a3c0434..4d08362cf 100644 --- a/tests/src/run.rs +++ b/tests/src/run.rs @@ -161,7 +161,7 @@ impl<'a> Runner<'a> { // Compare against reference output if available. // Test that is ok doesn't need to be updated. - if ref_data.as_ref().map_or(false, |r| D::matches(&live, r)) { + if ref_data.as_ref().is_ok_and(|r| D::matches(&live, r)) { return; } From 81efc82d3c0f7ccbcb40959ac8bddeca49e4c9f8 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 24 Feb 2025 16:05:36 +0000 Subject: [PATCH 06/12] Fix math accent base height calculation (#5941) --- crates/typst-layout/src/math/accent.rs | 4 ++-- tests/ref/gradient-math-misc.png | Bin 2993 -> 2993 bytes tests/ref/issue-math-realize-scripting.png | Bin 2610 -> 2605 bytes tests/ref/math-accent-align.png | Bin 614 -> 625 bytes tests/ref/math-accent-bounds.png | Bin 327 -> 327 bytes tests/ref/math-accent-dotless.png | Bin 1026 -> 1024 bytes tests/ref/math-accent-func.png | Bin 284 -> 284 bytes tests/ref/math-accent-sym-call.png | Bin 926 -> 930 bytes tests/ref/math-spacing-decorated.png | Bin 2385 -> 2375 bytes 9 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/typst-layout/src/math/accent.rs b/crates/typst-layout/src/math/accent.rs index 951870d68..f2dfa2c45 100644 --- a/crates/typst-layout/src/math/accent.rs +++ b/crates/typst-layout/src/math/accent.rs @@ -34,7 +34,7 @@ pub fn layout_accent( // Try to replace accent glyph with flattened variant. let flattened_base_height = scaled!(ctx, styles, flattened_accent_base_height); - if base.height() > flattened_base_height { + if base.ascent() > flattened_base_height { glyph.make_flattened_accent_form(ctx); } @@ -50,7 +50,7 @@ pub fn layout_accent( // minus the accent base height. Only if the base is very small, we need // a larger gap so that the accent doesn't move too low. let accent_base_height = scaled!(ctx, styles, accent_base_height); - let gap = -accent.descent() - base.height().min(accent_base_height); + let gap = -accent.descent() - base.ascent().min(accent_base_height); let size = Size::new(base.width(), accent.height() + gap + base.height()); let accent_pos = Point::with_x(base_attach - accent_attach); let base_pos = Point::with_y(accent.height() + gap); diff --git a/tests/ref/gradient-math-misc.png b/tests/ref/gradient-math-misc.png index acf14c6fe20e84146001d4117700a949a4fda6d1..13f5c27b38c0a80e502068b2784146ae58b838ed 100644 GIT binary patch delta 2915 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 N002ovPDHLkV1m<1w@d&4 diff --git a/tests/ref/issue-math-realize-scripting.png b/tests/ref/issue-math-realize-scripting.png index ee2d4cdf7a64d95e4bd8fffe538a89de1bde1ae4..7d721ed776199bd6611d1178bb7582c1dd6fe7c8 100644 GIT binary patch delta 2596 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 LNkvXXu0mjf*}K?_ diff --git a/tests/ref/math-accent-align.png b/tests/ref/math-accent-align.png index 84e8dc8ccda955a6b747d1462610b51219f43f43..efc66ec3faf784dcc17fcb8d3fbcb7a58c151773 100644 GIT binary patch delta 600 zcmV-e0;m1v1n~rrB!4(bL_t(|+U?ihOH*MS$8rBN$w3kfBPv$eMcov2VL?y{MM8Gd z57tG+P#LwUIa5}x)1Z##bk5AS;bf#!r!0#&JL+oI**ZJt6W_~c-3eb0>hr#O_};vD z9u8kP4RELi2}@YQ65cUb>$&>GV*>U>jQR%P-C18S!VZ7Ng@1IO4#^ox1Mso6P;xWF z)B#ihSiJ%23r(7!o@a+U7MiOeIutdk0wCwcnPql(Tuls_5bElDzUahPZ6D16PQZo1 zDY-x-yvt$Ra0piK?60S;1Rf6Gt^qLqP!@pf{ngoic6h|RqP_-T`5sdl0MU;4#$9HZ zI%tB*%~L<=*ne#QNU*~LS`#7wthaBdJk47066|o-i$JdiF@N-{+*}ft@HXI$?hn(B zz$jG>N8s4#oC-00c-~-##}}^$+D*Xn-lNj=_$R8K1Up>Dkxhu*>c=6I9WGjp$UwO9 zsg*5vmK{FXb1pOkA*IjXs<6YbQ2T#m%grU>T?`lW@_&+*L0vXKocq2$_csAC^V%MM z>R)hCJgvkbG!Rw7{BUK< mETOK_Z@IZ7EMW=nVE+J61?9wOxq%M=0000@y^($#u_1zm+% zU4*?s7G`a@&AB-$v&h;&a;CDE7F1JbTFoVF%9^cBx3hD;@m!wW6+9kf&-Wkra9;R5 z@U&o2Eeck!f)%`FaK7KsdrSi(@=o*R>~LN6 zq%jrs`p-wyfGAkO{|tXvT$!r8q@e}*aG_Gmv5YybPk%m4ZA1S}i{HEd0uQ^@uw>x;^K>s?!o;_IoS)CbKf?i6j{pu)Hwcu$%!1JYD@< J);T3K0RVa;6*B+; delta 53 zcmX@kbew6z2hrCT?4_2y>JfK%bbHQ$Ri`Dy>}_k?CbKf?iKI9dFkf_)7H0qgPgg&e IbxsLQ0CcJp7XSbN diff --git a/tests/ref/math-accent-dotless.png b/tests/ref/math-accent-dotless.png index 81eb4fa2bd7b48cba24fa3e1c8d6beda09bb6506..389ceb634aad124cc19196123c8ea188a72a0633 100644 GIT binary patch delta 1002 zcmVCXn9AOw3HbC%@)O|M?u=yLe9RO2H|3+iKUIDXjeaBY#OPp@e5UJcz12iXlDm zA-RGw>lT-6aDPQ+rU#X9caat;a~o`z$u4bE=^-+Nsx>^#}PaW7~pC^5tMD}(lY;D7d!kM2=(2TCgkMhb!Qj!O}a z2H@(cc;N`l?XGb?JO_dO$D+kU0)M>-9WPx|3DdhuuN~(9W=;_$ox znC}j#fGO#e89pWxerIQRGc%kB6MNad9ennP8hGEDw-LBnO{*JLGqLn z5d-eF3A~mIP@NM8OpCICa$<)^=1*hN?`~t!M Y0Al&n0a`kXD*ylh07*qoM6N<$g5P%2D*ylh delta 1004 zcmVpnSbg;BivD_N6K0T_;x!|MRqw-ah_GybnFYHL&Y-nmojC2*{5Wi&jGA_ z`Lb4c>d1g>JVVCz2}q4)NJZVfvcY%VNNoZ$d^8v7z<3a&m=q@cuH_(-~R?Le-F|~6~J^2$x~2djYBil z0Mr`*R;oh3O+k2Q=(;XBjQ&@dr6Y^LeCaI{K)g7=I0V30Q&UrfwN5(a=`RLAHIzIA zp!AB&!a*CbIy!2o)c_M?U2)&qF~)!HUWDYZy?^RDQg#^NyKP9f-`@|?Pq|(|a(*0_ z?Ro>rd+ohW0QPQ0%2WZyUO%7#HuoQwjik#2G5~2CNI%rgfTZ7X4x}8Uj&M#n0E1~r z=>qfh4h=A8+hhjz$*jJ$IULPeO@xWP=-3E8xkn4UeaTk`T&$qc1B+SMde-1N9|GSo z1AkCf0o<4oI9LVH_ZrR?1RggE>}dq@^EJTncL*EOd4!2`44 z_rQD2(|yP9dwM`@0K7wD~l&E{xDzw0#8>zmvv4FO#o$i9smFU delta 69 zcmbQkG>2(|yBc@TM`@0K7wz|+;wWt~$(698sT9m@a! diff --git a/tests/ref/math-accent-sym-call.png b/tests/ref/math-accent-sym-call.png index 0837a86c9e861a960cbca4d157ea7e719b54cd0f..609197f3c3da71d9f4b4efa72b92bcc64311b935 100644 GIT binary patch delta 908 zcmV;719SYI2cid%B!6j1L_t(|+U?cdPg`XG$MMC##Ka44jLDMua>Iqg7~_IVhFRvK zbB3sM5rUh8xj`l{7fet$L4t{Mq@fFRFaaAFAVpxPY|t|3RyMKix{j`ID?0^B*VFSg zd7hI>7Bwc%7B1G$&G{wg;`=;T&n7m=6Pq?jKD@!<3F@gD2)<+#AwBM2 zK=9&K3u`u{m%$W!>&GlWrz1WFz-qO#4M87W^dQtmE7iicQwY&rw~-9%r)dD@8!=rA zU`j@i!ZU_axPNk}yaRx)J#$qE_x7BO0iYdhmZxg8pXf&DZLpNeLmjyEp-T9|$CP>i zD7%{7g0wS^(B|;e05CiF%?I+n&olG|0I|NV=TyQK{S-z3*v`dwkqVLg$9v8LQ2xEA zBn)tIKSzGO3t->7QV>=MpX(cV&B{kN;j{32x7eKol7BmZnkgVs8K=w#1%Wd~JvTmq z#KAvaY`<&mfVv-?&z?~TGkeFQarH7Vp}{~1vcEI~0SBaF!5Tc1ppS=d+|O8nJG1cx z;&#C8j;h>P`We#@@W$a3FsVVX(>lzsfs}P%3S3804rkVnP!w|!TNFbw3``jm!byNf&iZ%x&=Tn zf?=@?0uZ=dxJJ?Z2*L{W2LN+dSECjl+Z^C*1fdF{VpQ7-fYbK^6i3b@S$31tQi598 zb!w`3aS*8=fVF2Btpi~7rz6hg&DX{e241~SJ5u*{UAHNPs~b4FpMaM10iynIiXDzy5op9!~y=;KG!+2{|svnaMwk i`EWj*4?kAnzW^mukOPEx)hPe~002ovP6b4+LSTZ{g0Nix delta 904 zcmV;319$wQ2c8FzB!6W|L_t(|+U?cdPg7?A$8od2WXUdevn(-jFE?CFmSveCCbAf3 zHs?aNIWq{;S)4)~;0#OHrh^fd%t<C+g0$zm zz7@PCBL+)wE^rpA2%fUaXT zBLD>5Zuc7M?i*f>V2b-01IQq2Bm#ke@wmfuMLV}k%JSGb!IR_rq_gsMoHTKIMvA+qZ>lA(RE3cz$7NK-mU z$uLrA+)xUa^?#PO0?@H%vK(P?&&enNiGvODRCSIMHiQec)?#_610$cPgfD(Zu@``n zYuPPGJ7WmVPH!au6FuL5Ebsd=yTLPjAAPp$~7dI|(Fr0DqM(AY2xs#0Po$nF9Nb&mn&B zpI2M%XsuBFv-`y}3SlPZy$P;e1%?vP9fa(q20(X0IvS|NI}Dl2p&NJCG+=%rHbcw- zcsvo68%w`~)C;_QI1LOZAkeP$(PtoKognGgk(9%0{~y7Kxrok*AsNQ{R|;Vzxo|H0 zNZ~ldd4CWCj3*UtuC8(-m8ZBzU(Lx@Sl4bKO-?I^Nv?tPm%+V4*TK}UY1{lrmJ^y5 zQww|k#?+lfn74tH868Sv3I~I;NuDd56)1@f{e@ifKGY{6kt<~{- z8-im;+lA*GN@06rGo~$RgwzO<)l=IsdTt4!A%8>3H%RpcMU5zh{dqcH9l8ZTA%bDG z_5h$?&0nElx*uVQngd|&iVD=igPV2Eh7rmUECY$H0JwdxKw@5GXEJR{;fh+0?nh4~eZYXhBrNR2((~t{ z4u9C^IxqUpt{5J`m6zc3AQ>+(^x86~MwP<8eW#m_f7is=M}Q@@v=z{7Kh!0LivgSt zM@M^l;SFH#vHGLC3_=CKJ5}|E-$Nz5&SgF%b3J^c9!~y?Fa}cmCX)HqG@kn{=EAvf eF8ox5{{vrCkOUezRbl`D002ovPDHLkU;%=IT%-#C diff --git a/tests/ref/math-spacing-decorated.png b/tests/ref/math-spacing-decorated.png index b8846ff0595667a56f7004ac4b0fcc5925670200..2f3c704e5d981ce119ac1e903e154c4a186e1553 100644 GIT binary patch delta 2364 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 From 3744c99b07f97a954a8468bef5fdb08c5c7914d7 Mon Sep 17 00:00:00 2001 From: Malo <57839069+MDLC01@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:15:17 +0100 Subject: [PATCH 07/12] Override the default math class of some characters (#5949) --- crates/typst-utils/src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/typst-utils/src/lib.rs b/crates/typst-utils/src/lib.rs index 34d6a9432..b346a8096 100644 --- a/crates/typst-utils/src/lib.rs +++ b/crates/typst-utils/src/lib.rs @@ -360,6 +360,21 @@ pub fn default_math_class(c: char) -> Option { // https://github.com/typst/typst/pull/5714 '\u{22A5}' => Some(MathClass::Normal), + // Used as a binary connector in linear logic, where it is referred to + // as "par". + // https://github.com/typst/typst/issues/5764 + 'â…‹' => Some(MathClass::Binary), + + // Those overrides should become the default in the next revision of + // MathClass.txt. + // https://github.com/typst/typst/issues/5764#issuecomment-2632435247 + '⎰' | '⟅' => Some(MathClass::Opening), + '⎱' | '⟆' => Some(MathClass::Closing), + + // Both ∨ and ⟑ are classified as Binary. + // https://github.com/typst/typst/issues/5764 + '⟇' => Some(MathClass::Binary), + c => unicode_math_class::class(c), } } From 36d83c8c092e7984eaa03dbecc1083f49da13129 Mon Sep 17 00:00:00 2001 From: Sharzy Date: Tue, 25 Feb 2025 00:35:13 +0800 Subject: [PATCH 08/12] HTML export: fix elem counting on classify_output (#5910) Co-authored-by: Laurenz --- crates/typst-html/src/lib.rs | 6 +++--- tests/ref/html/html-elem-alone-context.html | 2 ++ tests/suite/html/elem.typ | 7 +++++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 tests/ref/html/html-elem-alone-context.html create mode 100644 tests/suite/html/elem.typ diff --git a/crates/typst-html/src/lib.rs b/crates/typst-html/src/lib.rs index 25d0cd5d8..236a32544 100644 --- a/crates/typst-html/src/lib.rs +++ b/crates/typst-html/src/lib.rs @@ -307,18 +307,18 @@ fn head_element(info: &DocumentInfo) -> HtmlElement { /// Determine which kind of output the user generated. fn classify_output(mut output: Vec) -> SourceResult { - let len = output.len(); + let count = output.iter().filter(|node| !matches!(node, HtmlNode::Tag(_))).count(); for node in &mut output { let HtmlNode::Element(elem) = node else { continue }; let tag = elem.tag; let mut take = || std::mem::replace(elem, HtmlElement::new(tag::html)); - match (tag, len) { + match (tag, count) { (tag::html, 1) => return Ok(OutputKind::Html(take())), (tag::body, 1) => return Ok(OutputKind::Body(take())), (tag::html | tag::body, _) => bail!( elem.span, "`{}` element must be the only element in the document", - elem.tag + elem.tag, ), _ => {} } diff --git a/tests/ref/html/html-elem-alone-context.html b/tests/ref/html/html-elem-alone-context.html new file mode 100644 index 000000000..69e9da411 --- /dev/null +++ b/tests/ref/html/html-elem-alone-context.html @@ -0,0 +1,2 @@ + + diff --git a/tests/suite/html/elem.typ b/tests/suite/html/elem.typ new file mode 100644 index 000000000..81ab94577 --- /dev/null +++ b/tests/suite/html/elem.typ @@ -0,0 +1,7 @@ +--- html-elem-alone-context html --- +#context html.elem("html") + +--- html-elem-not-alone html --- +// Error: 2-19 `` element must be the only element in the document +#html.elem("html") +Text From 225e845021b9cfb37e6dc719c8bc85ccdc1ff69f Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 25 Feb 2025 12:31:15 +0100 Subject: [PATCH 09/12] Fix introspection of HTML root sibling metadata (#5953) --- crates/typst-html/src/lib.rs | 2 +- .../src/introspection/introspector.rs | 18 +++++++++--------- tests/ref/html/html-elem-metadata.html | 2 ++ tests/suite/html/elem.typ | 8 ++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 tests/ref/html/html-elem-metadata.html diff --git a/crates/typst-html/src/lib.rs b/crates/typst-html/src/lib.rs index 236a32544..aa769976e 100644 --- a/crates/typst-html/src/lib.rs +++ b/crates/typst-html/src/lib.rs @@ -83,8 +83,8 @@ fn html_document_impl( )?; let output = handle_list(&mut engine, &mut locator, children.iter().copied())?; + let introspector = Introspector::html(&output); let root = root_element(output, &info)?; - let introspector = Introspector::html(&root); Ok(HtmlDocument { info, root, introspector }) } diff --git a/crates/typst-library/src/introspection/introspector.rs b/crates/typst-library/src/introspection/introspector.rs index 8cbaea891..9751dfcb8 100644 --- a/crates/typst-library/src/introspection/introspector.rs +++ b/crates/typst-library/src/introspection/introspector.rs @@ -10,7 +10,7 @@ use typst_utils::NonZeroExt; use crate::diag::{bail, StrResult}; use crate::foundations::{Content, Label, Repr, Selector}; -use crate::html::{HtmlElement, HtmlNode}; +use crate::html::HtmlNode; use crate::introspection::{Location, Tag}; use crate::layout::{Frame, FrameItem, Page, Point, Position, Transform}; use crate::model::Numbering; @@ -55,8 +55,8 @@ impl Introspector { /// Creates an introspector for HTML. #[typst_macros::time(name = "introspect html")] - pub fn html(root: &HtmlElement) -> Self { - IntrospectorBuilder::new().build_html(root) + pub fn html(output: &[HtmlNode]) -> Self { + IntrospectorBuilder::new().build_html(output) } /// Iterates over all locatable elements. @@ -392,9 +392,9 @@ impl IntrospectorBuilder { } /// Build an introspector for an HTML document. - fn build_html(mut self, root: &HtmlElement) -> Introspector { + fn build_html(mut self, output: &[HtmlNode]) -> Introspector { let mut elems = Vec::new(); - self.discover_in_html(&mut elems, root); + self.discover_in_html(&mut elems, output); self.finalize(elems) } @@ -434,16 +434,16 @@ impl IntrospectorBuilder { } /// Processes the tags in the HTML element. - fn discover_in_html(&mut self, sink: &mut Vec, elem: &HtmlElement) { - for child in &elem.children { - match child { + fn discover_in_html(&mut self, sink: &mut Vec, nodes: &[HtmlNode]) { + for node in nodes { + match node { HtmlNode::Tag(tag) => self.discover_in_tag( sink, tag, Position { page: NonZeroUsize::ONE, point: Point::zero() }, ), HtmlNode::Text(_, _) => {} - HtmlNode::Element(elem) => self.discover_in_html(sink, elem), + HtmlNode::Element(elem) => self.discover_in_html(sink, &elem.children), HtmlNode::Frame(frame) => self.discover_in_frame( sink, frame, diff --git a/tests/ref/html/html-elem-metadata.html b/tests/ref/html/html-elem-metadata.html new file mode 100644 index 000000000..c37a7d2ef --- /dev/null +++ b/tests/ref/html/html-elem-metadata.html @@ -0,0 +1,2 @@ + +Hi diff --git a/tests/suite/html/elem.typ b/tests/suite/html/elem.typ index 81ab94577..b416fdf94 100644 --- a/tests/suite/html/elem.typ +++ b/tests/suite/html/elem.typ @@ -5,3 +5,11 @@ // Error: 2-19 `` element must be the only element in the document #html.elem("html") Text + +--- html-elem-metadata html --- +#html.elem("html", context { + let val = query().first().value + test(val, "Hi") + val +}) +#metadata("Hi") From acd3a5b7a5999d22fbf2da488744d564b2f3638e Mon Sep 17 00:00:00 2001 From: aodenis <45949528+aodenis@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:41:54 +0100 Subject: [PATCH 10/12] Fix high CPU usage due to inotify watch triggering itself (#5905) Co-authored-by: Laurenz --- crates/typst-cli/src/watch.rs | 57 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index 91132fc30..cc727f0fc 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -204,6 +204,10 @@ impl Watcher { let event = event .map_err(|err| eco_format!("failed to watch dependencies ({err})"))?; + if !is_relevant_event_kind(&event.kind) { + continue; + } + // Workaround for notify-rs' implicit unwatch on remove/rename // (triggered by some editors when saving files) with the // inotify backend. By keeping track of the potentially @@ -224,7 +228,17 @@ impl Watcher { } } - relevant |= self.is_event_relevant(&event); + // Don't recompile because the output file changed. + // FIXME: This doesn't work properly for multifile image export. + if event + .paths + .iter() + .all(|path| is_same_file(path, &self.output).unwrap_or(false)) + { + continue; + } + + relevant = true; } // If we found a relevant event or if any of the missing files now @@ -234,32 +248,23 @@ impl Watcher { } } } +} - /// Whether a watch event is relevant for compilation. - fn is_event_relevant(&self, event: ¬ify::Event) -> bool { - // Never recompile because the output file changed. - if event - .paths - .iter() - .all(|path| is_same_file(path, &self.output).unwrap_or(false)) - { - return false; - } - - match &event.kind { - notify::EventKind::Any => true, - notify::EventKind::Access(_) => false, - notify::EventKind::Create(_) => true, - notify::EventKind::Modify(kind) => match kind { - notify::event::ModifyKind::Any => true, - notify::event::ModifyKind::Data(_) => true, - notify::event::ModifyKind::Metadata(_) => false, - notify::event::ModifyKind::Name(_) => true, - notify::event::ModifyKind::Other => false, - }, - notify::EventKind::Remove(_) => true, - notify::EventKind::Other => false, - } +/// Whether a kind of watch event is relevant for compilation. +fn is_relevant_event_kind(kind: ¬ify::EventKind) -> bool { + match kind { + notify::EventKind::Any => true, + notify::EventKind::Access(_) => false, + notify::EventKind::Create(_) => true, + notify::EventKind::Modify(kind) => match kind { + notify::event::ModifyKind::Any => true, + notify::event::ModifyKind::Data(_) => true, + notify::event::ModifyKind::Metadata(_) => false, + notify::event::ModifyKind::Name(_) => true, + notify::event::ModifyKind::Other => false, + }, + notify::EventKind::Remove(_) => true, + notify::EventKind::Other => false, } } From f31c9716240eb5c81ae225455c069089088015bc Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 25 Feb 2025 13:47:41 +0100 Subject: [PATCH 11/12] Deduplicate watcher update call (#5955) --- crates/typst-cli/src/watch.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index cc727f0fc..0813d8ffd 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -55,11 +55,11 @@ pub fn watch(timer: &mut Timer, command: &WatchCommand) -> StrResult<()> { // Perform initial compilation. timer.record(&mut world, |world| compile_once(world, &mut config))??; - // Watch all dependencies of the initial compilation. - watcher.update(world.dependencies())?; - // Recompile whenever something relevant happens. loop { + // Watch all dependencies of the most recent compilation. + watcher.update(world.dependencies())?; + // Wait until anything relevant happens. watcher.wait()?; @@ -71,9 +71,6 @@ pub fn watch(timer: &mut Timer, command: &WatchCommand) -> StrResult<()> { // Evict the cache. comemo::evict(10); - - // Adjust the file watching. - watcher.update(world.dependencies())?; } } From bad343748b834cdc155c5fe76cd944e74f4665cf Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 25 Feb 2025 14:00:22 +0100 Subject: [PATCH 12/12] Fix paper name in page setup guide (#5956) --- docs/guides/page-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/page-setup.md b/docs/guides/page-setup.md index c93a778e2..36ed0fa23 100644 --- a/docs/guides/page-setup.md +++ b/docs/guides/page-setup.md @@ -56,7 +56,7 @@ requirements with examples. Typst's default page size is A4 paper. Depending on your region and your use case, you will want to change this. You can do this by using the [`{page}`]($page) set rule and passing it a string argument to use a common page -size. Options include the complete ISO 216 series (e.g. `"iso-a4"`, `"iso-c2"`), +size. Options include the complete ISO 216 series (e.g. `"a4"` and `"iso-c2"`), customary US formats like `"us-legal"` or `"us-letter"`, and more. Check out the reference for the [page's paper argument]($page.paper) to learn about all available options.