Rename Node to Template

This commit is contained in:
Laurenz 2022-02-02 16:02:23 +01:00
parent 0a1916c1e4
commit a7b403fd74
31 changed files with 244 additions and 246 deletions

View File

@ -179,7 +179,7 @@ fn process_const(
const NAME: &'static str = #name; const NAME: &'static str = #name;
fn node_id() -> TypeId { fn class_id() -> TypeId {
TypeId::of::<#self_ty>() TypeId::of::<#self_ty>()
} }

View File

@ -1,15 +1,15 @@
use std::fmt::{self, Debug, Formatter, Write}; use std::fmt::{self, Debug, Formatter, Write};
use super::{Args, EvalContext, Func, Node, StyleMap, Value}; use super::{Args, EvalContext, Func, StyleMap, Template, Value};
use crate::diag::TypResult; use crate::diag::TypResult;
/// A class of [nodes](Node). /// A class of nodes.
/// ///
/// You can [construct] an instance of a class in Typst code by invoking the /// You can [construct] an instance of a class in Typst code by invoking the
/// class as a callable. This always produces some node, but not necessarily one /// class as a callable. This always produces a template, but not necessarily a
/// of fixed type. For example, the `text` constructor does not actually create /// simple inline or block node. For example, the `text` constructor does not
/// a [`TextNode`]. Instead it applies styling to whatever node you pass in and /// actually create a [`TextNode`]. Instead it applies styling to whatever node
/// returns it structurally unchanged. /// you pass in and returns it structurally unchanged.
/// ///
/// The arguments you can pass to a class constructor fall into two categories: /// The arguments you can pass to a class constructor fall into two categories:
/// Data that is inherent to the instance (e.g. the text of a heading) and style /// Data that is inherent to the instance (e.g. the text of a heading) and style
@ -50,8 +50,8 @@ impl Class {
construct: |ctx, args| { construct: |ctx, args| {
let mut styles = StyleMap::new(); let mut styles = StyleMap::new();
T::set(args, &mut styles)?; T::set(args, &mut styles)?;
let node = T::construct(ctx, args)?; let template = T::construct(ctx, args)?;
Ok(Value::Node(node.styled_with_map(styles.scoped()))) Ok(Value::Template(template.styled_with_map(styles.scoped())))
}, },
set: T::set, set: T::set,
} }
@ -65,7 +65,7 @@ impl Class {
/// Construct an instance of the class. /// Construct an instance of the class.
/// ///
/// This parses both property and data arguments (in this order) and styles /// This parses both property and data arguments (in this order) and styles
/// the node constructed from the data with the style properties. /// the template constructed from the data with the style properties.
pub fn construct(&self, ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { pub fn construct(&self, ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
(self.construct)(ctx, args) (self.construct)(ctx, args)
} }
@ -104,7 +104,7 @@ pub trait Construct {
/// ///
/// This is passed only the arguments that remain after execution of the /// This is passed only the arguments that remain after execution of the
/// class's set rule. /// class's set rule.
fn construct(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Node>; fn construct(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Template>;
} }
/// Set style properties of a class. /// Set style properties of a class.

View File

@ -11,18 +11,18 @@ mod styles;
mod capture; mod capture;
mod class; mod class;
mod func; mod func;
mod node;
mod ops; mod ops;
mod scope; mod scope;
mod template;
pub use array::*; pub use array::*;
pub use capture::*; pub use capture::*;
pub use class::*; pub use class::*;
pub use dict::*; pub use dict::*;
pub use func::*; pub use func::*;
pub use node::*;
pub use scope::*; pub use scope::*;
pub use styles::*; pub use styles::*;
pub use template::*;
pub use value::*; pub use value::*;
use std::cell::RefMut; use std::cell::RefMut;
@ -64,13 +64,13 @@ pub struct Module {
/// The top-level definitions that were bound in this module. /// The top-level definitions that were bound in this module.
pub scope: Scope, pub scope: Scope,
/// The module's layoutable contents. /// The module's layoutable contents.
pub node: Node, pub template: Template,
} }
impl Module { impl Module {
/// Convert this module's node into a layout tree. /// Convert this module's template into a layout tree.
pub fn into_root(self) -> RootNode { pub fn into_root(self) -> RootNode {
self.node.into_root() self.template.into_root()
} }
} }
@ -143,14 +143,14 @@ impl<'a> EvalContext<'a> {
self.route.push(id); self.route.push(id);
// Evaluate the module. // Evaluate the module.
let node = ast.eval(self).trace(|| Tracepoint::Import, span)?; let template = ast.eval(self).trace(|| Tracepoint::Import, span)?;
// Restore the old context. // Restore the old context.
let new_scopes = mem::replace(&mut self.scopes, prev_scopes); let new_scopes = mem::replace(&mut self.scopes, prev_scopes);
self.route.pop().unwrap(); self.route.pop().unwrap();
// Save the evaluated module. // Save the evaluated module.
let module = Module { scope: new_scopes.top, node }; let module = Module { scope: new_scopes.top, template };
self.modules.insert(id, module); self.modules.insert(id, module);
Ok(id) Ok(id)
@ -170,7 +170,7 @@ impl<'a> EvalContext<'a> {
} }
impl Eval for Markup { impl Eval for Markup {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
eval_markup(ctx, &mut self.nodes()) eval_markup(ctx, &mut self.nodes())
@ -181,12 +181,12 @@ impl Eval for Markup {
fn eval_markup( fn eval_markup(
ctx: &mut EvalContext, ctx: &mut EvalContext,
nodes: &mut impl Iterator<Item = MarkupNode>, nodes: &mut impl Iterator<Item = MarkupNode>,
) -> TypResult<Node> { ) -> TypResult<Template> {
let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default()); let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default());
let mut styles = StyleMap::new(); let mut styles = StyleMap::new();
while let Some(node) = nodes.next() { while let Some(node) = nodes.next() {
let result = match node { let template = match node {
MarkupNode::Expr(Expr::Set(set)) => { MarkupNode::Expr(Expr::Set(set)) => {
let class = set.class(); let class = set.class();
let class = class.eval(ctx)?.cast::<Class>().at(class.span())?; let class = class.eval(ctx)?.cast::<Class>().at(class.span())?;
@ -206,21 +206,21 @@ fn eval_markup(
_ => node.eval(ctx)?, _ => node.eval(ctx)?,
}; };
seq.push(Styled::new(result, styles.clone())); seq.push(Styled::new(template, styles.clone()));
} }
Ok(Node::Sequence(seq)) Ok(Template::Sequence(seq))
} }
impl Eval for MarkupNode { impl Eval for MarkupNode {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
Ok(match self { Ok(match self {
Self::Space => Node::Space, Self::Space => Template::Space,
Self::Linebreak => Node::Linebreak, Self::Linebreak => Template::Linebreak,
Self::Parbreak => Node::Parbreak, Self::Parbreak => Template::Parbreak,
Self::Text(text) => Node::Text(text.clone()), Self::Text(text) => Template::Text(text.clone()),
Self::Strong(strong) => strong.eval(ctx)?, Self::Strong(strong) => strong.eval(ctx)?,
Self::Emph(emph) => emph.eval(ctx)?, Self::Emph(emph) => emph.eval(ctx)?,
Self::Raw(raw) => raw.eval(ctx)?, Self::Raw(raw) => raw.eval(ctx)?,
@ -234,7 +234,7 @@ impl Eval for MarkupNode {
} }
impl Eval for StrongNode { impl Eval for StrongNode {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
Ok(self.body().eval(ctx)?.styled(TextNode::STRONG, true)) Ok(self.body().eval(ctx)?.styled(TextNode::STRONG, true))
@ -242,7 +242,7 @@ impl Eval for StrongNode {
} }
impl Eval for EmphNode { impl Eval for EmphNode {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
Ok(self.body().eval(ctx)?.styled(TextNode::EMPH, true)) Ok(self.body().eval(ctx)?.styled(TextNode::EMPH, true))
@ -250,12 +250,12 @@ impl Eval for EmphNode {
} }
impl Eval for RawNode { impl Eval for RawNode {
type Output = Node; type Output = Template;
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
let code = self.highlighted(); let code = self.highlighted();
Ok(if self.block { Ok(if self.block {
Node::Block(code.into_block()) Template::Block(code.into_block())
} else { } else {
code code
}) })
@ -263,9 +263,9 @@ impl Eval for RawNode {
} }
impl RawNode { impl RawNode {
/// Styled node for a code block, with optional syntax highlighting. /// Styled template for a code block, with optional syntax highlighting.
pub fn highlighted(&self) -> Node { pub fn highlighted(&self) -> Template {
let mut sequence: Vec<Styled<Node>> = vec![]; let mut seq: Vec<Styled<Template>> = vec![];
let syntax = if let Some(syntax) = self let syntax = if let Some(syntax) = self
.lang .lang
@ -279,7 +279,7 @@ impl RawNode {
) { ) {
None None
} else { } else {
return Node::Text(self.text.clone()).monospaced(); return Template::Text(self.text.clone()).monospaced();
}; };
let foreground = THEME let foreground = THEME
@ -294,11 +294,11 @@ impl RawNode {
let mut highlighter = HighlightLines::new(syntax, &THEME); let mut highlighter = HighlightLines::new(syntax, &THEME);
for (i, line) in self.text.lines().enumerate() { for (i, line) in self.text.lines().enumerate() {
if i != 0 { if i != 0 {
sequence.push(Styled::bare(Node::Linebreak)); seq.push(Styled::bare(Template::Linebreak));
} }
for (style, piece) in highlighter.highlight(line, &SYNTAXES) { for (style, piece) in highlighter.highlight(line, &SYNTAXES) {
sequence.push(style_piece(piece, foreground, style)); seq.push(style_piece(piece, foreground, style));
} }
} }
} }
@ -311,23 +311,21 @@ impl RawNode {
red.as_ref(), red.as_ref(),
&highlighter, &highlighter,
&mut |range, style| { &mut |range, style| {
sequence.push(style_piece(&self.text[range], foreground, style)); seq.push(style_piece(&self.text[range], foreground, style));
}, },
) )
} }
} }
Node::Sequence(sequence).monospaced() Template::Sequence(seq).monospaced()
} }
} }
/// Style a piece of text with a syntect style. /// Style a piece of text with a syntect style.
fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Node> { fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Template> {
let paint = style.foreground.into();
let node = Node::Text(piece.into());
let mut styles = StyleMap::new(); let mut styles = StyleMap::new();
let paint = style.foreground.into();
if paint != foreground { if paint != foreground {
styles.set(TextNode::FILL, paint); styles.set(TextNode::FILL, paint);
} }
@ -344,16 +342,16 @@ fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Node>
styles.set(TextNode::LINES, vec![DecoLine::Underline.into()]); styles.set(TextNode::LINES, vec![DecoLine::Underline.into()]);
} }
Styled::new(node, styles) Styled::new(Template::Text(piece.into()), styles)
} }
impl Eval for MathNode { impl Eval for MathNode {
type Output = Node; type Output = Template;
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
let text = Node::Text(self.formula.trim().into()).monospaced(); let text = Template::Text(self.formula.trim().into()).monospaced();
Ok(if self.display { Ok(if self.display {
Node::Block(text.into_block()) Template::Block(text.into_block())
} else { } else {
text text
}) })
@ -361,10 +359,10 @@ impl Eval for MathNode {
} }
impl Eval for HeadingNode { impl Eval for HeadingNode {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
Ok(Node::block(library::HeadingNode { Ok(Template::block(library::HeadingNode {
child: self.body().eval(ctx)?.into_block(), child: self.body().eval(ctx)?.into_block(),
level: self.level(), level: self.level(),
})) }))
@ -372,10 +370,10 @@ impl Eval for HeadingNode {
} }
impl Eval for ListNode { impl Eval for ListNode {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
Ok(Node::block(library::ListNode { Ok(Template::block(library::ListNode {
child: self.body().eval(ctx)?.into_block(), child: self.body().eval(ctx)?.into_block(),
kind: library::Unordered, kind: library::Unordered,
})) }))
@ -383,10 +381,10 @@ impl Eval for ListNode {
} }
impl Eval for EnumNode { impl Eval for EnumNode {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
Ok(Node::block(library::ListNode { Ok(Template::block(library::ListNode {
child: self.body().eval(ctx)?.into_block(), child: self.body().eval(ctx)?.into_block(),
kind: library::Ordered(self.number()), kind: library::Ordered(self.number()),
})) }))
@ -402,7 +400,7 @@ impl Eval for Expr {
Self::Ident(v) => v.eval(ctx), Self::Ident(v) => v.eval(ctx),
Self::Array(v) => v.eval(ctx).map(Value::Array), Self::Array(v) => v.eval(ctx).map(Value::Array),
Self::Dict(v) => v.eval(ctx).map(Value::Dict), Self::Dict(v) => v.eval(ctx).map(Value::Dict),
Self::Template(v) => v.eval(ctx).map(Value::Node), Self::Template(v) => v.eval(ctx).map(Value::Template),
Self::Group(v) => v.eval(ctx), Self::Group(v) => v.eval(ctx),
Self::Block(v) => v.eval(ctx), Self::Block(v) => v.eval(ctx),
Self::Call(v) => v.eval(ctx), Self::Call(v) => v.eval(ctx),
@ -475,13 +473,13 @@ impl Eval for DictExpr {
} }
impl Eval for TemplateExpr { impl Eval for TemplateExpr {
type Output = Node; type Output = Template;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
ctx.scopes.enter(); ctx.scopes.enter();
let node = self.body().eval(ctx)?; let template = self.body().eval(ctx)?;
ctx.scopes.exit(); ctx.scopes.exit();
Ok(node) Ok(template)
} }
} }
@ -899,7 +897,7 @@ impl Eval for IncludeExpr {
let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?; let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?;
let file = ctx.import(&resolved, path.span())?; let file = ctx.import(&resolved, path.span())?;
let module = &ctx.modules[&file]; let module = &ctx.modules[&file];
Ok(Value::Node(module.node.clone())) Ok(Value::Template(module.template.clone()))
} }
} }

View File

@ -22,9 +22,9 @@ pub fn join(lhs: Value, rhs: Value) -> StrResult<Value> {
(Str(a), Str(b)) => Str(a + b), (Str(a), Str(b)) => Str(a + b),
(Array(a), Array(b)) => Array(a + b), (Array(a), Array(b)) => Array(a + b),
(Dict(a), Dict(b)) => Dict(a + b), (Dict(a), Dict(b)) => Dict(a + b),
(Node(a), Node(b)) => Node(a + b), (Template(a), Template(b)) => Template(a + b),
(Node(a), Str(b)) => Node(a + super::Node::Text(b)), (Template(a), Str(b)) => Template(a + super::Template::Text(b)),
(Str(a), Node(b)) => Node(super::Node::Text(a) + b), (Str(a), Template(b)) => Template(super::Template::Text(a) + b),
(a, b) => mismatch!("cannot join {} with {}", a, b), (a, b) => mismatch!("cannot join {} with {}", a, b),
}) })
} }
@ -85,11 +85,11 @@ pub fn add(lhs: Value, rhs: Value) -> StrResult<Value> {
(Array(a), Array(b)) => Array(a + b), (Array(a), Array(b)) => Array(a + b),
(Dict(a), Dict(b)) => Dict(a + b), (Dict(a), Dict(b)) => Dict(a + b),
(Node(a), None) => Node(a), (Template(a), None) => Template(a),
(None, Node(b)) => Node(b), (None, Template(b)) => Template(b),
(Node(a), Node(b)) => Node(a + b), (Template(a), Template(b)) => Template(a + b),
(Node(a), Str(b)) => Node(a + super::Node::Text(b)), (Template(a), Str(b)) => Template(a + super::Template::Text(b)),
(Str(a), Node(b)) => Node(super::Node::Text(a) + b), (Str(a), Template(b)) => Template(super::Template::Text(a) + b),
(a, b) => { (a, b) => {
if let (Dyn(a), Dyn(b)) = (&a, &b) { if let (Dyn(a), Dyn(b)) = (&a, &b) {
@ -178,8 +178,8 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> {
(Int(a), Str(b)) => Str(repeat_str(b, a)?), (Int(a), Str(b)) => Str(repeat_str(b, a)?),
(Array(a), Int(b)) => Array(a.repeat(b)?), (Array(a), Int(b)) => Array(a.repeat(b)?),
(Int(a), Array(b)) => Array(b.repeat(a)?), (Int(a), Array(b)) => Array(b.repeat(a)?),
(Node(a), Int(b)) => Node(a.repeat(b)?), (Template(a), Int(b)) => Template(a.repeat(b)?),
(Int(a), Node(b)) => Node(b.repeat(a)?), (Int(a), Template(b)) => Template(b.repeat(a)?),
(a, b) => mismatch!("cannot multiply {} with {}", a, b), (a, b) => mismatch!("cannot multiply {} with {}", a, b),
}) })
@ -296,7 +296,7 @@ pub fn equal(lhs: &Value, rhs: &Value) -> bool {
(Str(a), Str(b)) => a == b, (Str(a), Str(b)) => a == b,
(Array(a), Array(b)) => a == b, (Array(a), Array(b)) => a == b,
(Dict(a), Dict(b)) => a == b, (Dict(a), Dict(b)) => a == b,
(Node(a), Node(b)) => a == b, (Template(a), Template(b)) => a == b,
(Func(a), Func(b)) => a == b, (Func(a), Func(b)) => a == b,
(Dyn(a), Dyn(b)) => a == b, (Dyn(a), Dyn(b)) => a == b,

View File

@ -144,7 +144,7 @@ impl StyleMap {
} }
/// Whether two style maps are equal when filtered down to properties of the /// Whether two style maps are equal when filtered down to properties of the
/// node `T`. /// class `T`.
pub fn compatible<T: 'static>(&self, other: &Self) -> bool { pub fn compatible<T: 'static>(&self, other: &Self) -> bool {
let f = |entry: &&Entry| entry.is_of::<T>(); let f = |entry: &&Entry| entry.is_of::<T>();
self.0.iter().filter(f).count() == other.0.iter().filter(f).count() self.0.iter().filter(f).count() == other.0.iter().filter(f).count()
@ -242,10 +242,10 @@ impl<'a> StyleChain<'a> {
/// Barriers interact with [scoped](StyleMap::scoped) styles: A scoped style /// Barriers interact with [scoped](StyleMap::scoped) styles: A scoped style
/// can still be read through a single barrier (the one of the node it /// can still be read through a single barrier (the one of the node it
/// _should_ apply to), but a second barrier will make it invisible. /// _should_ apply to), but a second barrier will make it invisible.
pub fn barred<'b>(&'b self, node: TypeId) -> StyleChain<'b> { pub fn barred<'b>(&'b self, class: TypeId) -> StyleChain<'b> {
if self.needs_barrier(node) { if self.needs_barrier(class) {
StyleChain { StyleChain {
first: Link::Barrier(node), first: Link::Barrier(class),
outer: Some(self), outer: Some(self),
} }
} else { } else {
@ -297,18 +297,18 @@ impl<'a> StyleChain<'a> {
.and_then(|entry| entry.downcast::<P>()), .and_then(|entry| entry.downcast::<P>()),
depth, depth,
), ),
Link::Barrier(node) => (None, depth + (P::node_id() == node) as usize), Link::Barrier(class) => (None, depth + (P::class_id() == class) as usize),
} }
} }
fn needs_barrier(self, node: TypeId) -> bool { fn needs_barrier(self, class: TypeId) -> bool {
if let Link::Map(map) = self.first { if let Link::Map(map) = self.first {
if map.0.iter().any(|entry| entry.is_of_same(node)) { if map.0.iter().any(|entry| entry.is_of_same(class)) {
return true; return true;
} }
} }
self.outer.map_or(false, |outer| outer.needs_barrier(node)) self.outer.map_or(false, |outer| outer.needs_barrier(class))
} }
} }
@ -352,11 +352,11 @@ impl Entry {
} }
fn is_of<T: 'static>(&self) -> bool { fn is_of<T: 'static>(&self) -> bool {
self.p.node_id() == TypeId::of::<T>() self.p.class_id() == TypeId::of::<T>()
} }
fn is_of_same(&self, node: TypeId) -> bool { fn is_of_same(&self, class: TypeId) -> bool {
self.p.node_id() == node self.p.class_id() == class
} }
fn downcast<P: Property>(&self) -> Option<&P::Value> { fn downcast<P: Property>(&self) -> Option<&P::Value> {
@ -402,8 +402,8 @@ pub trait Property: Copy + Sync + Send + 'static {
/// Whether the property needs folding. /// Whether the property needs folding.
const FOLDABLE: bool = false; const FOLDABLE: bool = false;
/// The type id of the node this property belongs to. /// The type id of the class this property belongs to.
fn node_id() -> TypeId; fn class_id() -> TypeId;
/// The default value of the property. /// The default value of the property.
fn default() -> Self::Value; fn default() -> Self::Value;
@ -437,7 +437,7 @@ trait Bounds: Sync + Send + 'static {
fn dyn_fmt(&self, f: &mut Formatter) -> fmt::Result; fn dyn_fmt(&self, f: &mut Formatter) -> fmt::Result;
fn dyn_eq(&self, other: &Entry) -> bool; fn dyn_eq(&self, other: &Entry) -> bool;
fn hash64(&self) -> u64; fn hash64(&self) -> u64;
fn node_id(&self) -> TypeId; fn class_id(&self) -> TypeId;
fn style_id(&self) -> TypeId; fn style_id(&self) -> TypeId;
fn fold(&self, outer: &Entry) -> Entry; fn fold(&self, outer: &Entry) -> Entry;
} }
@ -467,8 +467,8 @@ impl<P: Property> Bounds for (P, P::Value) {
state.finish() state.finish()
} }
fn node_id(&self) -> TypeId { fn class_id(&self) -> TypeId {
P::node_id() P::class_id()
} }
fn style_id(&self) -> TypeId { fn style_id(&self) -> TypeId {

View File

@ -14,17 +14,17 @@ use crate::library::{
}; };
use crate::util::EcoString; use crate::util::EcoString;
/// A partial representation of a layout node. /// Composable representation of styled content.
/// ///
/// A node is a composable intermediate representation that can be converted /// This results from:
/// into a proper layout node by lifting it to a [block-level](PackedNode) or /// - anything written between square brackets in Typst
/// [root node](RootNode). /// - any class constructor
/// ///
/// When you write `[Hi] + [you]` in Typst, this type's [`Add`] implementation /// When you write `[Hi] + [you]` in Typst, this type's [`Add`] implementation
/// is invoked. There, multiple nodes are combined into a single /// is invoked. There, multiple templates are combined into a single
/// [`Sequence`](Self::Sequence) node. /// [`Sequence`](Self::Sequence) template.
#[derive(Debug, PartialEq, Clone, Hash)] #[derive(Debug, PartialEq, Clone, Hash)]
pub enum Node { pub enum Template {
/// A word space. /// A word space.
Space, Space,
/// A line break. /// A line break.
@ -62,13 +62,13 @@ pub enum Node {
Sequence(Vec<Styled<Self>>), Sequence(Vec<Styled<Self>>),
} }
impl Node { impl Template {
/// Create an empty node. /// Create an empty template.
pub fn new() -> Self { pub fn new() -> Self {
Self::Sequence(vec![]) Self::Sequence(vec![])
} }
/// Create an inline-level node. /// Create a template from an inline-level node.
pub fn inline<T>(node: T) -> Self pub fn inline<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + Sync + Send + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
@ -76,7 +76,7 @@ impl Node {
Self::Inline(node.pack()) Self::Inline(node.pack())
} }
/// Create a block-level node. /// Create a template from a block-level node.
pub fn block<T>(node: T) -> Self pub fn block<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + Sync + Send + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
@ -84,7 +84,7 @@ impl Node {
Self::Block(node.pack()) Self::Block(node.pack())
} }
/// Style this node with a single property. /// Style this template with a single property.
pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self { pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self {
if let Self::Sequence(vec) = &mut self { if let Self::Sequence(vec) = &mut self {
if let [styled] = vec.as_mut_slice() { if let [styled] = vec.as_mut_slice() {
@ -96,7 +96,7 @@ impl Node {
self.styled_with_map(StyleMap::with(key, value)) self.styled_with_map(StyleMap::with(key, value))
} }
/// Style this node with a full style map. /// Style this template with a full style map.
pub fn styled_with_map(mut self, styles: StyleMap) -> Self { pub fn styled_with_map(mut self, styles: StyleMap) -> Self {
if styles.is_empty() { if styles.is_empty() {
return self; return self;
@ -112,14 +112,14 @@ impl Node {
Self::Sequence(vec![Styled::new(self, styles)]) Self::Sequence(vec![Styled::new(self, styles)])
} }
/// Style this node in monospace. /// Style this template in monospace.
pub fn monospaced(self) -> Self { pub fn monospaced(self) -> Self {
self.styled(TextNode::MONOSPACE, true) self.styled(TextNode::MONOSPACE, true)
} }
/// Lift to a type-erased block-level node. /// Lift to a type-erased block-level template.
pub fn into_block(self) -> PackedNode { pub fn into_block(self) -> PackedNode {
if let Node::Block(packed) = self { if let Template::Block(packed) = self {
packed packed
} else { } else {
let mut packer = Packer::new(false); let mut packer = Packer::new(false);
@ -135,23 +135,22 @@ impl Node {
packer.into_root() packer.into_root()
} }
/// Repeat this node `n` times. /// Repeat this template `n` times.
pub fn repeat(&self, n: i64) -> StrResult<Self> { pub fn repeat(&self, n: i64) -> StrResult<Self> {
let count = usize::try_from(n) let count = usize::try_from(n)
.map_err(|_| format!("cannot repeat this template {} times", n))?; .map_err(|_| format!("cannot repeat this template {} times", n))?;
// TODO(style): Make more efficient.
Ok(Self::Sequence(vec![Styled::bare(self.clone()); count])) Ok(Self::Sequence(vec![Styled::bare(self.clone()); count]))
} }
} }
impl Default for Node { impl Default for Template {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl Add for Node { impl Add for Template {
type Output = Self; type Output = Self;
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
@ -175,19 +174,19 @@ impl Add for Node {
} }
} }
impl AddAssign for Node { impl AddAssign for Template {
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
*self = mem::take(self) + rhs; *self = mem::take(self) + rhs;
} }
} }
impl Sum for Node { impl Sum for Template {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
Self::Sequence(iter.map(|n| Styled::bare(n)).collect()) Self::Sequence(iter.map(|n| Styled::bare(n)).collect())
} }
} }
/// Packs a [`Node`] into a flow or root node. /// Packs a [`Template`] into a flow or root node.
struct Packer { struct Packer {
/// Whether this packer produces a root node. /// Whether this packer produces a root node.
top: bool, top: bool,
@ -200,7 +199,7 @@ struct Packer {
} }
impl Packer { impl Packer {
/// Start a new node-packing session. /// Start a new template-packing session.
fn new(top: bool) -> Self { fn new(top: bool) -> Self {
Self { Self {
top, top,
@ -222,28 +221,28 @@ impl Packer {
RootNode(self.pages) RootNode(self.pages)
} }
/// Consider a node with the given styles. /// Consider a template with the given styles.
fn walk(&mut self, node: Node, styles: StyleMap) { fn walk(&mut self, template: Template, styles: StyleMap) {
match node { match template {
Node::Space => { Template::Space => {
// A text space is "soft", meaning that it can be eaten up by // A text space is "soft", meaning that it can be eaten up by
// adjacent line breaks or explicit spacings. // adjacent line breaks or explicit spacings.
self.par.last.soft(Styled::new(ParChild::text(' '), styles), false); self.par.last.soft(Styled::new(ParChild::text(' '), styles), false);
} }
Node::Linebreak => { Template::Linebreak => {
// A line break eats up surrounding text spaces. // A line break eats up surrounding text spaces.
self.par.last.hard(); self.par.last.hard();
self.push_inline(Styled::new(ParChild::text('\n'), styles)); self.push_inline(Styled::new(ParChild::text('\n'), styles));
self.par.last.hard(); self.par.last.hard();
} }
Node::Parbreak => { Template::Parbreak => {
// An explicit paragraph break is styled according to the active // An explicit paragraph break is styled according to the active
// styles (`Some(_)`) whereas paragraph breaks forced by // styles (`Some(_)`) whereas paragraph breaks forced by
// incompatibility take their styles from the preceding // incompatibility take their styles from the preceding
// paragraph. // paragraph.
self.parbreak(Some(styles), true); self.parbreak(Some(styles), true);
} }
Node::Colbreak => { Template::Colbreak => {
// Explicit column breaks end the current paragraph and then // Explicit column breaks end the current paragraph and then
// discards the paragraph break. // discards the paragraph break.
self.parbreak(None, false); self.parbreak(None, false);
@ -251,24 +250,24 @@ impl Packer {
self.flow.children.push(Styled::new(FlowChild::Skip, styles)); self.flow.children.push(Styled::new(FlowChild::Skip, styles));
self.flow.last.hard(); self.flow.last.hard();
} }
Node::Pagebreak => { Template::Pagebreak => {
// We must set the flow styles after the page break such that an // We must set the flow styles after the page break such that an
// empty page created by two page breaks in a row has styles at // empty page created by two page breaks in a row has styles at
// all. // all.
self.pagebreak(); self.pagebreak();
self.flow.styles = styles; self.flow.styles = styles;
} }
Node::Text(text) => { Template::Text(text) => {
self.push_inline(Styled::new(ParChild::text(text), styles)); self.push_inline(Styled::new(ParChild::text(text), styles));
} }
Node::Spacing(SpecAxis::Horizontal, kind) => { Template::Spacing(SpecAxis::Horizontal, kind) => {
// Just like a line break, explicit horizontal spacing eats up // Just like a line break, explicit horizontal spacing eats up
// surrounding text spaces. // surrounding text spaces.
self.par.last.hard(); self.par.last.hard();
self.push_inline(Styled::new(ParChild::Spacing(kind), styles)); self.push_inline(Styled::new(ParChild::Spacing(kind), styles));
self.par.last.hard(); self.par.last.hard();
} }
Node::Spacing(SpecAxis::Vertical, kind) => { Template::Spacing(SpecAxis::Vertical, kind) => {
// Explicit vertical spacing ends the current paragraph and then // Explicit vertical spacing ends the current paragraph and then
// discards the paragraph break. // discards the paragraph break.
self.parbreak(None, false); self.parbreak(None, false);
@ -276,13 +275,13 @@ impl Packer {
self.flow.children.push(Styled::new(FlowChild::Spacing(kind), styles)); self.flow.children.push(Styled::new(FlowChild::Spacing(kind), styles));
self.flow.last.hard(); self.flow.last.hard();
} }
Node::Inline(inline) => { Template::Inline(inline) => {
self.push_inline(Styled::new(ParChild::Node(inline), styles)); self.push_inline(Styled::new(ParChild::Node(inline), styles));
} }
Node::Block(block) => { Template::Block(block) => {
self.push_block(Styled::new(block, styles)); self.push_block(Styled::new(block, styles));
} }
Node::Page(page) => { Template::Page(page) => {
if self.top { if self.top {
self.pagebreak(); self.pagebreak();
self.pages.push(Styled::new(page, styles)); self.pages.push(Styled::new(page, styles));
@ -290,12 +289,12 @@ impl Packer {
self.push_block(Styled::new(page.0, styles)); self.push_block(Styled::new(page.0, styles));
} }
} }
Node::Sequence(list) => { Template::Sequence(list) => {
// For a list of nodes, we apply the list's styles to each node // For a list of templates, we apply the list's styles to each
// individually. // templates individually.
for mut node in list { for Styled { item, mut map } in list {
node.map.apply(&styles); map.apply(&styles);
self.walk(node.item, node.map); self.walk(item, map);
} }
} }
} }
@ -303,7 +302,7 @@ impl Packer {
/// Insert an inline-level element into the current paragraph. /// Insert an inline-level element into the current paragraph.
fn push_inline(&mut self, child: Styled<ParChild>) { fn push_inline(&mut self, child: Styled<ParChild>) {
// The node must be both compatible with the current page and the // The child's map must be both compatible with the current page and the
// current paragraph. // current paragraph.
self.make_flow_compatible(&child.map); self.make_flow_compatible(&child.map);
self.make_par_compatible(&child.map); self.make_par_compatible(&child.map);
@ -458,28 +457,28 @@ impl<T> Default for Builder<T> {
} }
} }
/// The kind of node that was last added to a flow or paragraph. A small finite /// The kind of child that was last added to a flow or paragraph. A small finite
/// state machine used to coalesce spaces. /// state machine used to coalesce spaces.
/// ///
/// Soft nodes can only exist when surrounded by `Any` nodes. Not at the /// Soft children can only exist when surrounded by `Any` children. Not at the
/// start, end or next to hard nodes. This way, spaces at start and end of /// start, end or next to hard children. This way, spaces at start and end of
/// paragraphs and next to `#h(..)` goes away. /// paragraphs and next to `#h(..)` goes away.
enum Last<N> { enum Last<N> {
/// Start state, nothing there. /// Start state, nothing there.
None, None,
/// Text or a block node or something. /// Text or a block node or something.
Any, Any,
/// Hard nodes: Linebreaks and explicit spacing. /// Hard children: Linebreaks and explicit spacing.
Hard, Hard,
/// Soft nodes: Word spaces and paragraph breaks. These are saved here /// Soft children: Word spaces and paragraph breaks. These are saved here
/// temporarily and then applied once an `Any` node appears. The boolean /// temporarily and then applied once an `Any` child appears. The boolean
/// says whether this soft node is "important" and preferrable to other soft /// says whether this soft child is "important" and preferrable to other soft
/// nodes (that is the case for explicit paragraph breaks). /// nodes (that is the case for explicit paragraph breaks).
Soft(N, bool), Soft(N, bool),
} }
impl<N> Last<N> { impl<N> Last<N> {
/// Transition into the `Any` state and return a soft node to really add /// Transition into the `Any` state and return a soft child to really add
/// now if currently in `Soft` state. /// now if currently in `Soft` state.
fn any(&mut self) -> Option<N> { fn any(&mut self) -> Option<N> {
match mem::replace(self, Self::Any) { match mem::replace(self, Self::Any) {
@ -489,7 +488,7 @@ impl<N> Last<N> {
} }
/// Transition into the `Soft` state, but only if in `Any`. Otherwise, the /// Transition into the `Soft` state, but only if in `Any`. Otherwise, the
/// soft node is discarded. /// soft child is discarded.
fn soft(&mut self, soft: N, important: bool) { fn soft(&mut self, soft: N, important: bool) {
if matches!( if matches!(
(&self, important), (&self, important),
@ -500,7 +499,7 @@ impl<N> Last<N> {
} }
/// Transition into the `Hard` state, discarding a possibly existing soft /// Transition into the `Hard` state, discarding a possibly existing soft
/// node and preventing further soft nodes from being added. /// child and preventing further soft nodes from being added.
fn hard(&mut self) { fn hard(&mut self) {
*self = Self::Hard; *self = Self::Hard;
} }

View File

@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
use super::{ops, Args, Array, Class, Dict, Func, Node}; use super::{ops, Args, Array, Class, Dict, Func, Template};
use crate::diag::StrResult; use crate::diag::StrResult;
use crate::geom::{Angle, Color, Fractional, Length, Linear, Relative, RgbaColor}; use crate::geom::{Angle, Color, Fractional, Length, Linear, Relative, RgbaColor};
use crate::layout::Layout; use crate::layout::Layout;
@ -42,8 +42,8 @@ pub enum Value {
Array(Array), Array(Array),
/// A dictionary value: `(color: #f79143, pattern: dashed)`. /// A dictionary value: `(color: #f79143, pattern: dashed)`.
Dict(Dict), Dict(Dict),
/// A node value: `[*Hi* there]`. /// A template value: `[*Hi* there]`.
Node(Node), Template(Template),
/// An executable function. /// An executable function.
Func(Func), Func(Func),
/// Captured arguments to a function. /// Captured arguments to a function.
@ -55,20 +55,20 @@ pub enum Value {
} }
impl Value { impl Value {
/// Create an inline-level node value. /// Create a template value from an inline-level node.
pub fn inline<T>(node: T) -> Self pub fn inline<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + Sync + Send + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
{ {
Self::Node(Node::inline(node)) Self::Template(Template::inline(node))
} }
/// Create a block-level node value. /// Create a template value from a block-level node.
pub fn block<T>(node: T) -> Self pub fn block<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + Sync + Send + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
{ {
Self::Node(Node::block(node)) Self::Template(Template::block(node))
} }
/// The name of the stored value's type. /// The name of the stored value's type.
@ -88,7 +88,7 @@ impl Value {
Self::Str(_) => EcoString::TYPE_NAME, Self::Str(_) => EcoString::TYPE_NAME,
Self::Array(_) => Array::TYPE_NAME, Self::Array(_) => Array::TYPE_NAME,
Self::Dict(_) => Dict::TYPE_NAME, Self::Dict(_) => Dict::TYPE_NAME,
Self::Node(_) => Node::TYPE_NAME, Self::Template(_) => Template::TYPE_NAME,
Self::Func(_) => Func::TYPE_NAME, Self::Func(_) => Func::TYPE_NAME,
Self::Args(_) => Args::TYPE_NAME, Self::Args(_) => Args::TYPE_NAME,
Self::Class(_) => Class::TYPE_NAME, Self::Class(_) => Class::TYPE_NAME,
@ -115,16 +115,16 @@ impl Value {
} }
/// Return the display representation of the value. /// Return the display representation of the value.
pub fn show(self) -> Node { pub fn show(self) -> Template {
match self { match self {
Value::None => Node::new(), Value::None => Template::new(),
Value::Int(v) => Node::Text(format_eco!("{}", v)), Value::Int(v) => Template::Text(format_eco!("{}", v)),
Value::Float(v) => Node::Text(format_eco!("{}", v)), Value::Float(v) => Template::Text(format_eco!("{}", v)),
Value::Str(v) => Node::Text(v), Value::Str(v) => Template::Text(v),
Value::Node(v) => v, Value::Template(v) => v,
// For values which can't be shown "naturally", we print the // For values which can't be shown "naturally", we print the
// representation in monospace. // representation in monospace.
v => Node::Text(v.repr()).monospaced(), v => Template::Text(v.repr()).monospaced(),
} }
} }
} }
@ -152,7 +152,7 @@ impl Debug for Value {
Self::Str(v) => Debug::fmt(v, f), Self::Str(v) => Debug::fmt(v, f),
Self::Array(v) => Debug::fmt(v, f), Self::Array(v) => Debug::fmt(v, f),
Self::Dict(v) => Debug::fmt(v, f), Self::Dict(v) => Debug::fmt(v, f),
Self::Node(_) => f.pad("<template>"), Self::Template(_) => f.pad("<template>"),
Self::Func(v) => Debug::fmt(v, f), Self::Func(v) => Debug::fmt(v, f),
Self::Args(v) => Debug::fmt(v, f), Self::Args(v) => Debug::fmt(v, f),
Self::Class(v) => Debug::fmt(v, f), Self::Class(v) => Debug::fmt(v, f),
@ -400,7 +400,7 @@ primitive! { Color: "color", Color }
primitive! { EcoString: "string", Str } primitive! { EcoString: "string", Str }
primitive! { Array: "array", Array } primitive! { Array: "array", Array }
primitive! { Dict: "dictionary", Dict } primitive! { Dict: "dictionary", Dict }
primitive! { Node: "template", Node } primitive! { Template: "template", Template }
primitive! { Func: "function", Func, Class(v) => v.constructor() } primitive! { Func: "function", Func, Class(v) => v.constructor() }
primitive! { Args: "arguments", Args } primitive! { Args: "arguments", Args }
primitive! { Class: "class", Class } primitive! { Class: "class", Class }

View File

@ -307,7 +307,7 @@ where
} }
} }
/// A node that sizes its child. /// Fix the size of a node.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct SizedNode { pub struct SizedNode {
/// How to size the node horizontally and vertically. /// How to size the node horizontally and vertically.

View File

@ -7,10 +7,11 @@
//! is provided in the [AST] module. //! is provided in the [AST] module.
//! - **Evaluation:** The next step is to [evaluate] the markup. This produces a //! - **Evaluation:** The next step is to [evaluate] the markup. This produces a
//! [module], consisting of a scope of values that were exported by the code //! [module], consisting of a scope of values that were exported by the code
//! and a [node] with the contents of the module. This node can be converted //! and a [template] with the contents of the module. This node can be
//! into a [layout tree], a hierarchical, styled representation of the //! converted into a [layout tree], a hierarchical, styled representation of
//! document. The nodes of this tree are well structured and order-independent //! the document. The nodes of this tree are well structured and
//! and thus much better suited for layouting than the raw markup. //! order-independent and thus much better suited for layouting than the raw
//! markup.
//! - **Layouting:** Next, the tree is [layouted] into a portable version of the //! - **Layouting:** Next, the tree is [layouted] into a portable version of the
//! typeset document. The output of this is a collection of [`Frame`]s (one //! typeset document. The output of this is a collection of [`Frame`]s (one
//! per page), ready for exporting. This step is supported by an incremental //! per page), ready for exporting. This step is supported by an incremental
@ -24,7 +25,7 @@
//! [AST]: syntax::ast //! [AST]: syntax::ast
//! [evaluate]: Context::evaluate //! [evaluate]: Context::evaluate
//! [module]: eval::Module //! [module]: eval::Module
//! [node]: eval::Node //! [template]: eval::Template
//! [layout tree]: layout::RootNode //! [layout tree]: layout::RootNode
//! [layouted]: layout::RootNode::layout //! [layouted]: layout::RootNode::layout
//! [cache]: layout::LayoutCache //! [cache]: layout::LayoutCache
@ -110,13 +111,13 @@ impl Context {
/// Evaluate a source file and return the resulting module. /// Evaluate a source file and return the resulting module.
/// ///
/// Returns either a module containing a scope with top-level bindings and a /// Returns either a module containing a scope with top-level bindings and a
/// layoutable node or diagnostics in the form of a vector of error message /// layoutable template or diagnostics in the form of a vector of error
/// with file and span information. /// message with file and span information.
pub fn evaluate(&mut self, id: SourceId) -> TypResult<Module> { pub fn evaluate(&mut self, id: SourceId) -> TypResult<Module> {
let markup = self.sources.get(id).ast()?; let markup = self.sources.get(id).ast()?;
let mut ctx = EvalContext::new(self, id); let mut ctx = EvalContext::new(self, id);
let node = markup.eval(&mut ctx)?; let template = markup.eval(&mut ctx)?;
Ok(Module { scope: ctx.scopes.top, node }) Ok(Module { scope: ctx.scopes.top, template })
} }
/// Typeset a source file into a collection of layouted frames. /// Typeset a source file into a collection of layouted frames.

View File

@ -14,10 +14,10 @@ pub struct AlignNode {
#[class] #[class]
impl AlignNode { impl AlignNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let aligns: Spec<_> = args.find().unwrap_or_default(); let aligns: Spec<_> = args.find().unwrap_or_default();
let body: PackedNode = args.expect("body")?; let body: PackedNode = args.expect("body")?;
Ok(Node::block(body.aligned(aligns))) Ok(Template::block(body.aligned(aligns)))
} }
} }

View File

@ -3,7 +3,7 @@
use super::prelude::*; use super::prelude::*;
use super::ParNode; use super::ParNode;
/// A node that separates a region into multiple equally sized columns. /// Separate a region into multiple equally sized columns.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct ColumnsNode { pub struct ColumnsNode {
/// How many columns there should be. /// How many columns there should be.
@ -18,8 +18,8 @@ impl ColumnsNode {
/// The size of the gutter space between each column. /// The size of the gutter space between each column.
pub const GUTTER: Linear = Relative::new(0.04).into(); pub const GUTTER: Linear = Relative::new(0.04).into();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::block(Self { Ok(Template::block(Self {
columns: args.expect("column count")?, columns: args.expect("column count")?,
child: args.expect("body")?, child: args.expect("body")?,
})) }))
@ -116,7 +116,7 @@ pub struct ColbreakNode;
#[class] #[class]
impl ColbreakNode { impl ColbreakNode {
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
Ok(Node::Colbreak) Ok(Template::Colbreak)
} }
} }

View File

@ -7,11 +7,11 @@ pub struct BoxNode;
#[class] #[class]
impl BoxNode { impl BoxNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let width = args.named("width")?; let width = args.named("width")?;
let height = args.named("height")?; let height = args.named("height")?;
let body: PackedNode = args.find().unwrap_or_default(); let body: PackedNode = args.find().unwrap_or_default();
Ok(Node::inline(body.sized(Spec::new(width, height)))) Ok(Template::inline(body.sized(Spec::new(width, height))))
} }
} }
@ -20,7 +20,7 @@ pub struct BlockNode;
#[class] #[class]
impl BlockNode { impl BlockNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::Block(args.find().unwrap_or_default())) Ok(Template::Block(args.find().unwrap_or_default()))
} }
} }

View File

@ -8,7 +8,7 @@ pub struct DecoNode<L: LineKind>(pub L);
#[class] #[class]
impl<L: LineKind> DecoNode<L> { impl<L: LineKind> DecoNode<L> {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let deco = Decoration { let deco = Decoration {
line: L::LINE, line: L::LINE,
stroke: args.named("stroke")?.or_else(|| args.find()), stroke: args.named("stroke")?.or_else(|| args.find()),
@ -17,7 +17,7 @@ impl<L: LineKind> DecoNode<L> {
extent: args.named("extent")?.unwrap_or_default(), extent: args.named("extent")?.unwrap_or_default(),
evade: args.named("evade")?.unwrap_or(true), evade: args.named("evade")?.unwrap_or(true),
}; };
Ok(args.expect::<Node>("body")?.styled(TextNode::LINES, vec![deco])) Ok(args.expect::<Template>("body")?.styled(TextNode::LINES, vec![deco]))
} }
} }

View File

@ -48,7 +48,7 @@ impl Debug for FlowChild {
match self { match self {
Self::Break => f.pad("Break"), Self::Break => f.pad("Break"),
Self::Skip => f.pad("Skip"), Self::Skip => f.pad("Skip"),
Self::Spacing(node) => node.fmt(f), Self::Spacing(kind) => kind.fmt(f),
Self::Node(node) => node.fmt(f), Self::Node(node) => node.fmt(f),
} }
} }
@ -56,7 +56,7 @@ impl Debug for FlowChild {
/// Performs flow layout. /// Performs flow layout.
struct FlowLayouter<'a> { struct FlowLayouter<'a> {
/// The flow node to layout. /// The children of the flow.
children: &'a [Styled<FlowChild>], children: &'a [Styled<FlowChild>],
/// The regions to layout children into. /// The regions to layout children into.
regions: Regions, regions: Regions,

View File

@ -2,7 +2,7 @@
use super::prelude::*; use super::prelude::*;
/// A node that arranges its children in a grid. /// Arrange nodes in a grid.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct GridNode { pub struct GridNode {
/// Defines sizing for content rows and columns. /// Defines sizing for content rows and columns.
@ -15,13 +15,13 @@ pub struct GridNode {
#[class] #[class]
impl GridNode { impl GridNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let columns = args.named("columns")?.unwrap_or_default(); let columns = args.named("columns")?.unwrap_or_default();
let rows = args.named("rows")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default();
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default(); let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
let column_gutter = args.named("column-gutter")?; let column_gutter = args.named("column-gutter")?;
let row_gutter = args.named("row-gutter")?; let row_gutter = args.named("row-gutter")?;
Ok(Node::block(Self { Ok(Template::block(Self {
tracks: Spec::new(columns, rows), tracks: Spec::new(columns, rows),
gutter: Spec::new( gutter: Spec::new(
column_gutter.unwrap_or_else(|| base_gutter.clone()), column_gutter.unwrap_or_else(|| base_gutter.clone()),

View File

@ -28,8 +28,8 @@ impl HeadingNode {
/// The extra padding below the heading. /// The extra padding below the heading.
pub const BELOW: Length = Length::zero(); pub const BELOW: Length = Length::zero();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::block(Self { Ok(Template::block(Self {
child: args.expect("body")?, child: args.expect("body")?,
level: args.named("level")?.unwrap_or(1), level: args.named("level")?.unwrap_or(1),
})) }))

View File

@ -2,14 +2,14 @@
use super::prelude::*; use super::prelude::*;
/// A node that hides its child without affecting layout. /// Hide a node without affecting layout.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct HideNode(pub PackedNode); pub struct HideNode(pub PackedNode);
#[class] #[class]
impl HideNode { impl HideNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::inline(Self(args.expect("body")?))) Ok(Template::inline(Self(args.expect("body")?)))
} }
} }

View File

@ -5,7 +5,7 @@ use super::TextNode;
use crate::diag::Error; use crate::diag::Error;
use crate::image::ImageId; use crate::image::ImageId;
/// An image node. /// Show a raster or vector graphic.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct ImageNode(pub ImageId); pub struct ImageNode(pub ImageId);
@ -14,7 +14,7 @@ impl ImageNode {
/// How the image should adjust itself to a given area. /// How the image should adjust itself to a given area.
pub const FIT: ImageFit = ImageFit::Cover; pub const FIT: ImageFit = ImageFit::Cover;
fn construct(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let path = args.expect::<Spanned<EcoString>>("path to image file")?; let path = args.expect::<Spanned<EcoString>>("path to image file")?;
let full = ctx.make_path(&path.v); let full = ctx.make_path(&path.v);
let id = ctx.images.load(&full).map_err(|err| { let id = ctx.images.load(&full).map_err(|err| {
@ -27,7 +27,7 @@ impl ImageNode {
let width = args.named("width")?; let width = args.named("width")?;
let height = args.named("height")?; let height = args.named("height")?;
Ok(Node::inline( Ok(Template::inline(
ImageNode(id).pack().sized(Spec::new(width, height)), ImageNode(id).pack().sized(Spec::new(width, height)),
)) ))
} }

View File

@ -9,7 +9,7 @@ pub struct LinkNode;
#[class] #[class]
impl LinkNode { impl LinkNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let url = args.expect::<EcoString>("url")?; let url = args.expect::<EcoString>("url")?;
let body = args.find().unwrap_or_else(|| { let body = args.find().unwrap_or_else(|| {
let mut text = url.as_str(); let mut text = url.as_str();
@ -17,7 +17,7 @@ impl LinkNode {
text = text.trim_start_matches(prefix); text = text.trim_start_matches(prefix);
} }
let shorter = text.len() < url.len(); let shorter = text.len() < url.len();
Node::Text(if shorter { text.into() } else { url.clone() }) Template::Text(if shorter { text.into() } else { url.clone() })
}); });
Ok(body.styled(TextNode::LINK, Some(url))) Ok(body.styled(TextNode::LINK, Some(url)))

View File

@ -19,10 +19,10 @@ impl<L: ListKind> ListNode<L> {
/// The space between the label and the body of each item. /// The space between the label and the body of each item.
pub const BODY_INDENT: Linear = Relative::new(0.5).into(); pub const BODY_INDENT: Linear = Relative::new(0.5).into();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(args Ok(args
.all() .all()
.map(|child: PackedNode| Node::block(Self { kind: L::default(), child })) .map(|child: PackedNode| Template::block(Self { kind: L::default(), child }))
.sum()) .sum())
} }
@ -54,7 +54,7 @@ impl<L: ListKind> Layout for ListNode<L> {
gutter: Spec::default(), gutter: Spec::default(),
children: vec![ children: vec![
PackedNode::default(), PackedNode::default(),
Node::Text(self.kind.label()).into_block(), Template::Text(self.kind.label()).into_block(),
PackedNode::default(), PackedNode::default(),
self.child.clone(), self.child.clone(),
], ],

View File

@ -68,7 +68,7 @@ prelude! {
pub use crate::diag::{At, TypResult}; pub use crate::diag::{At, TypResult};
pub use crate::eval::{ pub use crate::eval::{
Args, Construct, EvalContext, Node, Property, Scope, Set, Smart, StyleChain, Args, Construct, EvalContext, Template, Property, Scope, Set, Smart, StyleChain,
StyleMap, Styled, Value, StyleMap, Styled, Value,
}; };
pub use crate::frame::*; pub use crate::frame::*;
@ -227,6 +227,6 @@ castable! {
castable! { castable! {
PackedNode, PackedNode,
Expected: "node", Expected: "template",
Value::Node(node) => node.into_block(), Value::Template(template) => template.into_block(),
} }

View File

@ -2,7 +2,7 @@
use super::prelude::*; use super::prelude::*;
/// Pad content at the sides. /// Pad a node at the sides.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct PadNode { pub struct PadNode {
/// The amount of padding. /// The amount of padding.
@ -13,7 +13,7 @@ pub struct PadNode {
#[class] #[class]
impl PadNode { impl PadNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let all = args.find(); let all = args.find();
let left = args.named("left")?; let left = args.named("left")?;
let top = args.named("top")?; let top = args.named("top")?;
@ -27,7 +27,7 @@ impl PadNode {
bottom.or(all).unwrap_or_default(), bottom.or(all).unwrap_or_default(),
); );
Ok(Node::block(body.padded(padding))) Ok(Template::block(body.padded(padding)))
} }
} }

View File

@ -33,8 +33,8 @@ impl PageNode {
/// How many columns the page has. /// How many columns the page has.
pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap(); pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::Page(Self(args.expect("body")?))) Ok(Template::Page(Self(args.expect("body")?)))
} }
fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> { fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
@ -130,8 +130,8 @@ pub struct PagebreakNode;
#[class] #[class]
impl PagebreakNode { impl PagebreakNode {
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
Ok(Node::Pagebreak) Ok(Template::Pagebreak)
} }
} }

View File

@ -11,7 +11,7 @@ use super::prelude::*;
use super::{shape, ShapedText, SpacingKind, TextNode}; use super::{shape, ShapedText, SpacingKind, TextNode};
use crate::util::{ArcExt, EcoString, RangeExt, SliceExt}; use crate::util::{ArcExt, EcoString, RangeExt, SliceExt};
/// A node that arranges its children into a paragraph. /// Arrange text, spacing and inline nodes into a paragraph.
#[derive(Hash)] #[derive(Hash)]
pub struct ParNode(pub Vec<Styled<ParChild>>); pub struct ParNode(pub Vec<Styled<ParChild>>);
@ -26,12 +26,12 @@ impl ParNode {
/// The spacing between paragraphs (dependent on scaled font size). /// The spacing between paragraphs (dependent on scaled font size).
pub const SPACING: Linear = Relative::new(1.2).into(); pub const SPACING: Linear = Relative::new(1.2).into();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
// The paragraph constructor is special: It doesn't create a paragraph // The paragraph constructor is special: It doesn't create a paragraph
// since that happens automatically through markup. Instead, it just // since that happens automatically through markup. Instead, it just
// lifts the passed body to the block level so that it won't merge with // lifts the passed body to the block level so that it won't merge with
// adjacent stuff and it styles the contained paragraphs. // adjacent stuff and it styles the contained paragraphs.
Ok(Node::Block(args.expect("body")?)) Ok(Template::Block(args.expect("body")?))
} }
fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> { fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
@ -118,7 +118,7 @@ impl ParNode {
fn strings(&self) -> impl Iterator<Item = &str> { fn strings(&self) -> impl Iterator<Item = &str> {
self.0.iter().map(|styled| match &styled.item { self.0.iter().map(|styled| match &styled.item {
ParChild::Spacing(_) => " ", ParChild::Spacing(_) => " ",
ParChild::Text(node) => &node.0, ParChild::Text(text) => &text.0,
ParChild::Node(_) => "\u{FFFC}", ParChild::Node(_) => "\u{FFFC}",
}) })
} }
@ -152,8 +152,8 @@ impl ParChild {
impl Debug for ParChild { impl Debug for ParChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::Spacing(node) => node.fmt(f), Self::Spacing(kind) => kind.fmt(f),
Self::Text(node) => node.fmt(f), Self::Text(text) => text.fmt(f),
Self::Node(node) => node.fmt(f), Self::Node(node) => node.fmt(f),
} }
} }
@ -164,8 +164,8 @@ pub struct ParbreakNode;
#[class] #[class]
impl ParbreakNode { impl ParbreakNode {
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
Ok(Node::Parbreak) Ok(Template::Parbreak)
} }
} }
@ -174,8 +174,8 @@ pub struct LinebreakNode;
#[class] #[class]
impl LinebreakNode { impl LinebreakNode {
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
Ok(Node::Linebreak) Ok(Template::Linebreak)
} }
} }

View File

@ -3,18 +3,18 @@
use super::prelude::*; use super::prelude::*;
use super::AlignNode; use super::AlignNode;
/// Place content at an absolute position. /// Place a node at an absolute position.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct PlaceNode(pub PackedNode); pub struct PlaceNode(pub PackedNode);
#[class] #[class]
impl PlaceNode { impl PlaceNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let aligns = args.find().unwrap_or(Spec::with_x(Some(Align::Left))); let aligns = args.find().unwrap_or(Spec::with_x(Some(Align::Left)));
let tx = args.named("dx")?.unwrap_or_default(); let tx = args.named("dx")?.unwrap_or_default();
let ty = args.named("dy")?.unwrap_or_default(); let ty = args.named("dy")?.unwrap_or_default();
let body: PackedNode = args.expect("body")?; let body: PackedNode = args.expect("body")?;
Ok(Node::block(Self( Ok(Template::block(Self(
body.moved(Point::new(tx, ty)).aligned(aligns), body.moved(Point::new(tx, ty)).aligned(aligns),
))) )))
} }

View File

@ -5,7 +5,7 @@ use std::f64::consts::SQRT_2;
use super::prelude::*; use super::prelude::*;
use super::TextNode; use super::TextNode;
/// Places its child into a sizable and fillable shape. /// Place a node into a sizable and fillable shape.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct ShapeNode<S: ShapeKind> { pub struct ShapeNode<S: ShapeKind> {
/// Which shape to place the child into. /// Which shape to place the child into.
@ -25,7 +25,7 @@ impl<S: ShapeKind> ShapeNode<S> {
/// How much to pad the shape's content. /// How much to pad the shape's content.
pub const PADDING: Linear = Linear::zero(); pub const PADDING: Linear = Linear::zero();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let size = if !S::ROUND && S::QUADRATIC { let size = if !S::ROUND && S::QUADRATIC {
args.named::<Length>("size")?.map(Linear::from) args.named::<Length>("size")?.map(Linear::from)
} else if S::ROUND && S::QUADRATIC { } else if S::ROUND && S::QUADRATIC {
@ -44,7 +44,7 @@ impl<S: ShapeKind> ShapeNode<S> {
size => size, size => size,
}; };
Ok(Node::inline( Ok(Template::inline(
ShapeNode { kind: S::default(), child: args.find() } ShapeNode { kind: S::default(), child: args.find() }
.pack() .pack()
.sized(Spec::new(width, height)), .sized(Spec::new(width, height)),

View File

@ -7,8 +7,8 @@ pub struct HNode;
#[class] #[class]
impl HNode { impl HNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::Spacing(SpecAxis::Horizontal, args.expect("spacing")?)) Ok(Template::Spacing(SpecAxis::Horizontal, args.expect("spacing")?))
} }
} }
@ -17,8 +17,8 @@ pub struct VNode;
#[class] #[class]
impl VNode { impl VNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::Spacing(SpecAxis::Vertical, args.expect("spacing")?)) Ok(Template::Spacing(SpecAxis::Vertical, args.expect("spacing")?))
} }
} }

View File

@ -3,7 +3,7 @@
use super::prelude::*; use super::prelude::*;
use super::{AlignNode, SpacingKind}; use super::{AlignNode, SpacingKind};
/// Stack children along an axis. /// Arrange nodes and spacing along an axis.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct StackNode { pub struct StackNode {
/// The stacking direction. /// The stacking direction.
@ -16,8 +16,8 @@ pub struct StackNode {
#[class] #[class]
impl StackNode { impl StackNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::block(Self { Ok(Template::block(Self {
dir: args.named("dir")?.unwrap_or(Dir::TTB), dir: args.named("dir")?.unwrap_or(Dir::TTB),
spacing: args.named("spacing")?, spacing: args.named("spacing")?,
children: args.all().collect(), children: args.all().collect(),
@ -48,7 +48,7 @@ pub enum StackChild {
impl Debug for StackChild { impl Debug for StackChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::Spacing(node) => node.fmt(f), Self::Spacing(kind) => kind.fmt(f),
Self::Node(node) => node.fmt(f), Self::Node(node) => node.fmt(f),
} }
} }
@ -61,12 +61,12 @@ castable! {
Value::Relative(v) => Self::Spacing(SpacingKind::Linear(v.into())), Value::Relative(v) => Self::Spacing(SpacingKind::Linear(v.into())),
Value::Linear(v) => Self::Spacing(SpacingKind::Linear(v)), Value::Linear(v) => Self::Spacing(SpacingKind::Linear(v)),
Value::Fractional(v) => Self::Spacing(SpacingKind::Fractional(v)), Value::Fractional(v) => Self::Spacing(SpacingKind::Fractional(v)),
Value::Node(v) => Self::Node(v.into_block()), Value::Template(v) => Self::Node(v.into_block()),
} }
/// Performs stack layout. /// Performs stack layout.
struct StackLayouter<'a> { struct StackLayouter<'a> {
/// The flow node to layout. /// The children of the stack.
children: &'a [StackChild], children: &'a [StackChild],
/// The stacking direction. /// The stacking direction.
dir: Dir, dir: Dir,
@ -99,7 +99,7 @@ enum StackItem {
Absolute(Length), Absolute(Length),
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fractional), Fractional(Fractional),
/// A layouted child node. /// A frame for a layouted child node.
Frame(Arc<Frame>, Align), Frame(Arc<Frame>, Align),
} }

View File

@ -27,13 +27,13 @@ impl TableNode {
/// How much to pad the cells's content. /// How much to pad the cells's content.
pub const PADDING: Linear = Length::pt(5.0).into(); pub const PADDING: Linear = Length::pt(5.0).into();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
let columns = args.named("columns")?.unwrap_or_default(); let columns = args.named("columns")?.unwrap_or_default();
let rows = args.named("rows")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default();
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default(); let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
let column_gutter = args.named("column-gutter")?; let column_gutter = args.named("column-gutter")?;
let row_gutter = args.named("row-gutter")?; let row_gutter = args.named("row-gutter")?;
Ok(Node::block(Self { Ok(Template::block(Self {
tracks: Spec::new(columns, rows), tracks: Spec::new(columns, rows),
gutter: Spec::new( gutter: Spec::new(
column_gutter.unwrap_or_else(|| base_gutter.clone()), column_gutter.unwrap_or_else(|| base_gutter.clone()),

View File

@ -95,7 +95,7 @@ impl TextNode {
/// Raw OpenType features to apply. /// Raw OpenType features to apply.
pub const FEATURES: Vec<(Tag, u32)> = vec![]; pub const FEATURES: Vec<(Tag, u32)> = vec![];
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
// The text constructor is special: It doesn't create a text node. // The text constructor is special: It doesn't create a text node.
// Instead, it leaves the passed argument structurally unchanged, but // Instead, it leaves the passed argument structurally unchanged, but
// styles all text in it. // styles all text in it.
@ -156,8 +156,8 @@ pub struct StrongNode;
#[class] #[class]
impl StrongNode { impl StrongNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(args.expect::<Node>("body")?.styled(TextNode::STRONG, true)) Ok(args.expect::<Template>("body")?.styled(TextNode::STRONG, true))
} }
} }
@ -166,8 +166,8 @@ pub struct EmphNode;
#[class] #[class]
impl EmphNode { impl EmphNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(args.expect::<Node>("body")?.styled(TextNode::EMPH, true)) Ok(args.expect::<Template>("body")?.styled(TextNode::EMPH, true))
} }
} }

View File

@ -3,7 +3,7 @@
use super::prelude::*; use super::prelude::*;
use crate::geom::Transform; use crate::geom::Transform;
/// A node that transforms its child without affecting layout. /// Transform a node without affecting layout.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct TransformNode<T: TransformKind> { pub struct TransformNode<T: TransformKind> {
/// Transformation to apply to the contents. /// Transformation to apply to the contents.
@ -17,8 +17,8 @@ impl<T: TransformKind> TransformNode<T> {
/// The origin of the transformation. /// The origin of the transformation.
pub const ORIGIN: Spec<Option<Align>> = Spec::default(); pub const ORIGIN: Spec<Option<Align>> = Spec::default();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
Ok(Node::inline(Self { Ok(Template::inline(Self {
kind: T::construct(args)?, kind: T::construct(args)?,
child: args.expect("body")?, child: args.expect("body")?,
})) }))