summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-24 14:39:53 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-24 14:53:43 +0200
commit50e4002a2a65c27f46895103c59cb775ca60d16d (patch)
treedbd43c16ae8456536c89d64d2cfff293bb6b1148
parent04fb8b288aa7c80607da79db7d085a4820b95a9d (diff)
Split `show` into `realize` and `finalize`
-rw-r--r--src/eval/content.rs51
-rw-r--r--src/eval/show.rs32
-rw-r--r--src/library/math/mod.rs17
-rw-r--r--src/library/structure/heading.rs36
-rw-r--r--src/library/structure/list.rs97
-rw-r--r--src/library/structure/table.rs11
-rw-r--r--src/library/text/deco.rs21
-rw-r--r--src/library/text/link.rs22
-rw-r--r--src/library/text/mod.rs18
-rw-r--r--src/library/text/raw.rs32
10 files changed, 166 insertions, 171 deletions
diff --git a/src/eval/content.rs b/src/eval/content.rs
index 098bfbfc..2465f0e3 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>) -> 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<Self> {
+ 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::<UNDERLINE>(self))
}
- /// Create a new sequence nodes from multiples nodes.
- pub fn sequence(seq: Vec<Self>) -> 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<Self> {
- 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 f8d98d52..c374c2df 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<Content>;
+
+ /// 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<Content>,
- ) -> TypResult<Content>;
+ realized: Content,
+ ) -> TypResult<Content> {
+ 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<Content> {
+ self.0.realize(ctx, styles)
+ }
+
+ fn finalize(
&self,
ctx: &mut Context,
styles: StyleChain,
- realized: Option<Content>,
+ realized: Content,
) -> TypResult<Content> {
- 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 587949d7..345bb3f6 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<Content> {
+ Ok(Content::Text(self.formula.trim().into()))
+ }
+
+ fn finalize(
&self,
_: &mut Context,
styles: StyleChain,
- realized: Option<Content>,
+ mut realized: Content,
) -> TypResult<Content> {
- 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 a352cc92..a6c87912 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<Content> {
+ Ok(self.body.clone())
+ }
+
+ fn finalize(
&self,
ctx: &mut Context,
styles: StyleChain,
- realized: Option<Content>,
+ mut realized: Content,
) -> TypResult<Content> {
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();
- }
-
- let above = resolve!(Self::ABOVE);
- if !above.is_zero() {
- seq.push(Content::Vertical(above.resolve(styles).into()));
+ realized = realized.underlined();
}
- 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 c59b443d..6655175f 100644
--- a/src/library/structure/list.rs
+++ b/src/library/structure/list.rs
@@ -79,66 +79,51 @@ impl<const L: ListKind> Show for ListNode<L> {
}
}
- fn show(
- &self,
- ctx: &mut Context,
- styles: StyleChain,
- realized: Option<Content>,
- ) -> TypResult<Content> {
- let content = if let Some(content) = realized {
- content
- } 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,
- })
- };
-
- let mut seq = vec![];
- let above = styles.get(Self::ABOVE);
- if !above.is_zero() {
- seq.push(Content::Vertical(above.into()));
+ fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ 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;
}
- seq.push(content);
+ let leading = styles.get(ParNode::LEADING);
+ let spacing = if self.tight {
+ styles.get(Self::SPACING)
+ } else {
+ styles.get(ParNode::SPACING)
+ };
- let below = styles.get(Self::BELOW);
- if !below.is_zero() {
- seq.push(Content::Vertical(below.into()));
- }
+ let gutter = leading + spacing;
+ let indent = styles.get(Self::INDENT);
+ let body_indent = styles.get(Self::BODY_INDENT);
+
+ 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,
+ }))
+ }
- Ok(Content::sequence(seq))
+ fn finalize(
+ &self,
+ _: &mut Context,
+ styles: StyleChain,
+ realized: Content,
+ ) -> TypResult<Content> {
+ 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 aefd01b5..191d3dd3 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<Content>,
- ) -> TypResult<Content> {
- if let Some(content) = realized {
- return Ok(content);
- }
-
+ fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
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 9fe4e65a..52f8ea80 100644
--- a/src/library/text/deco.rs
+++ b/src/library/text/deco.rs
@@ -47,20 +47,13 @@ impl<const L: DecoLine> Show for DecoNode<L> {
dict! { "body" => Value::Content(self.0.clone()) }
}
- fn show(
- &self,
- _: &mut Context,
- styles: StyleChain,
- realized: Option<Content>,
- ) -> TypResult<Content> {
- 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<Content> {
+ 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 d1e5eb8e..710fbc47 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<Content>,
- ) -> TypResult<Content> {
- let mut body = realized.or_else(|| self.body.clone()).unwrap_or_else(|| {
+ fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ 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<Content> {
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 e477e76d..3cfbc55d 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<Content>,
- ) -> TypResult<Content> {
- Ok(realized.unwrap_or_else(|| self.0.clone().styled(TextNode::STRONG, Toggle)))
+ fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ 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<Content>,
- ) -> TypResult<Content> {
- Ok(realized.unwrap_or_else(|| self.0.clone().styled(TextNode::EMPH, Toggle)))
+ fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ Ok(self.0.clone().styled(TextNode::EMPH, Toggle))
}
}
diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs
index cc225bed..13daa1b9 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<Content>,
- ) -> TypResult<Content> {
+ fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
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<Content> {
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)
}
}