From 50e4002a2a65c27f46895103c59cb775ca60d16d Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 24 Apr 2022 14:39:53 +0200 Subject: [PATCH] Split `show` into `realize` and `finalize` --- src/eval/content.rs | 51 ++++++++++++----- src/eval/show.rs | 32 ++++++++--- src/library/math/mod.rs | 17 +++--- src/library/structure/heading.rs | 36 +++++------- src/library/structure/list.rs | 95 ++++++++++++++------------------ src/library/structure/table.rs | 11 +--- src/library/text/deco.rs | 21 +++---- src/library/text/link.rs | 22 ++++---- src/library/text/mod.rs | 18 ++---- src/library/text/raw.rs | 32 +++++------ 10 files changed, 165 insertions(+), 170 deletions(-) diff --git a/src/eval/content.rs b/src/eval/content.rs index 098bfbfc5..2465f0e3a 100644 --- a/src/eval/content.rs +++ b/src/eval/content.rs @@ -104,6 +104,23 @@ impl Content { Self::Show(node.pack()) } + /// Create a new sequence nodes from multiples nodes. + pub fn sequence(seq: Vec) -> Self { + if seq.len() == 1 { + seq.into_iter().next().unwrap() + } else { + Self::Sequence(Arc::new(seq)) + } + } + + /// Repeat this content `n` times. + pub fn repeat(&self, n: i64) -> StrResult { + let count = usize::try_from(n) + .map_err(|_| format!("cannot repeat this content {} times", n))?; + + Ok(Self::sequence(vec![self.clone(); count])) + } + /// Style this content with a single style property. pub fn styled<'k, K: Key<'k>>(mut self, key: K, value: K::Value) -> Self { if let Self::Styled(styled) = &mut self { @@ -137,21 +154,24 @@ impl Content { Self::show(DecoNode::(self)) } - /// Create a new sequence nodes from multiples nodes. - pub fn sequence(seq: Vec) -> Self { - if seq.len() == 1 { - seq.into_iter().next().unwrap() - } else { - Self::Sequence(Arc::new(seq)) + /// Return a node that is spaced apart at top and bottom. + pub fn spaced(self, above: Length, below: Length) -> Self { + if above.is_zero() && below.is_zero() { + return self; } - } - /// Repeat this content `n` times. - pub fn repeat(&self, n: i64) -> StrResult { - let count = usize::try_from(n) - .map_err(|_| format!("cannot repeat this content {} times", n))?; + let mut seq = vec![]; + if !above.is_zero() { + seq.push(Content::Vertical(above.into())); + } - Ok(Self::sequence(vec![self.clone(); count])) + seq.push(self); + + if !below.is_zero() { + seq.push(Content::Vertical(below.into())); + } + + Self::sequence(seq) } /// Layout this content into a collection of pages. @@ -454,8 +474,11 @@ impl<'a> Builder<'a> { } Content::Show(node) => { let id = node.id(); - let realized = styles.realize(ctx, node)?; - let content = node.show(ctx, styles, realized)?; + let realized = match styles.realize(ctx, node)? { + Some(content) => content, + None => node.realize(ctx, styles)?, + }; + let content = node.finalize(ctx, styles, realized)?; let stored = self.tpa.alloc(content); self.process(ctx, stored, styles.unscoped(id))?; } diff --git a/src/eval/show.rs b/src/eval/show.rs index f8d98d52e..c374c2df2 100644 --- a/src/eval/show.rs +++ b/src/eval/show.rs @@ -13,14 +13,26 @@ pub trait Show: 'static { /// Encode this node into a dictionary. fn encode(&self) -> Dict; - /// Show this node in the given styles and optionally given the realization - /// of a show rule. - fn show( + /// The base recipe for this node that is executed if there is no + /// user-defined show rule. + fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult; + + /// Finalize this node given the realization of a base or user recipe. Use + /// this for effects that should work even in the face of a user-defined + /// show rule, for example: + /// - Application of general settable properties + /// - Attaching things like semantics to a heading + /// + /// Defaults to just the realized content. + #[allow(unused_variables)] + fn finalize( &self, ctx: &mut Context, styles: StyleChain, - realized: Option, - ) -> TypResult; + realized: Content, + ) -> TypResult { + Ok(realized) + } /// Convert to a packed show node. fn pack(self) -> ShowNode @@ -55,13 +67,17 @@ impl Show for ShowNode { self.0.encode() } - fn show( + fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult { + self.0.realize(ctx, styles) + } + + fn finalize( &self, ctx: &mut Context, styles: StyleChain, - realized: Option, + realized: Content, ) -> TypResult { - self.0.show(ctx, styles, realized) + self.0.finalize(ctx, styles, realized) } fn pack(self) -> ShowNode { diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs index 587949d74..345bb3f65 100644 --- a/src/library/math/mod.rs +++ b/src/library/math/mod.rs @@ -35,26 +35,27 @@ impl Show for MathNode { } } - fn show( + fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult { + Ok(Content::Text(self.formula.trim().into())) + } + + fn finalize( &self, _: &mut Context, styles: StyleChain, - realized: Option, + mut realized: Content, ) -> TypResult { - let mut content = - realized.unwrap_or_else(|| Content::Text(self.formula.trim().into())); - let mut map = StyleMap::new(); if let Smart::Custom(family) = styles.get(Self::FAMILY) { map.set_family(family.clone(), styles); } - content = content.styled_with_map(map); + realized = realized.styled_with_map(map); if self.display { - content = Content::Block(content.pack()); + realized = Content::block(realized); } - Ok(content) + Ok(realized) } } diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs index a352cc92b..a6c879120 100644 --- a/src/library/structure/heading.rs +++ b/src/library/structure/heading.rs @@ -63,11 +63,15 @@ impl Show for HeadingNode { } } - fn show( + fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult { + Ok(self.body.clone()) + } + + fn finalize( &self, ctx: &mut Context, styles: StyleChain, - realized: Option, + mut realized: Content, ) -> TypResult { macro_rules! resolve { ($key:expr) => { @@ -75,8 +79,6 @@ impl Show for HeadingNode { }; } - let mut body = realized.unwrap_or_else(|| self.body.clone()); - let mut map = StyleMap::new(); map.set(TextNode::SIZE, resolve!(Self::SIZE)); @@ -96,30 +98,22 @@ impl Show for HeadingNode { map.set(TextNode::EMPH, Toggle); } - let mut seq = vec![]; if resolve!(Self::UNDERLINE) { - body = body.underlined(); + realized = realized.underlined(); } - let above = resolve!(Self::ABOVE); - if !above.is_zero() { - seq.push(Content::Vertical(above.resolve(styles).into())); - } - - seq.push(body); - - let below = resolve!(Self::BELOW); - if !below.is_zero() { - seq.push(Content::Vertical(below.resolve(styles).into())); - } - - let mut content = Content::sequence(seq).styled_with_map(map); + realized = realized.styled_with_map(map); if resolve!(Self::BLOCK) { - content = Content::block(content); + realized = Content::block(realized); } - Ok(content) + realized = realized.spaced( + resolve!(Self::ABOVE).resolve(styles), + resolve!(Self::BELOW).resolve(styles), + ); + + Ok(realized) } } diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs index c59b443dc..6655175fc 100644 --- a/src/library/structure/list.rs +++ b/src/library/structure/list.rs @@ -79,66 +79,51 @@ impl Show for ListNode { } } - fn show( - &self, - ctx: &mut Context, - styles: StyleChain, - realized: Option, - ) -> TypResult { - let content = if let Some(content) = realized { - content + fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult { + let mut cells = vec![]; + let mut number = self.start; + + let label = styles.get(Self::LABEL); + + for item in &self.items { + number = item.number.unwrap_or(number); + cells.push(LayoutNode::default()); + cells.push(label.resolve(ctx, L, number)?.pack()); + cells.push(LayoutNode::default()); + cells.push((*item.body).clone().pack()); + number += 1; + } + + let leading = styles.get(ParNode::LEADING); + let spacing = if self.tight { + styles.get(Self::SPACING) } else { - let mut cells = vec![]; - let mut number = self.start; - - let label = styles.get(Self::LABEL); - - for item in &self.items { - number = item.number.unwrap_or(number); - cells.push(LayoutNode::default()); - cells.push(label.resolve(ctx, L, number)?.pack()); - cells.push(LayoutNode::default()); - cells.push((*item.body).clone().pack()); - number += 1; - } - - let leading = styles.get(ParNode::LEADING); - let spacing = if self.tight { - styles.get(Self::SPACING) - } else { - styles.get(ParNode::SPACING) - }; - - let gutter = leading + spacing; - let indent = styles.get(Self::INDENT); - let body_indent = styles.get(Self::BODY_INDENT); - - Content::block(GridNode { - tracks: Spec::with_x(vec![ - TrackSizing::Relative(indent.into()), - TrackSizing::Auto, - TrackSizing::Relative(body_indent.into()), - TrackSizing::Auto, - ]), - gutter: Spec::with_y(vec![TrackSizing::Relative(gutter.into())]), - cells, - }) + styles.get(ParNode::SPACING) }; - let mut seq = vec![]; - let above = styles.get(Self::ABOVE); - if !above.is_zero() { - seq.push(Content::Vertical(above.into())); - } + let gutter = leading + spacing; + let indent = styles.get(Self::INDENT); + let body_indent = styles.get(Self::BODY_INDENT); - seq.push(content); + Ok(Content::block(GridNode { + tracks: Spec::with_x(vec![ + TrackSizing::Relative(indent.into()), + TrackSizing::Auto, + TrackSizing::Relative(body_indent.into()), + TrackSizing::Auto, + ]), + gutter: Spec::with_y(vec![TrackSizing::Relative(gutter.into())]), + cells, + })) + } - let below = styles.get(Self::BELOW); - if !below.is_zero() { - seq.push(Content::Vertical(below.into())); - } - - Ok(Content::sequence(seq)) + fn finalize( + &self, + _: &mut Context, + styles: StyleChain, + realized: Content, + ) -> TypResult { + Ok(realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))) } } diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs index aefd01b54..191d3dd35 100644 --- a/src/library/structure/table.rs +++ b/src/library/structure/table.rs @@ -64,16 +64,7 @@ impl Show for TableNode { } } - fn show( - &self, - _: &mut Context, - styles: StyleChain, - realized: Option, - ) -> TypResult { - if let Some(content) = realized { - return Ok(content); - } - + fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult { let primary = styles.get(Self::PRIMARY); let secondary = styles.get(Self::SECONDARY); let stroke = styles.get(Self::STROKE).map(RawStroke::unwrap_or_default); diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs index 9fe4e65a6..52f8ea80c 100644 --- a/src/library/text/deco.rs +++ b/src/library/text/deco.rs @@ -47,20 +47,13 @@ impl Show for DecoNode { dict! { "body" => Value::Content(self.0.clone()) } } - fn show( - &self, - _: &mut Context, - styles: StyleChain, - realized: Option, - ) -> TypResult { - Ok(realized.unwrap_or_else(|| { - self.0.clone().styled(TextNode::DECO, Decoration { - line: L, - stroke: styles.get(Self::STROKE).unwrap_or_default(), - offset: styles.get(Self::OFFSET), - extent: styles.get(Self::EXTENT), - evade: styles.get(Self::EVADE), - }) + fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult { + Ok(self.0.clone().styled(TextNode::DECO, Decoration { + line: L, + stroke: styles.get(Self::STROKE).unwrap_or_default(), + offset: styles.get(Self::OFFSET), + extent: styles.get(Self::EXTENT), + evade: styles.get(Self::EVADE), })) } } diff --git a/src/library/text/link.rs b/src/library/text/link.rs index d1e5eb8e3..710fbc477 100644 --- a/src/library/text/link.rs +++ b/src/library/text/link.rs @@ -38,13 +38,8 @@ impl Show for LinkNode { } } - fn show( - &self, - _: &mut Context, - styles: StyleChain, - realized: Option, - ) -> TypResult { - let mut body = realized.or_else(|| self.body.clone()).unwrap_or_else(|| { + fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult { + Ok(self.body.clone().unwrap_or_else(|| { let url = &self.url; let mut text = url.as_str(); for prefix in ["mailto:", "tel:"] { @@ -52,8 +47,15 @@ impl Show for LinkNode { } let shorter = text.len() < url.len(); Content::Text(if shorter { text.into() } else { url.clone() }) - }); + })) + } + fn finalize( + &self, + _: &mut Context, + styles: StyleChain, + mut realized: Content, + ) -> TypResult { let mut map = StyleMap::new(); map.set(TextNode::LINK, Some(self.url.clone())); @@ -62,9 +64,9 @@ impl Show for LinkNode { } if styles.get(Self::UNDERLINE) { - body = body.underlined(); + realized = realized.underlined(); } - Ok(body.styled_with_map(map)) + Ok(realized.styled_with_map(map)) } } diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index e477e76d1..3cfbc55d3 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -475,13 +475,8 @@ impl Show for StrongNode { dict! { "body" => Value::Content(self.0.clone()) } } - fn show( - &self, - _: &mut Context, - _: StyleChain, - realized: Option, - ) -> TypResult { - Ok(realized.unwrap_or_else(|| self.0.clone().styled(TextNode::STRONG, Toggle))) + fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult { + Ok(self.0.clone().styled(TextNode::STRONG, Toggle)) } } @@ -501,12 +496,7 @@ impl Show for EmphNode { dict! { "body" => Value::Content(self.0.clone()) } } - fn show( - &self, - _: &mut Context, - _: StyleChain, - realized: Option, - ) -> TypResult { - Ok(realized.unwrap_or_else(|| self.0.clone().styled(TextNode::EMPH, Toggle))) + fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult { + Ok(self.0.clone().styled(TextNode::EMPH, Toggle)) } } diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs index cc225bedb..13daa1b9c 100644 --- a/src/library/text/raw.rs +++ b/src/library/text/raw.rs @@ -50,12 +50,7 @@ impl Show for RawNode { } } - fn show( - &self, - _: &mut Context, - styles: StyleChain, - realized: Option, - ) -> TypResult { + fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult { let lang = styles.get(Self::LANG).as_ref(); let foreground = THEME .settings @@ -64,9 +59,7 @@ impl Show for RawNode { .unwrap_or(Color::BLACK) .into(); - let mut content = if let Some(content) = realized { - content - } else if matches!( + if matches!( lang.map(|s| s.to_lowercase()).as_deref(), Some("typ" | "typst") ) { @@ -79,7 +72,7 @@ impl Show for RawNode { seq.push(styled(&self.text[range], foreground, style)); }); - Content::sequence(seq) + Ok(Content::sequence(seq)) } else if let Some(syntax) = lang.and_then(|token| SYNTAXES.find_syntax_by_token(&token)) { @@ -95,11 +88,18 @@ impl Show for RawNode { } } - Content::sequence(seq) + Ok(Content::sequence(seq)) } else { - Content::Text(self.text.clone()) - }; + Ok(Content::Text(self.text.clone())) + } + } + fn finalize( + &self, + _: &mut Context, + styles: StyleChain, + mut realized: Content, + ) -> TypResult { let mut map = StyleMap::new(); map.set(TextNode::OVERHANG, false); map.set(TextNode::HYPHENATE, Smart::Custom(Hyphenate(false))); @@ -109,13 +109,13 @@ impl Show for RawNode { map.set_family(family.clone(), styles); } - content = content.styled_with_map(map); + realized = realized.styled_with_map(map); if self.block { - content = Content::Block(content.pack()); + realized = Content::block(realized); } - Ok(content) + Ok(realized) } }