diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/mod.rs | 25 | ||||
| -rw-r--r-- | src/eval/template.rs | 90 |
2 files changed, 60 insertions, 55 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs index fce8bed4..33ee23ca 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -183,17 +183,18 @@ fn eval_markup( nodes: &mut impl Iterator<Item = MarkupNode>, ) -> TypResult<Template> { let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default()); - let mut styles = StyleMap::new(); while let Some(node) = nodes.next() { - let template = match node { + seq.push(match node { MarkupNode::Expr(Expr::Set(set)) => { let class = set.class(); let class = class.eval(ctx)?.cast::<Class>().at(class.span())?; let mut args = set.args().eval(ctx)?; + let mut styles = StyleMap::new(); class.set(&mut args, &mut styles)?; args.finish()?; - continue; + let tail = eval_markup(ctx, nodes)?; + tail.styled_with_map(styles) } MarkupNode::Expr(Expr::Show(show)) => { return Err("show rules are not yet implemented").at(show.span()); @@ -204,12 +205,14 @@ fn eval_markup( wrap.body().eval(ctx)?.show() } _ => node.eval(ctx)?, - }; - - seq.push(Styled::new(template, styles.clone())); + }); } - Ok(Template::Sequence(seq)) + if seq.len() == 1 { + Ok(seq.into_iter().next().unwrap()) + } else { + Ok(Template::Sequence(seq)) + } } impl Eval for MarkupNode { @@ -265,7 +268,7 @@ impl Eval for RawNode { impl RawNode { /// Styled template for a code block, with optional syntax highlighting. pub fn highlighted(&self) -> Template { - let mut seq: Vec<Styled<Template>> = vec![]; + let mut seq: Vec<Template> = vec![]; let syntax = if let Some(syntax) = self .lang @@ -294,7 +297,7 @@ impl RawNode { let mut highlighter = HighlightLines::new(syntax, &THEME); for (i, line) in self.text.lines().enumerate() { if i != 0 { - seq.push(Styled::bare(Template::Linebreak)); + seq.push(Template::Linebreak); } for (style, piece) in highlighter.highlight(line, &SYNTAXES) { @@ -322,7 +325,7 @@ impl RawNode { } /// Style a piece of text with a syntect style. -fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Template> { +fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Template { let mut styles = StyleMap::new(); let paint = style.foreground.into(); @@ -342,7 +345,7 @@ fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Templa styles.set(TextNode::LINES, vec![DecoLine::Underline.into()]); } - Styled::new(Template::Text(piece.into()), styles) + Template::Text(piece.into()).styled_with_map(styles) } impl Eval for MathNode { diff --git a/src/eval/template.rs b/src/eval/template.rs index 8a49f84d..c1a2b44c 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -20,9 +20,25 @@ use crate::util::EcoString; /// - anything written between square brackets in Typst /// - any class constructor /// -/// When you write `[Hi] + [you]` in Typst, this type's [`Add`] implementation -/// is invoked. There, multiple templates are combined into a single -/// [`Sequence`](Self::Sequence) template. +/// This enum has two notable variants: +/// +/// 1. A `Styled` template attaches a style map to a template. This map affects +/// the whole subtemplate. For example, a single bold word could be +/// represented as a `Styled(Text("Hello"), [TextNode::STRONG: true])` +/// template. +/// +/// 2. A `Sequence` template simply combines multiple templates and will be +/// layouted as a [flow](FlowNode). So, when you write `[Hi] + [you]` in +/// Typst, this type's [`Add`] implementation is invoked and the two +/// templates are combined into a single [`Sequence`](Self::Sequence) +/// template. +/// +/// A sequence may contain nested sequences (meaning this variant effectively +/// allows nodes to form trees). All nested sequences can equivalently be +/// represented as a single flat sequence, but allowing nesting doesn't hurt +/// since we can just recurse into the nested sequences during packing. Also, +/// in theory, this allows better complexity when adding (large) sequence +/// nodes (just like for a text rope). #[derive(Debug, PartialEq, Clone, Hash)] pub enum Template { /// A word space. @@ -45,21 +61,10 @@ pub enum Template { Block(PackedNode), /// A page node. Page(PageNode), - /// Multiple nodes with attached styles. - /// - /// For example, the Typst template `[Hi *you!*]` would result in the - /// sequence: - /// - `Text("Hi")` with empty style map, - /// - `Space` with empty style map, - /// - `Text("you!")` with `TextNode::STRONG` set to `true`. - /// - /// A sequence may contain nested sequences (meaning this variant - /// effectively allows nodes to form trees). All nested sequences can - /// equivalently be represented as a single flat sequence, but allowing - /// nesting doesn't hurt since we can just recurse into the nested sequences - /// during packing. Also, in theory, this allows better complexity when - /// adding (large) sequence nodes (just like for a text rope). - Sequence(Vec<Styled<Self>>), + /// A template with attached styles. + Styled(Box<Self>, StyleMap), + /// A sequence of multiple subtemplates. + Sequence(Vec<Self>), } impl Template { @@ -86,30 +91,24 @@ impl Template { /// Style this template with a single property. pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self { - if let Self::Sequence(vec) = &mut self { - if let [styled] = vec.as_mut_slice() { - styled.map.set(key, value); - return self; - } + if let Self::Styled(_, map) = &mut self { + map.set(key, value); + self + } else { + self.styled_with_map(StyleMap::with(key, value)) } - - self.styled_with_map(StyleMap::with(key, value)) } /// Style this template with a full style map. pub fn styled_with_map(mut self, styles: StyleMap) -> Self { if styles.is_empty() { - return self; - } - - if let Self::Sequence(vec) = &mut self { - if let [styled] = vec.as_mut_slice() { - styled.map.apply(&styles); - return self; - } + self + } else if let Self::Styled(_, map) = &mut self { + map.apply(&styles); + self + } else { + Self::Styled(Box::new(self), styles) } - - Self::Sequence(vec![Styled::new(self, styles)]) } /// Style this template in monospace. @@ -140,7 +139,7 @@ impl Template { let count = usize::try_from(n) .map_err(|_| format!("cannot repeat this template {} times", n))?; - Ok(Self::Sequence(vec![Styled::bare(self.clone()); count])) + Ok(Self::Sequence(vec![self.clone(); count])) } } @@ -160,15 +159,15 @@ impl Add for Template { left } (Self::Sequence(mut left), right) => { - left.push(Styled::bare(right)); + left.push(right); left } (left, Self::Sequence(mut right)) => { - right.insert(0, Styled::bare(left)); + right.insert(0, left); right } (left, right) => { - vec![Styled::bare(left), Styled::bare(right)] + vec![left, right] } }) } @@ -182,7 +181,7 @@ impl AddAssign for Template { impl Sum for Template { fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { - Self::Sequence(iter.map(|n| Styled::bare(n)).collect()) + Self::Sequence(iter.collect()) } } @@ -289,12 +288,15 @@ impl Packer { self.push_block(Styled::new(page.0, styles)); } } - Template::Sequence(list) => { + Template::Styled(template, mut map) => { + map.apply(&styles); + self.walk(*template, map); + } + Template::Sequence(seq) => { // For a list of templates, we apply the list's styles to each // templates individually. - for Styled { item, mut map } in list { - map.apply(&styles); - self.walk(item, map); + for item in seq { + self.walk(item, styles.clone()); } } } |
