From b5f68017a9c2f1a562f9b30cf0739e4439ae2db9 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 5 Nov 2025 16:54:57 +0100 Subject: [PATCH 01/54] Add missing Typst 0.14 changelog entry (#7285) --- docs/changelog/0.14.0.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog/0.14.0.md b/docs/changelog/0.14.0.md index 6db75e3bf9..a6e060ad94 100644 --- a/docs/changelog/0.14.0.md +++ b/docs/changelog/0.14.0.md @@ -285,6 +285,9 @@ _Thanks to [@mkorje](https://github.com/mkorje) for his work on math!_ - The `--make-deps` CLI flag in favor of `--deps` with `--deps-format make` [#7022] - Various symbols, see the [deprecation section in the dedicated changelog](https://github.com/typst/codex/blob/v0.2.0/CHANGELOG.md#deprecated) for a full listing +## Removals +- Removed compatibility behavior of type/str comparisons (e.g. `{int == "integer"}`), which was temporarily introduced in Typst 0.8 and deprecated in Typst 0.13 **(Breaking change)** + ## Development - The `Default` impl for `Library` had to be removed for crate splitting and trait coherence reasons, but you can get a drop-in replacement via `use typst::LibraryExt` [#6576] - The `PdfOptions` struct has a new `tagged` field, which defaults to `{true}` [#6619] [#7046] From 29e742904d71608103e4a29e741d0b8b8d5a5152 Mon Sep 17 00:00:00 2001 From: Tobias Schmitz Date: Mon, 27 Oct 2025 10:32:37 +0100 Subject: [PATCH 02/54] Fix panic in PDF backend due to ambiguous logical parent (#7216) --- crates/typst-pdf/src/tags/tree/mod.rs | 10 ++++- .../query-tags-ambiguous-parent-footnote.yml | 37 +++++++++++++++++++ .../query-tags-ambiguous-parent-place.yml | 4 ++ tests/suite/pdftags/query.typ | 14 ++++++- 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 tests/ref/pdftags/query-tags-ambiguous-parent-footnote.yml create mode 100644 tests/ref/pdftags/query-tags-ambiguous-parent-place.yml diff --git a/crates/typst-pdf/src/tags/tree/mod.rs b/crates/typst-pdf/src/tags/tree/mod.rs index c4d72df209..0919f766c2 100644 --- a/crates/typst-pdf/src/tags/tree/mod.rs +++ b/crates/typst-pdf/src/tags/tree/mod.rs @@ -385,10 +385,16 @@ fn close_group(tree: &mut Tree, surface: &mut Surface, id: GroupId) -> GroupId { GroupKind::LogicalParent(elem) => { let loc = elem.location().unwrap(); // Insert logical children when closing the logical parent, so they - // are at the end of the group. - if let Some(children) = tree.logical_children.get(&loc) { + // are at the end of the group. In some cases there might be + // multiple parent groups with the same location, only insert the + // children for the first parent group. + if let Some(located) = tree.groups.by_loc(&loc) + && located.id == id + && let Some(children) = tree.logical_children.get(&loc) + { tree.groups.push_groups(id, children); } + tree.groups.push_group(direct_parent, id); } GroupKind::LogicalChild(inherit, logical_parent) => { diff --git a/tests/ref/pdftags/query-tags-ambiguous-parent-footnote.yml b/tests/ref/pdftags/query-tags-ambiguous-parent-footnote.yml new file mode 100644 index 0000000000..dd769b0b2f --- /dev/null +++ b/tests/ref/pdftags/query-tags-ambiguous-parent-footnote.yml @@ -0,0 +1,37 @@ +- Tag: P + /K: + - Tag: Lbl + /K: + - Tag: Link + /K: + - Annotation: page=0 index=0 + - Tag: Span + /BaselineShift: 3.500 + /LineHeight: 6.000 + /K: + - Content: page=0 mcid=0 + - Tag: Note + /K: + - Tag: Lbl + /K: + - Tag: Link + /K: + - Annotation: page=0 index=2 + - Tag: Span + /BaselineShift: 2.975 + /LineHeight: 5.100 + /K: + - Content: page=0 mcid=2 + - Content: page=0 mcid=3 +- Tag: P + /K: + - Tag: Lbl + /K: + - Tag: Link + /K: + - Annotation: page=0 index=1 + - Tag: Span + /BaselineShift: 3.500 + /LineHeight: 6.000 + /K: + - Content: page=0 mcid=1 diff --git a/tests/ref/pdftags/query-tags-ambiguous-parent-place.yml b/tests/ref/pdftags/query-tags-ambiguous-parent-place.yml new file mode 100644 index 0000000000..937505c3f0 --- /dev/null +++ b/tests/ref/pdftags/query-tags-ambiguous-parent-place.yml @@ -0,0 +1,4 @@ +- Tag: Span + /Placement: Block + /K: + - Content: page=0 mcid=0 diff --git a/tests/suite/pdftags/query.typ b/tests/suite/pdftags/query.typ index d4ca292b02..5e9cdd6d3c 100644 --- a/tests/suite/pdftags/query.typ +++ b/tests/suite/pdftags/query.typ @@ -10,16 +10,26 @@ #context query(
).at(0) ---- query-tags-ambiguous-parent-place pdftags --- +--- query-tags-ambiguous-parent-place-error pdftags --- // Error: 2-43 PDF/UA-1 error: ambiguous logical parent // Hint: 2-43 please report this as a bug #place(float: true, top + left)[something] #context query().join() ---- query-tags-ambiguous-parent-footnote pdftags --- +--- query-tags-ambiguous-parent-place pdftags nopdfua --- +#place(float: true, top + left)[something] + +#context query().join() + +--- query-tags-ambiguous-parent-footnote-error pdftags --- // Error: 1:2-1:21 PDF/UA-1 error: ambiguous logical parent // Hint: 1:2-1:21 please report this as a bug #footnote[something] #context query().join() + +--- query-tags-ambiguous-parent-footnote pdftags nopdfua --- +#footnote[something] + +#context query().join() From dfc7e08378033a4b6af571d584feeaab68bcddd1 Mon Sep 17 00:00:00 2001 From: "Y.D.X." <73375426+YDX-2147483647@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:22:09 +0800 Subject: [PATCH 03/54] Specify the signature of `layout.func` in documentation (#7199) --- crates/typst-library/src/layout/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/typst-library/src/layout/layout.rs b/crates/typst-library/src/layout/layout.rs index 8855813c13..25a2660f31 100644 --- a/crates/typst-library/src/layout/layout.rs +++ b/crates/typst-library/src/layout/layout.rs @@ -69,7 +69,7 @@ pub fn layout( /// displayed in the document. /// /// The container's size is given as a [dictionary] with the keys `width` - /// and `height`. + /// and `height`, both of type [`length`]. /// /// This function is called once for each time the content returned by /// `layout` appears in the document. This makes it possible to generate From 00dbfab0e61ecdc40599e546d113b8861a48ac3a Mon Sep 17 00:00:00 2001 From: Malo <57839069+MDLC01@users.noreply.github.com> Date: Mon, 27 Oct 2025 14:38:21 +0000 Subject: [PATCH 04/54] Properly document the default value of `array.join`'s `default` parameter (#7218) Co-authored-by: Laurenz --- crates/typst-library/src/foundations/array.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/typst-library/src/foundations/array.rs b/crates/typst-library/src/foundations/array.rs index 16105f96c9..e4e8bbb487 100644 --- a/crates/typst-library/src/foundations/array.rs +++ b/crates/typst-library/src/foundations/array.rs @@ -720,6 +720,7 @@ impl Array { last: Option, /// What to return if the array is empty. #[named] + #[default] default: Option, ) -> StrResult { let len = self.0.len(); From a7644652b99a2884ff65b42229d6d146f6fa9f0b Mon Sep 17 00:00:00 2001 From: "Y.D.X." <73375426+YDX-2147483647@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:47:02 +0800 Subject: [PATCH 05/54] Document the OpenType contextual alternates (`calt`) feature (#7169) --- crates/typst-library/src/text/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/typst-library/src/text/mod.rs b/crates/typst-library/src/text/mod.rs index 833564b703..33c9fe070f 100644 --- a/crates/typst-library/src/text/mod.rs +++ b/crates/typst-library/src/text/mod.rs @@ -643,6 +643,11 @@ pub struct TextElem { /// #set text(ligatures: false) /// A fine ligature. /// ``` + /// + /// Note that some programming fonts use other OpenType font features to + /// implement "ligatures," including the contextual alternates (`calt`) + /// feature, which is also enabled by default. Use the general + /// [`features`]($text.features) parameter to control such features. #[default(true)] #[ghost] pub ligatures: bool, @@ -721,11 +726,19 @@ pub struct TextElem { /// - If given a dictionary mapping to numbers, sets the features /// identified by the keys to the values. /// - /// ```example + /// ```example:"Give an array of strings" /// // Enable the `frac` feature manually. /// #set text(features: ("frac",)) /// 1/2 /// ``` + /// + /// ```example:"Give a dictionary mapping to numbers" + /// #set text(font: "Cascadia Code") + /// => + /// // Disable the contextual alternates (`calt`) feature. + /// #set text(features: (calt: 0)) + /// => + /// ``` #[fold] #[ghost] pub features: FontFeatures, From 68a41d7114b85a101655d217aa436141d05167d6 Mon Sep 17 00:00:00 2001 From: "Y.D.X." <73375426+YDX-2147483647@users.noreply.github.com> Date: Mon, 27 Oct 2025 23:02:02 +0800 Subject: [PATCH 06/54] Improve the docs for relative lengths (#6897) --- crates/typst-library/src/layout/container.rs | 12 +++++++----- crates/typst-library/src/layout/rel.rs | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/typst-library/src/layout/container.rs b/crates/typst-library/src/layout/container.rs index bebc20ee10..f50384b13c 100644 --- a/crates/typst-library/src/layout/container.rs +++ b/crates/typst-library/src/layout/container.rs @@ -77,8 +77,10 @@ pub struct BoxElem { /// other dictionary entries). All keys are optional; omitted keys will use /// their previously set value, or the default value if never set. /// - /// [Relative lengths]($relative) are relative to the box size without - /// outset. + /// [Relative lengths]($relative) for this parameter are relative to the box + /// size excluding [outset]($box.outset). Note that relative insets and + /// outsets are different from relative [widths]($box.width) and + /// [heights]($box.height), which are relative to the container. /// /// _Note:_ When the box contains text, its exact size depends on the /// current [text edges]($text.top-edge). @@ -92,9 +94,9 @@ pub struct BoxElem { /// How much to expand the box's size without affecting the layout. /// /// This can be a single length for all sides or a dictionary of lengths for - /// individual sides. [Relative lengths]($relative) are relative to the box - /// size without outset. See the documentation for [inset]($box.inset) above - /// for further details. + /// individual sides. [Relative lengths]($relative) for this parameter are + /// relative to the box size excluding outset. See the documentation for + /// [inset]($box.inset) above for further details. /// /// This is useful to prevent padding from affecting line layout. For a /// generalized version of the example below, see the documentation for the diff --git a/crates/typst-library/src/layout/rel.rs b/crates/typst-library/src/layout/rel.rs index d77ef0d1db..9e41e0d4c0 100644 --- a/crates/typst-library/src/layout/rel.rs +++ b/crates/typst-library/src/layout/rel.rs @@ -59,8 +59,8 @@ use crate::layout::{Abs, Em, Length, Ratio}; /// [floats]($float). /// /// A relative length has the following fields: -/// - `length`: Its length component. -/// - `ratio`: Its ratio component. +/// - `length`: Its [length] component. +/// - `ratio`: Its [ratio] component. /// /// ```example /// #(100% - 50pt).length \ From fa23f930df9d52f40731d9313b2dd84d071b7ba8 Mon Sep 17 00:00:00 2001 From: Toon Verstraelen Date: Tue, 28 Oct 2025 16:29:35 +0100 Subject: [PATCH 07/54] Do not create empty Make deps file when writing to standard output (#7246) --- crates/typst-cli/src/deps.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/typst-cli/src/deps.rs b/crates/typst-cli/src/deps.rs index 921400a88d..bdd97f8c48 100644 --- a/crates/typst-cli/src/deps.rs +++ b/crates/typst-cli/src/deps.rs @@ -64,7 +64,7 @@ fn write_deps_make( dest: &Output, outputs: &[Output], ) -> io::Result<()> { - let mut dest = dest.open()?; + let mut buffer = Vec::new(); for (i, output) in outputs.iter().enumerate() { let path = match output { Output::Path(path) => path.as_os_str(), @@ -82,10 +82,14 @@ fn write_deps_make( // processed. let Some(string) = path.to_str() else { continue }; if i != 0 { - dest.write_all(b" ")?; + buffer.write_all(b" ")?; } - dest.write_all(munge(string).as_bytes())?; + buffer.write_all(munge(string).as_bytes())?; } + + // Only create the deps file in case of valid output paths. + let mut dest = dest.open()?; + dest.write_all(&buffer)?; dest.write_all(b":")?; for dep in relative_dependencies(world)? { From 0166c2f9d4c660ade5c8cf851342932bce6ad0bd Mon Sep 17 00:00:00 2001 From: Andrew Voynov <37143421+Andrew15-5@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:00:02 +0300 Subject: [PATCH 08/54] Document version type comparison (#7152) Co-authored-by: Malo <57839069+MDLC01@users.noreply.github.com> Co-authored-by: Laurenz --- crates/typst-library/src/foundations/version.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/typst-library/src/foundations/version.rs b/crates/typst-library/src/foundations/version.rs index 71b0b71535..39f3cdf9f8 100644 --- a/crates/typst-library/src/foundations/version.rs +++ b/crates/typst-library/src/foundations/version.rs @@ -65,13 +65,22 @@ impl Version { /// /// It can have any number of components (even zero). /// - /// ```example + /// ```example:"Constructing versions" /// #version() \ /// #version(1) \ /// #version(1, 2, 3, 4) \ /// #version((1, 2, 3, 4)) \ /// #version((1, 2), 3) /// ``` + /// + /// As a practical use case, this allows comparing the current version + /// ([`{sys.version}`]($version)) to a specific one. + /// + /// ```example:"Comparing with the current version" + /// Current version: #sys.version \ + /// #(sys.version >= version(0, 14, 0)) \ + /// #(version(3, 2, 0) > version(4, 1, 0)) + /// ``` #[func(constructor)] pub fn construct( /// The components of the version (array arguments are flattened) From f7fbc8ab6ebe1134b289769d12570b51681b1cfe Mon Sep 17 00:00:00 2001 From: Malo <57839069+MDLC01@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:26:21 +0000 Subject: [PATCH 09/54] Minor fixes to documentation groups (#7242) --- docs/guides/tables.md | 8 ++++---- docs/reference/groups.yml | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/guides/tables.md b/docs/guides/tables.md index c726dbf5eb..77df47d813 100644 --- a/docs/guides/tables.md +++ b/docs/guides/tables.md @@ -800,9 +800,9 @@ calendar. >>> >>> #show table.cell.where(y: 0): strong #set table(stroke: (x, y) => ( - left: if x == 0 or y > 0 { 1pt } else { 0pt }, + left: if x == 0 or y > 0 { 1pt } else { 0pt }, right: 1pt, - top: if y <= 1 { 1pt } else { 0pt }, + top: if y <= 1 { 1pt } else { 0pt }, bottom: 1pt, )) @@ -1037,7 +1037,7 @@ on the right of the table. inset: (x: 0.6em,), stroke: (_, y) => ( x: 1pt, - top: if y <= 1 { 1pt } else { 0pt }, + top: if y <= 1 { 1pt } else { 0pt }, bottom: 1pt, ), align: (left, right, right, right, right, left), @@ -1090,7 +1090,7 @@ upright: inset: (x: 0.6em,), stroke: (_, y) => ( x: 1pt, - top: if y <= 1 { 1pt } else { 0pt }, + top: if y <= 1 { 1pt } else { 0pt }, bottom: 1pt, ), align: (left, right, right, right, right, left), diff --git a/docs/reference/groups.yml b/docs/reference/groups.yml index 9acaab2bec..f76c9c29a1 100644 --- a/docs/reference/groups.yml +++ b/docs/reference/groups.yml @@ -138,7 +138,7 @@ the constants `pi`, `tau`, `e`, and `inf`. - name: std - title: Standard library + title: Standard Library category: foundations path: ["std"] details: | @@ -251,11 +251,11 @@ # Example ```typ #html.video( -   controls: true, -   width: 1280, -   height: 720, -   src: "sunrise.mp4", + controls: true, + width: 1280, + height: 720, + src: "sunrise.mp4", )[ -   Your browser does not support the video tag. + Your browser does not support the video tag. ] ``` From 0b71b5c645f3ef1fcd58e30c96a58b82007c109c Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 31 Oct 2025 10:04:58 -0400 Subject: [PATCH 10/54] Always treat `TextElem` fragments as spaced in math (#7276) --- crates/typst-layout/src/math/text.rs | 4 +--- tests/ref/math-spacing-kept-spaces.png | Bin 884 -> 1176 bytes tests/suite/math/spacing.typ | 3 ++- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/typst-layout/src/math/text.rs b/crates/typst-layout/src/math/text.rs index f15936d6b4..66a718c4ca 100644 --- a/crates/typst-layout/src/math/text.rs +++ b/crates/typst-layout/src/math/text.rs @@ -97,8 +97,6 @@ fn layout_inline_text( .chars() .flat_map(|c| to_style(c, MathStyle::select(c, variant, bold, italic))) .collect(); - - let spaced = styled_text.graphemes(true).nth(1).is_some(); let elem = TextElem::packed(styled_text).spanned(span); // There isn't a natural width for a paragraph in a math environment; @@ -118,7 +116,7 @@ fn layout_inline_text( Ok(FrameFragment::new(styles, frame) .with_class(MathClass::Alphabetic) .with_text_like(true) - .with_spaced(spaced)) + .with_spaced(true)) } } diff --git a/tests/ref/math-spacing-kept-spaces.png b/tests/ref/math-spacing-kept-spaces.png index bb433d4fc5e46ac6ee1f17263cfb9870adaac05b..0f638c21092408099055358d002ae757d832c2a2 100644 GIT binary patch delta 1169 zcmV;C1aABE2ABzu7k@(t00000a6e zO46iPqJ3ygMdJxQmDEbAU~3P-ltTq6wuq&%aKnP)5=mFpLC(op>)Y89(FWZ_<^N@L1}K!0-OV-=}6&lof?CPK{7KSg^WLJTkaJbzAdV}H0;=cM2NUTIDG8f{iA&rgt1aOx`!|4g2 zjRJ`+0Kb)>bbq7|!aG3fcLne?iiUj~V8j<%?z>P8;f;&{;0R3Sbh=!dP z0Z(vG3P>IT9}{jj0kab@@DqB^sB`fa@DvQ|?tBf9Folxo7Z~e@s)-H?rBEgqwrGtq?AUFx zg(tdfVdt(X(eMMecIPHkv~AIUVFQ;2m%g_QTO8Uw9teg*64|wgil}T}Gh1Qvt0t}2 zGF*QW_kY`h;l29#JwvECet+a`tZ?7^gcl51;nXZ%pA`&WXpA|mMnz_YS2Llo-S`le zj&|-=^;+T1*q_x1hUqZ&NT{IOARkK&4`JpzjXJC_gTsi1l~mTFX2r(|1j9jfw%@f~ z-XH-@--y`1HV5VCDnOWJ=+80OwC$suc=%xZq#Kr($ue|J)Ri>jF?A0B$aa0~#5=^%8Es!&EekT7c_X*s5KE4QmI1!OcL1?$P1OU6r)& z_Z|=08W(n=gUPSLQ`JCl3KZ{XrQYd`1SGu?743Bmfc)bL$#+&`fk*(DoB#I;;jpy^ jvwc_FVLNPxSL|;R{Z)TCnv$Xb015yANkvXXu0mjf(^oPQ delta 874 zcmV-w1C{)k3G@b#7k@Pf00000ugP${0009!Nkl8hSPVF~sh==o1 z&e2(pUTq_jrL6Gd3ZQpE77xeE5e^wElZl4sjl#jnHJB|Nz7j*>05_fJ zt!;;s&7gH80)Lof(Qw*h=uU&Dua;3WX4TUTKs<2eHlu#q*+Cy9A{tHz113ner5AKT zszTCzK>Z(heH6)*bMSlwOoHLSvkd^&0rZs9(9;3c6;^=bOyqM3hVPnQj(Y{@*+cLE zFlR&n+A0A+wN2NNIiLVQFGkUOP>H=Hz8QA306-4_9e>yL6}+Yb(RYAh`+z_=BLn~z zhLRpLvP)l%I~e8azq^cf(JK%>&Lqszeq%cPpTdXTP$3wOc;#_8zEz2a`~1;xf`33X z{648Ep#clNnbP_w*q!NKFa<~Ano`~ihO_dS6UIW$4SrV*Sp7}$Zkd8T+ev;T82(Qh znb(DdO@FVt|H6RV7jm+!%YZLkwj}Xbp`|cjzO`NQ)f6fawe(8rHKI)Ahy22?WFY>!QDF{aZl;8uqC`^c^6y zGZ1@8{IGBY05#wD+4af1)@gy`B>+2&qWWhHRC1o}!FZ0*2X z^O**xs~w=R=*2W2Ag`tGbaHjX&gvK(gMSG40~bgbur*__T>t<807*qoM6N<$g8I6p AoB#j- diff --git a/tests/suite/math/spacing.typ b/tests/suite/math/spacing.typ index db8b905c63..481c421f26 100644 --- a/tests/suite/math/spacing.typ +++ b/tests/suite/math/spacing.typ @@ -19,7 +19,8 @@ $f(x) sin(y)$ // Test ignored vs non-ignored spaces. $f (x), f(x)$ \ $[a|b], [a | b]$ \ -$a"is"b, a "is" b$ +$a"is"b, a "is" b$ \ +$A"B"C, A "B" C$ --- math-spacing-predefined --- // Test predefined spacings. From e8dc6d3655c8308808d6eca29bf4cb021c646afb Mon Sep 17 00:00:00 2001 From: Brian Wilson <15809934+bountonw@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:55:29 +0700 Subject: [PATCH 11/54] Update link on selector page to point to element functions (#7289) --- crates/typst-library/src/foundations/selector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/typst-library/src/foundations/selector.rs b/crates/typst-library/src/foundations/selector.rs index 4fa9238968..abc5898e09 100644 --- a/crates/typst-library/src/foundations/selector.rs +++ b/crates/typst-library/src/foundations/selector.rs @@ -38,7 +38,7 @@ pub use crate::__select_where as select_where; /// A filter for selecting elements within the document. /// /// To construct a selector you can: -/// - use an element [function] +/// - use an [element function]($function/#element-functions) /// - filter for an element function with [specific fields]($function.where) /// - use a [string]($str) or [regular expression]($regex) /// - use a [`{