diff --git a/Cargo.lock b/Cargo.lock index 9ba77fa32..b516363ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2632,8 +2632,10 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" name = "typst" version = "0.11.0" dependencies = [ + "arrayvec", "az", "bitflags 2.6.0", + "bumpalo", "chinese-number", "ciborium", "comemo", diff --git a/Cargo.toml b/Cargo.toml index 7289bd7d2..e5882afad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ arrayvec = "0.7.4" az = "1.2" base64 = "0.22" bitflags = { version = "2", features = ["serde"] } +bumpalo = { version = "3", features = ["collections"] } bytemuck = "1" chinese-number = { version = "0.7.2", default-features = false, features = ["number-to-chinese"] } chrono = { version = "0.4.24", default-features = false, features = ["clock", "std"] } diff --git a/crates/typst/Cargo.toml b/crates/typst/Cargo.toml index b90780377..2b9c5d1a6 100644 --- a/crates/typst/Cargo.toml +++ b/crates/typst/Cargo.toml @@ -18,8 +18,10 @@ typst-macros = { workspace = true } typst-syntax = { workspace = true } typst-timing = { workspace = true } typst-utils = { workspace = true } +arrayvec = { workspace = true } az = { workspace = true } bitflags = { workspace = true } +bumpalo = { workspace = true } chinese-number = { workspace = true } ciborium = { workspace = true } comemo = { workspace = true } diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs index d0ab7d2c6..9e4d9d709 100644 --- a/crates/typst/src/engine.rs +++ b/crates/typst/src/engine.rs @@ -29,15 +29,11 @@ pub struct Engine<'a> { } impl Engine<'_> { - /// Performs a fallible operation that does not immediately terminate further - /// execution. Instead it produces a delayed error that is only promoted to - /// a fatal one if it remains at the end of the introspection loop. - pub fn delay(&mut self, f: F) -> T - where - F: FnOnce(&mut Self) -> SourceResult, - T: Default, - { - match f(self) { + /// Handles a result without immediately terminating execution. Instead, it + /// produces a delayed error that is only promoted to a fatal one if it + /// remains by the end of the introspection loop. + pub fn delay(&mut self, result: SourceResult) -> T { + match result { Ok(value) => value, Err(errors) => { self.sink.delay(errors); diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs index b9d1b1897..91c911ed9 100644 --- a/crates/typst/src/foundations/content.rs +++ b/crates/typst/src/foundations/content.rs @@ -21,10 +21,9 @@ use crate::foundations::{ use crate::introspection::Location; use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides}; use crate::model::{Destination, EmphElem, LinkElem, StrongElem}; -use crate::realize::{Behave, Behaviour}; use crate::syntax::Span; use crate::text::UnderlineElem; -use crate::utils::{fat, LazyHash, SmallBitSet}; +use crate::utils::{fat, singleton, LazyHash, SmallBitSet}; /// A piece of document content. /// @@ -109,9 +108,9 @@ impl Content { } } - /// Creates a new empty sequence content. + /// Creates a empty sequence content. pub fn empty() -> Self { - Self::new(SequenceElem::default()) + singleton!(Content, SequenceElem::default().pack()).clone() } /// Get the element of this content. @@ -185,12 +184,6 @@ impl Content { self.make_mut().lifecycle.insert(0); } - /// How this element interacts with other elements in a stream. - pub fn behaviour(&self) -> Behaviour { - self.with::() - .map_or(Behaviour::Supportive, Behave::behaviour) - } - /// Get a field by ID. /// /// This is the preferred way to access fields. However, you can only use it diff --git a/crates/typst/src/foundations/selector.rs b/crates/typst/src/foundations/selector.rs index 55fd95559..3a9ab3082 100644 --- a/crates/typst/src/foundations/selector.rs +++ b/crates/typst/src/foundations/selector.rs @@ -12,7 +12,6 @@ use crate::foundations::{ }; use crate::introspection::{Introspector, Locatable, Location}; use crate::symbols::Symbol; -use crate::text::TextElem; /// A helper macro to create a field selector used in [`Selector::Elem`] #[macro_export] @@ -126,15 +125,12 @@ impl Selector { pub fn matches(&self, target: &Content, styles: Option) -> bool { match self { Self::Elem(element, dict) => { - target.func() == *element + target.elem() == *element && dict.iter().flat_map(|dict| dict.iter()).all(|(id, value)| { target.get(*id, styles).as_ref().ok() == Some(value) }) } Self::Label(label) => target.label() == Some(*label), - Self::Regex(regex) => target - .to_packed::() - .is_some_and(|elem| regex.is_match(elem.text())), Self::Can(cap) => target.func().can_type_id(*cap), Self::Or(selectors) => { selectors.iter().any(move |sel| sel.matches(target, styles)) @@ -144,7 +140,7 @@ impl Selector { } Self::Location(location) => target.location() == Some(*location), // Not supported here. - Self::Before { .. } | Self::After { .. } => false, + Self::Regex(_) | Self::Before { .. } | Self::After { .. } => false, } } } diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs index e74a16499..e297db7d7 100644 --- a/crates/typst/src/foundations/styles.rs +++ b/crates/typst/src/foundations/styles.rs @@ -164,12 +164,6 @@ impl Styles { .any(|property| property.is_of(elem) && property.id == field) } - /// Returns `Some(_)` with an optional span if this list contains - /// styles for the given element. - pub fn interruption(&self) -> Option { - self.0.iter().find_map(|entry| entry.interruption::()) - } - /// Set a font family composed of a preferred family and existing families /// from a style chain. pub fn set_family(&mut self, preferred: FontFamily, existing: StyleChain) { @@ -229,6 +223,10 @@ pub enum Style { /// A show rule recipe. Recipe(Recipe), /// Disables a specific show rule recipe. + /// + /// Note: This currently only works for regex recipes since it's the only + /// place we need it for the moment. Normal show rules use guards directly + /// on elements instead. Revocation(RecipeIndex), } @@ -249,13 +247,24 @@ impl Style { } } - /// Returns `Some(_)` with an optional span if this style is of - /// the given element. - pub fn interruption(&self) -> Option { - let elem = T::elem(); + /// The style's span, if any. + pub fn span(&self) -> Span { match self { - Style::Property(property) => property.is_of(elem).then_some(property.span), - Style::Recipe(recipe) => recipe.is_of(elem).then_some(recipe.span), + Self::Property(property) => property.span, + Self::Recipe(recipe) => recipe.span, + Self::Revocation(_) => Span::detached(), + } + } + + /// Returns `Some(_)` with an optional span if this style is for + /// the given element. + pub fn element(&self) -> Option { + match self { + Style::Property(property) => Some(property.elem), + Style::Recipe(recipe) => match recipe.selector { + Some(Selector::Elem(elem, _)) => Some(elem), + _ => None, + }, Style::Revocation(_) => None, } } @@ -279,6 +288,11 @@ impl Style { Self::Revocation(_) => false, } } + + /// Turn this style into prehashed style. + pub fn wrap(self) -> LazyHash