diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-19 22:28:49 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-19 22:39:19 +0100 |
| commit | ab43bd802eafe33977a91893907e67553e099569 (patch) | |
| tree | af4dead92b143348f52e2e8f869df3f7dfd7322a /library/src | |
| parent | d6aaae0cea1e79eecd85dc94ab85b9ad8eff48e8 (diff) | |
Renaming and refactoring
Diffstat (limited to 'library/src')
64 files changed, 1196 insertions, 1252 deletions
diff --git a/library/src/compute/construct.rs b/library/src/compute/construct.rs index 4d6068a1..a30faf2e 100644 --- a/library/src/compute/construct.rs +++ b/library/src/compute/construct.rs @@ -1,7 +1,6 @@ use std::num::NonZeroI64; use std::str::FromStr; -use ecow::EcoVec; use typst::eval::Regex; use crate::prelude::*; @@ -173,12 +172,12 @@ cast_from_value! { Component, v: i64 => match v { 0 ..= 255 => Self(v as u8), - _ => Err("must be between 0 and 255")?, + _ => Err("number must be between 0 and 255")?, }, v: Ratio => if (0.0 ..= 1.0).contains(&v.get()) { Self((v.get() * 255.0).round() as u8) } else { - Err("must be between 0% and 100%")? + Err("ratio must be between 0% and 100%")? }, } @@ -220,7 +219,7 @@ cast_from_value! { v: Ratio => if (0.0 ..= 1.0).contains(&v.get()) { Self((v.get() * 255.0).round() as u8) } else { - Err("must be between 0% and 100%")? + Err("ratio must be between 0% and 100%")? }, } @@ -258,14 +257,14 @@ pub fn symbol( #[variadic] variants: Vec<Spanned<Variant>>, ) -> Value { - let mut list = EcoVec::new(); + let mut list = Vec::new(); for Spanned { v, span } in variants { if list.iter().any(|(prev, _)| &v.0 == prev) { bail!(span, "duplicate variant"); } list.push((v.0, v.1)); } - Value::Symbol(Symbol::runtime(list)) + Value::Symbol(Symbol::runtime(list.into_boxed_slice())) } /// A value that can be cast to a symbol. diff --git a/library/src/compute/foundations.rs b/library/src/compute/foundations.rs index 8b148c85..d5397e60 100644 --- a/library/src/compute/foundations.rs +++ b/library/src/compute/foundations.rs @@ -134,5 +134,5 @@ pub fn eval( source: Spanned<String>, ) -> Value { let Spanned { v: text, span } = source; - typst::eval::eval_code_str(vm.world(), &text, span)? + typst::eval::eval_string(vm.world(), &text, span)? } diff --git a/library/src/layout/align.rs b/library/src/layout/align.rs index 2a3998bf..c2f8262e 100644 --- a/library/src/layout/align.rs +++ b/library/src/layout/align.rs @@ -14,8 +14,8 @@ use crate::prelude::*; /// /// Display: Align /// Category: layout -#[node(Show)] -pub struct AlignNode { +#[element(Show)] +pub struct AlignElem { /// The alignment along both axes. /// /// Possible values for horizontal alignments are: @@ -57,7 +57,7 @@ pub struct AlignNode { pub body: Content, } -impl Show for AlignNode { +impl Show for AlignElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { Ok(self .body() diff --git a/library/src/layout/columns.rs b/library/src/layout/columns.rs index 7704e9c4..3a1b012a 100644 --- a/library/src/layout/columns.rs +++ b/library/src/layout/columns.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; /// Separate a region into multiple equally sized columns. /// @@ -32,8 +32,8 @@ use crate::text::TextNode; /// /// Display: Columns /// Category: layout -#[node(Layout)] -pub struct ColumnsNode { +#[element(Layout)] +pub struct ColumnsElem { /// The number of columns. #[positional] #[default(NonZeroUsize::new(2).unwrap())] @@ -49,7 +49,7 @@ pub struct ColumnsNode { pub body: Content, } -impl Layout for ColumnsNode { +impl Layout for ColumnsElem { fn layout( &self, vt: &mut Vt, @@ -88,7 +88,7 @@ impl Layout for ColumnsNode { let mut frames = body.layout(vt, styles, pod)?.into_iter(); let mut finished = vec![]; - let dir = TextNode::dir_in(styles); + let dir = TextElem::dir_in(styles); let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize; // Stitch together the columns for each region. @@ -151,15 +151,15 @@ impl Layout for ColumnsNode { /// /// Display: Column Break /// Category: layout -#[node(Behave)] -pub struct ColbreakNode { +#[element(Behave)] +pub struct ColbreakElem { /// If `{true}`, the column break is skipped if the current column is /// already empty. #[default(false)] pub weak: bool, } -impl Behave for ColbreakNode { +impl Behave for ColbreakElem { fn behaviour(&self) -> Behaviour { if self.weak(StyleChain::default()) { Behaviour::Weak(1) diff --git a/library/src/layout/container.rs b/library/src/layout/container.rs index bdc147c3..ef7def7a 100644 --- a/library/src/layout/container.rs +++ b/library/src/layout/container.rs @@ -1,4 +1,4 @@ -use super::VNode; +use super::VElem; use crate::layout::Spacing; use crate::prelude::*; @@ -21,8 +21,8 @@ use crate::prelude::*; /// /// Display: Box /// Category: layout -#[node(Layout)] -pub struct BoxNode { +#[element(Layout)] +pub struct BoxElem { /// The width of the box. /// /// Boxes can have [fractional]($type/fraction) widths, as the example @@ -93,7 +93,7 @@ pub struct BoxNode { pub body: Option<Content>, } -impl Layout for BoxNode { +impl Layout for BoxElem { fn layout( &self, vt: &mut Vt, @@ -183,8 +183,8 @@ impl Layout for BoxNode { /// /// Display: Block /// Category: layout -#[node(Layout)] -pub struct BlockNode { +#[element(Layout)] +pub struct BlockElem { /// The block's width. /// /// ```example @@ -278,11 +278,11 @@ pub struct BlockNode { #[parse( let spacing = args.named("spacing")?; args.named("above")? - .map(VNode::block_around) - .or_else(|| spacing.map(VNode::block_spacing)) + .map(VElem::block_around) + .or_else(|| spacing.map(VElem::block_spacing)) )] - #[default(VNode::block_spacing(Em::new(1.2).into()))] - pub above: VNode, + #[default(VElem::block_spacing(Em::new(1.2).into()))] + pub above: VElem, /// The spacing between this block and its successor. Takes precedence /// over `spacing`. @@ -290,11 +290,11 @@ pub struct BlockNode { /// The default value is `{1.2em}`. #[parse( args.named("below")? - .map(VNode::block_around) - .or_else(|| spacing.map(VNode::block_spacing)) + .map(VElem::block_around) + .or_else(|| spacing.map(VElem::block_spacing)) )] - #[default(VNode::block_spacing(Em::new(1.2).into()))] - pub below: VNode, + #[default(VElem::block_spacing(Em::new(1.2).into()))] + pub below: VElem, /// The contents of the block. #[positional] @@ -308,7 +308,7 @@ pub struct BlockNode { pub sticky: bool, } -impl Layout for BlockNode { +impl Layout for BlockElem { fn layout( &self, vt: &mut Vt, diff --git a/library/src/layout/enum.rs b/library/src/layout/enum.rs index 05b42bd8..1be57d4c 100644 --- a/library/src/layout/enum.rs +++ b/library/src/layout/enum.rs @@ -1,9 +1,9 @@ use std::str::FromStr; -use crate::layout::{BlockNode, ParNode, Sizing, Spacing}; +use crate::layout::{BlockElem, ParElem, Sizing, Spacing}; use crate::meta::{Numbering, NumberingPattern}; use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; use super::GridLayouter; @@ -50,8 +50,8 @@ use super::GridLayouter; /// /// Display: Numbered List /// Category: layout -#[node(Layout)] -pub struct EnumNode { +#[element(Layout)] +pub struct EnumElem { /// If this is `{false}`, the items are spaced apart with /// [enum spacing]($func/enum.spacing). If it is `{true}`, they use normal /// [leading]($func/par.leading) instead. This makes the enumeration more @@ -153,7 +153,7 @@ pub struct EnumNode { parents: Parent, } -impl Layout for EnumNode { +impl Layout for EnumElem { fn layout( &self, vt: &mut Vt, @@ -164,10 +164,10 @@ impl Layout for EnumNode { let indent = self.indent(styles); let body_indent = self.body_indent(styles); let gutter = if self.tight(styles) { - ParNode::leading_in(styles).into() + ParElem::leading_in(styles).into() } else { self.spacing(styles) - .unwrap_or_else(|| BlockNode::below_in(styles).amount()) + .unwrap_or_else(|| BlockElem::below_in(styles).amount()) }; let mut cells = vec![]; @@ -186,7 +186,7 @@ impl Layout for EnumNode { } else { match &numbering { Numbering::Pattern(pattern) => { - TextNode::packed(pattern.apply_kth(parents.len(), number)) + TextElem::packed(pattern.apply_kth(parents.len(), number)) } other => other.apply_vt(vt, &[number])?.display(), } @@ -221,7 +221,7 @@ impl Layout for EnumNode { /// /// Display: Numbered List Item /// Category: layout -#[node] +#[element] pub struct EnumItem { /// The item's number. #[positional] diff --git a/library/src/layout/flow.rs b/library/src/layout/flow.rs index 096c575e..b6476816 100644 --- a/library/src/layout/flow.rs +++ b/library/src/layout/flow.rs @@ -1,24 +1,22 @@ -use typst::model::StyledNode; - -use super::{AlignNode, BlockNode, ColbreakNode, ParNode, PlaceNode, Spacing, VNode}; +use super::{AlignElem, BlockElem, ColbreakElem, ParElem, PlaceElem, Spacing, VElem}; use crate::prelude::*; -use crate::visualize::{CircleNode, EllipseNode, ImageNode, RectNode, SquareNode}; +use crate::visualize::{CircleElem, EllipseElem, ImageElem, RectElem, SquareElem}; -/// Arrange spacing, paragraphs and block-level nodes into a flow. +/// Arrange spacing, paragraphs and block-level elements into a flow. /// -/// This node is responsible for layouting both the top-level content flow and +/// This element is responsible for layouting both the top-level content flow and /// the contents of boxes. /// /// Display: Flow /// Category: layout -#[node(Layout)] -pub struct FlowNode { +#[element(Layout)] +pub struct FlowElem { /// The children that will be arranges into a flow. #[variadic] pub children: Vec<Content>, } -impl Layout for FlowNode { +impl Layout for FlowElem { fn layout( &self, vt: &mut Vt, @@ -27,29 +25,27 @@ impl Layout for FlowNode { ) -> SourceResult<Fragment> { let mut layouter = FlowLayouter::new(regions); - for mut child in self.children() { - let map; + for mut child in &self.children() { let outer = styles; - let mut styles = outer; - if let Some(node) = child.to::<StyledNode>() { - map = node.styles(); + let mut styles = styles; + if let Some((elem, map)) = child.to_styled() { + child = elem; styles = outer.chain(&map); - child = node.body(); } - if let Some(node) = child.to::<VNode>() { - layouter.layout_spacing(node, styles); - } else if let Some(node) = child.to::<ParNode>() { - layouter.layout_par(vt, node, styles)?; - } else if child.is::<RectNode>() - || child.is::<SquareNode>() - || child.is::<EllipseNode>() - || child.is::<CircleNode>() - || child.is::<ImageNode>() + if let Some(elem) = child.to::<VElem>() { + layouter.layout_spacing(elem, styles); + } else if let Some(elem) = child.to::<ParElem>() { + layouter.layout_par(vt, elem, styles)?; + } else if child.is::<RectElem>() + || child.is::<SquareElem>() + || child.is::<EllipseElem>() + || child.is::<CircleElem>() + || child.is::<ImageElem>() { let layoutable = child.with::<dyn Layout>().unwrap(); layouter.layout_single(vt, layoutable, styles)?; - } else if child.is::<MetaNode>() { + } else if child.is::<MetaElem>() { let mut frame = Frame::new(Size::zero()); frame.meta(styles, true); layouter.items.push(FlowItem::Frame( @@ -59,7 +55,7 @@ impl Layout for FlowNode { )); } else if child.can::<dyn Layout>() { layouter.layout_multiple(vt, &child, styles)?; - } else if child.is::<ColbreakNode>() { + } else if child.is::<ColbreakElem>() { if !layouter.regions.backlog.is_empty() || layouter.regions.last.is_some() { layouter.finish_region(); @@ -122,13 +118,13 @@ impl<'a> FlowLayouter<'a> { } /// Layout vertical spacing. - fn layout_spacing(&mut self, node: &VNode, styles: StyleChain) { - self.layout_item(match node.amount() { - Spacing::Rel(v) => FlowItem::Absolute( - v.resolve(styles).relative_to(self.initial.y), - node.weakness(styles) > 0, + fn layout_spacing(&mut self, v: &VElem, styles: StyleChain) { + self.layout_item(match v.amount() { + Spacing::Rel(rel) => FlowItem::Absolute( + rel.resolve(styles).relative_to(self.initial.y), + v.weakness(styles) > 0, ), - Spacing::Fr(v) => FlowItem::Fractional(v), + Spacing::Fr(fr) => FlowItem::Fractional(fr), }); } @@ -136,11 +132,11 @@ impl<'a> FlowLayouter<'a> { fn layout_par( &mut self, vt: &mut Vt, - par: &ParNode, + par: &ParElem, styles: StyleChain, ) -> SourceResult<()> { - let aligns = AlignNode::alignment_in(styles).resolve(styles); - let leading = ParNode::leading_in(styles); + let aligns = AlignElem::alignment_in(styles).resolve(styles); + let leading = ParElem::leading_in(styles); let consecutive = self.last_was_par; let frames = par .layout(vt, styles, consecutive, self.regions.base(), self.regions.expand.x)? @@ -185,8 +181,8 @@ impl<'a> FlowLayouter<'a> { content: &dyn Layout, styles: StyleChain, ) -> SourceResult<()> { - let aligns = AlignNode::alignment_in(styles).resolve(styles); - let sticky = BlockNode::sticky_in(styles); + let aligns = AlignElem::alignment_in(styles).resolve(styles); + let sticky = BlockElem::sticky_in(styles); let pod = Regions::one(self.regions.base(), Axes::splat(false)); let frame = content.layout(vt, styles, pod)?.into_frame(); self.layout_item(FlowItem::Frame(frame, aligns, sticky)); @@ -201,9 +197,9 @@ impl<'a> FlowLayouter<'a> { block: &Content, styles: StyleChain, ) -> SourceResult<()> { - // Placed nodes that are out of flow produce placed items which aren't - // aligned later. - if let Some(placed) = block.to::<PlaceNode>() { + // Placed elements that are out of flow produce placed items which + // aren't aligned later. + if let Some(placed) = block.to::<PlaceElem>() { if placed.out_of_flow(styles) { let frame = block.layout(vt, styles, self.regions)?.into_frame(); self.layout_item(FlowItem::Placed(frame)); @@ -212,17 +208,17 @@ impl<'a> FlowLayouter<'a> { } // How to align the block. - let aligns = if let Some(align) = block.to::<AlignNode>() { + let aligns = if let Some(align) = block.to::<AlignElem>() { align.alignment(styles) - } else if let Some(styled) = block.to::<StyledNode>() { - AlignNode::alignment_in(styles.chain(&styled.styles())) + } else if let Some((_, local)) = block.to_styled() { + AlignElem::alignment_in(styles.chain(local)) } else { - AlignNode::alignment_in(styles) + AlignElem::alignment_in(styles) } .resolve(styles); // Layout the block itself. - let sticky = BlockNode::sticky_in(styles); + let sticky = BlockElem::sticky_in(styles); let fragment = block.layout(vt, styles, self.regions)?; for (i, frame) in fragment.into_iter().enumerate() { if i > 0 { diff --git a/library/src/layout/grid.rs b/library/src/layout/grid.rs index 47d3ab86..5c3d132e 100644 --- a/library/src/layout/grid.rs +++ b/library/src/layout/grid.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; use super::Sizing; @@ -61,8 +61,8 @@ use super::Sizing; /// /// Display: Grid /// Category: layout -#[node(Layout)] -pub struct GridNode { +#[element(Layout)] +pub struct GridElem { /// Defines the column sizes. /// /// Either specify a track size array or provide an integer to create a grid @@ -101,7 +101,7 @@ pub struct GridNode { pub children: Vec<Content>, } -impl Layout for GridNode { +impl Layout for GridElem { fn layout( &self, vt: &mut Vt, @@ -257,7 +257,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> { } // Reverse for RTL. - let is_rtl = TextNode::dir_in(styles) == Dir::RTL; + let is_rtl = TextElem::dir_in(styles) == Dir::RTL; if is_rtl { cols.reverse(); } diff --git a/library/src/layout/hide.rs b/library/src/layout/hide.rs index 1d87d3e8..d9bee317 100644 --- a/library/src/layout/hide.rs +++ b/library/src/layout/hide.rs @@ -15,15 +15,15 @@ use crate::prelude::*; /// /// Display: Hide /// Category: layout -#[node(Show)] -pub struct HideNode { +#[element(Show)] +pub struct HideElem { /// The content to hide. #[required] pub body: Content, } -impl Show for HideNode { +impl Show for HideElem { fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(self.body().styled(MetaNode::set_data(vec![Meta::Hide]))) + Ok(self.body().styled(MetaElem::set_data(vec![Meta::Hide]))) } } diff --git a/library/src/layout/list.rs b/library/src/layout/list.rs index fe78131d..179c93eb 100644 --- a/library/src/layout/list.rs +++ b/library/src/layout/list.rs @@ -1,6 +1,6 @@ -use crate::layout::{BlockNode, ParNode, Sizing, Spacing}; +use crate::layout::{BlockElem, ParElem, Sizing, Spacing}; use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; use super::GridLayouter; @@ -36,8 +36,8 @@ use super::GridLayouter; /// /// Display: Bullet List /// Category: layout -#[node(Layout)] -pub struct ListNode { +#[element(Layout)] +pub struct ListElem { /// If this is `{false}`, the items are spaced apart with [list /// spacing]($func/list.spacing). If it is `{true}`, they use normal /// [leading]($func/par.leading) instead. This makes the list more compact, @@ -111,7 +111,7 @@ pub struct ListNode { depth: Depth, } -impl Layout for ListNode { +impl Layout for ListElem { fn layout( &self, vt: &mut Vt, @@ -121,10 +121,10 @@ impl Layout for ListNode { let indent = self.indent(styles); let body_indent = self.body_indent(styles); let gutter = if self.tight(styles) { - ParNode::leading_in(styles).into() + ParElem::leading_in(styles).into() } else { self.spacing(styles) - .unwrap_or_else(|| BlockNode::below_in(styles).amount()) + .unwrap_or_else(|| BlockElem::below_in(styles).amount()) }; let depth = self.depth(styles); @@ -160,7 +160,7 @@ impl Layout for ListNode { /// /// Display: Bullet List Item /// Category: layout -#[node] +#[element] pub struct ListItem { /// The item's body. #[required] @@ -187,7 +187,7 @@ impl ListMarker { .get(depth) .or(list.last()) .cloned() - .unwrap_or_else(|| TextNode::packed('•')), + .unwrap_or_else(|| TextElem::packed('•')), Self::Func(func) => func.call_vt(vt, [Value::Int(depth as i64)])?.display(), }) } @@ -198,7 +198,7 @@ cast_from_value! { v: Content => Self::Content(vec![v]), array: Array => { if array.len() == 0 { - Err("must contain at least one marker")?; + Err("array must contain at least one marker")?; } Self::Content(array.into_iter().map(Value::display).collect()) }, diff --git a/library/src/layout/measure.rs b/library/src/layout/measure.rs index b116cbf8..df66d67f 100644 --- a/library/src/layout/measure.rs +++ b/library/src/layout/measure.rs @@ -10,7 +10,7 @@ pub fn measure( /// The content whose size to measure. content: Content, /// The styles with which to layout the content. - styles: StyleMap, + styles: Styles, ) -> Value { let pod = Regions::one(Axes::splat(Abs::inf()), Axes::splat(false)); let styles = StyleChain::new(&styles); diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs index b6ecce51..02d3bca5 100644 --- a/library/src/layout/mod.rs +++ b/library/src/layout/mod.rs @@ -50,14 +50,14 @@ use std::mem; use typed_arena::Arena; use typst::diag::SourceResult; use typst::eval::Tracer; -use typst::model::{applicable, realize, SequenceNode, StyleVecBuilder, StyledNode}; +use typst::model::{applicable, realize, StyleVecBuilder}; -use crate::math::{EquationNode, LayoutMath}; -use crate::meta::DocumentNode; +use crate::math::{EquationElem, LayoutMath}; +use crate::meta::DocumentElem; use crate::prelude::*; use crate::shared::BehavedBuilder; -use crate::text::{LinebreakNode, SmartQuoteNode, SpaceNode, TextNode}; -use crate::visualize::{CircleNode, EllipseNode, ImageNode, RectNode, SquareNode}; +use crate::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem}; +use crate::visualize::{CircleElem, EllipseElem, ImageElem, RectElem, SquareElem}; /// Root-level layout. pub trait LayoutRoot { @@ -69,7 +69,7 @@ impl LayoutRoot for Content { fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> { #[comemo::memoize] fn cached( - node: &Content, + content: &Content, world: Tracked<dyn World>, tracer: TrackedMut<Tracer>, provider: TrackedMut<StabilityProvider>, @@ -78,7 +78,7 @@ impl LayoutRoot for Content { ) -> SourceResult<Document> { let mut vt = Vt { world, tracer, provider, introspector }; let scratch = Scratch::default(); - let (realized, styles) = realize_root(&mut vt, &scratch, node, styles)?; + let (realized, styles) = realize_root(&mut vt, &scratch, content, styles)?; realized .with::<dyn LayoutRoot>() .unwrap() @@ -108,8 +108,8 @@ pub trait Layout { /// Layout without side effects. /// - /// This node must be layouted again in the same order for the results to be - /// valid. + /// This element must be layouted again in the same order for the results to + /// be valid. fn measure( &self, vt: &mut Vt, @@ -132,7 +132,7 @@ impl Layout for Content { ) -> SourceResult<Fragment> { #[comemo::memoize] fn cached( - node: &Content, + content: &Content, world: Tracked<dyn World>, tracer: TrackedMut<Tracer>, provider: TrackedMut<StabilityProvider>, @@ -142,7 +142,7 @@ impl Layout for Content { ) -> SourceResult<Fragment> { let mut vt = Vt { world, tracer, provider, introspector }; let scratch = Scratch::default(); - let (realized, styles) = realize_block(&mut vt, &scratch, node, styles)?; + let (realized, styles) = realize_block(&mut vt, &scratch, content, styles)?; realized .with::<dyn Layout>() .unwrap() @@ -161,7 +161,7 @@ impl Layout for Content { } } -/// Realize into a node that is capable of root-level layout. +/// Realize into an element that is capable of root-level layout. fn realize_root<'a>( vt: &mut Vt, scratch: &'a Scratch<'a>, @@ -176,10 +176,10 @@ fn realize_root<'a>( builder.accept(content, styles)?; builder.interrupt_page(Some(styles))?; let (pages, shared) = builder.doc.unwrap().pages.finish(); - Ok((DocumentNode::new(pages.to_vec()).pack(), shared)) + Ok((DocumentElem::new(pages.to_vec()).pack(), shared)) } -/// Realize into a node that is capable of block-level layout. +/// Realize into an element that is capable of block-level layout. fn realize_block<'a>( vt: &mut Vt, scratch: &'a Scratch<'a>, @@ -187,11 +187,11 @@ fn realize_block<'a>( styles: StyleChain<'a>, ) -> SourceResult<(Content, StyleChain<'a>)> { if content.can::<dyn Layout>() - && !content.is::<RectNode>() - && !content.is::<SquareNode>() - && !content.is::<EllipseNode>() - && !content.is::<CircleNode>() - && !content.is::<ImageNode>() + && !content.is::<RectElem>() + && !content.is::<SquareElem>() + && !content.is::<EllipseElem>() + && !content.is::<CircleElem>() + && !content.is::<ImageElem>() && !applicable(content, styles) { return Ok((content.clone(), styles)); @@ -201,10 +201,10 @@ fn realize_block<'a>( builder.accept(content, styles)?; builder.interrupt_par()?; let (children, shared) = builder.flow.0.finish(); - Ok((FlowNode::new(children.to_vec()).pack(), shared)) + Ok((FlowElem::new(children.to_vec()).pack(), shared)) } -/// Builds a document or a flow node from content. +/// Builds a document or a flow element from content. struct Builder<'a, 'v, 't> { /// The virtual typesetter. vt: &'v mut Vt<'t>, @@ -227,7 +227,6 @@ struct Scratch<'a> { styles: Arena<StyleChain<'a>>, /// An arena where intermediate content resulting from show rules is stored. content: Arena<Content>, - maps: Arena<StyleMap>, } impl<'a, 'v, 't> Builder<'a, 'v, 't> { @@ -247,19 +246,18 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { mut content: &'a Content, styles: StyleChain<'a>, ) -> SourceResult<()> { - if content.can::<dyn LayoutMath>() && !content.is::<EquationNode>() { + if content.can::<dyn LayoutMath>() && !content.is::<EquationElem>() { content = - self.scratch.content.alloc(EquationNode::new(content.clone()).pack()); + self.scratch.content.alloc(EquationElem::new(content.clone()).pack()); } - if let Some(styled) = content.to::<StyledNode>() { - return self.styled(styled, styles); + if let Some((elem, local)) = content.to_styled() { + return self.styled(elem, local, styles); } - if let Some(seq) = content.to::<SequenceNode>() { - for sub in seq.children() { - let stored = self.scratch.content.alloc(sub); - self.accept(stored, styles)?; + if let Some(children) = content.to_sequence() { + for elem in children { + self.accept(elem, styles)?; } return Ok(()); } @@ -290,7 +288,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { } let keep = content - .to::<PagebreakNode>() + .to::<PagebreakElem>() .map_or(false, |pagebreak| !pagebreak.weak(styles)); self.interrupt_page(keep.then(|| styles))?; @@ -301,52 +299,55 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { } } - bail!(content.span(), "not allowed here"); + if content.is::<PagebreakElem>() { + bail!(content.span(), "pagebreaks are not allowed inside of containers"); + } else { + bail!(content.span(), "{} is not allowed here", content.func().name()); + } } fn styled( &mut self, - styled: &'a StyledNode, + elem: &'a Content, + map: &'a Styles, styles: StyleChain<'a>, ) -> SourceResult<()> { - let map = self.scratch.maps.alloc(styled.styles()); let stored = self.scratch.styles.alloc(styles); - let content = self.scratch.content.alloc(styled.body()); let styles = stored.chain(map); self.interrupt_style(&map, None)?; - self.accept(content, styles)?; + self.accept(elem, styles)?; self.interrupt_style(map, Some(styles))?; Ok(()) } fn interrupt_style( &mut self, - map: &StyleMap, - styles: Option<StyleChain<'a>>, + local: &Styles, + outer: Option<StyleChain<'a>>, ) -> SourceResult<()> { - if let Some(Some(span)) = map.interruption::<DocumentNode>() { + if let Some(Some(span)) = local.interruption::<DocumentElem>() { if self.doc.is_none() { - bail!(span, "not allowed here"); + bail!(span, "document set rules are not allowed inside of containers"); } - if styles.is_none() + if outer.is_none() && (!self.flow.0.is_empty() || !self.par.0.is_empty() || !self.list.items.is_empty()) { - bail!(span, "must appear before any content"); + bail!(span, "document set rules must appear before any content"); } - } else if let Some(Some(span)) = map.interruption::<PageNode>() { + } else if let Some(Some(span)) = local.interruption::<PageElem>() { if self.doc.is_none() { - bail!(span, "not allowed here"); + bail!(span, "page configuration is not allowed inside of containers"); } - self.interrupt_page(styles)?; - } else if map.interruption::<ParNode>().is_some() - || map.interruption::<AlignNode>().is_some() + self.interrupt_page(outer)?; + } else if local.interruption::<ParElem>().is_some() + || local.interruption::<AlignElem>().is_some() { self.interrupt_par()?; - } else if map.interruption::<ListNode>().is_some() - || map.interruption::<EnumNode>().is_some() - || map.interruption::<TermsNode>().is_some() + } else if local.interruption::<ListElem>().is_some() + || local.interruption::<EnumElem>().is_some() + || local.interruption::<TermsElem>().is_some() { self.interrupt_list()?; } @@ -387,7 +388,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { } else { shared }; - let page = PageNode::new(FlowNode::new(flow.to_vec()).pack()).pack(); + let page = PageElem::new(FlowElem::new(flow.to_vec()).pack()).pack(); let stored = self.scratch.content.alloc(page); self.accept(stored, styles)?; } @@ -405,12 +406,12 @@ struct DocBuilder<'a> { impl<'a> DocBuilder<'a> { fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool { - if let Some(pagebreak) = content.to::<PagebreakNode>() { + if let Some(pagebreak) = content.to::<PagebreakElem>() { self.keep_next = !pagebreak.weak(styles); return true; } - if content.is::<PageNode>() { + if content.is::<PageElem>() { self.pages.push(content.clone(), styles); self.keep_next = false; return true; @@ -432,7 +433,7 @@ struct FlowBuilder<'a>(BehavedBuilder<'a>, bool); impl<'a> FlowBuilder<'a> { fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool { - if content.is::<ParbreakNode>() { + if content.is::<ParbreakElem>() { self.1 = true; return true; } @@ -440,33 +441,33 @@ impl<'a> FlowBuilder<'a> { let last_was_parbreak = self.1; self.1 = false; - if content.is::<VNode>() - || content.is::<ColbreakNode>() - || content.is::<MetaNode>() + if content.is::<VElem>() + || content.is::<ColbreakElem>() + || content.is::<MetaElem>() { self.0.push(content.clone(), styles); return true; } - if content.can::<dyn Layout>() || content.is::<ParNode>() { - let is_tight_list = if let Some(node) = content.to::<ListNode>() { - node.tight(styles) - } else if let Some(node) = content.to::<EnumNode>() { - node.tight(styles) - } else if let Some(node) = content.to::<TermsNode>() { - node.tight(styles) + if content.can::<dyn Layout>() || content.is::<ParElem>() { + let is_tight_list = if let Some(elem) = content.to::<ListElem>() { + elem.tight(styles) + } else if let Some(elem) = content.to::<EnumElem>() { + elem.tight(styles) + } else if let Some(elem) = content.to::<TermsElem>() { + elem.tight(styles) } else { false }; if !last_was_parbreak && is_tight_list { - let leading = ParNode::leading_in(styles); - let spacing = VNode::list_attach(leading.into()); + let leading = ParElem::leading_in(styles); + let spacing = VElem::list_attach(leading.into()); self.0.push(spacing.pack(), styles); } - let above = BlockNode::above_in(styles); - let below = BlockNode::below_in(styles); + let above = BlockElem::above_in(styles); + let below = BlockElem::below_in(styles); self.0.push(above.clone().pack(), styles); self.0.push(content.clone(), styles); self.0.push(below.clone().pack(), styles); @@ -483,18 +484,18 @@ struct ParBuilder<'a>(BehavedBuilder<'a>); impl<'a> ParBuilder<'a> { fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool { - if content.is::<MetaNode>() { + if content.is::<MetaElem>() { if !self.0.is_basically_empty() { self.0.push(content.clone(), styles); return true; } - } else if content.is::<SpaceNode>() - || content.is::<TextNode>() - || content.is::<HNode>() - || content.is::<LinebreakNode>() - || content.is::<SmartQuoteNode>() - || content.to::<EquationNode>().map_or(false, |node| !node.block(styles)) - || content.is::<BoxNode>() + } else if content.is::<SpaceElem>() + || content.is::<TextElem>() + || content.is::<HElem>() + || content.is::<LinebreakElem>() + || content.is::<SmartQuoteElem>() + || content.to::<EquationElem>().map_or(false, |elem| !elem.block(styles)) + || content.is::<BoxElem>() { self.0.push(content.clone(), styles); return true; @@ -505,7 +506,7 @@ impl<'a> ParBuilder<'a> { fn finish(self) -> (Content, StyleChain<'a>) { let (children, shared) = self.0.finish(); - (ParNode::new(children.to_vec()).pack(), shared) + (ParElem::new(children.to_vec()).pack(), shared) } } @@ -522,7 +523,7 @@ struct ListBuilder<'a> { impl<'a> ListBuilder<'a> { fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool { if !self.items.is_empty() - && (content.is::<SpaceNode>() || content.is::<ParbreakNode>()) + && (content.is::<SpaceElem>() || content.is::<ParbreakElem>()) { self.staged.push((content, styles)); return true; @@ -533,12 +534,12 @@ impl<'a> ListBuilder<'a> { || content.is::<TermItem>()) && self .items - .items() + .elems() .next() - .map_or(true, |first| first.id() == content.id()) + .map_or(true, |first| first.func() == content.func()) { self.items.push(content.clone(), styles); - self.tight &= self.staged.drain(..).all(|(t, _)| !t.is::<ParbreakNode>()); + self.tight &= self.staged.drain(..).all(|(t, _)| !t.is::<ParbreakElem>()); return true; } @@ -549,39 +550,39 @@ impl<'a> ListBuilder<'a> { let (items, shared) = self.items.finish(); let item = items.items().next().unwrap(); let output = if item.is::<ListItem>() { - ListNode::new( + ListElem::new( items .iter() - .map(|(item, map)| { + .map(|(item, local)| { let item = item.to::<ListItem>().unwrap(); - item.clone().with_body(item.body().styled_with_map(map.clone())) + item.clone().with_body(item.body().styled_with_map(local.clone())) }) .collect::<Vec<_>>(), ) .with_tight(self.tight) .pack() } else if item.is::<EnumItem>() { - EnumNode::new( + EnumElem::new( items .iter() - .map(|(item, map)| { + .map(|(item, local)| { let item = item.to::<EnumItem>().unwrap(); - item.clone().with_body(item.body().styled_with_map(map.clone())) + item.clone().with_body(item.body().styled_with_map(local.clone())) }) .collect::<Vec<_>>(), ) .with_tight(self.tight) .pack() } else if item.is::<TermItem>() { - TermsNode::new( + TermsElem::new( items .iter() - .map(|(item, map)| { + .map(|(item, local)| { let item = item.to::<TermItem>().unwrap(); item.clone() - .with_term(item.term().styled_with_map(map.clone())) + .with_term(item.term().styled_with_map(local.clone())) .with_description( - item.description().styled_with_map(map.clone()), + item.description().styled_with_map(local.clone()), ) }) .collect::<Vec<_>>(), diff --git a/library/src/layout/pad.rs b/library/src/layout/pad.rs index e8171560..441aa211 100644 --- a/library/src/layout/pad.rs +++ b/library/src/layout/pad.rs @@ -17,8 +17,8 @@ use crate::prelude::*; /// /// Display: Padding /// Category: layout -#[node(Layout)] -pub struct PadNode { +#[element(Layout)] +pub struct PadElem { /// The padding at the left side. #[parse( let all = args.named("rest")?.or(args.find()?); @@ -59,7 +59,7 @@ pub struct PadNode { pub body: Content, } -impl Layout for PadNode { +impl Layout for PadElem { fn layout( &self, vt: &mut Vt, diff --git a/library/src/layout/page.rs b/library/src/layout/page.rs index 93ee08ce..a8a806ad 100644 --- a/library/src/layout/page.rs +++ b/library/src/layout/page.rs @@ -1,7 +1,7 @@ use std::ptr; use std::str::FromStr; -use super::{AlignNode, ColumnsNode}; +use super::{AlignElem, ColumnsElem}; use crate::meta::{Counter, CounterKey, Numbering}; use crate::prelude::*; @@ -24,8 +24,8 @@ use crate::prelude::*; /// /// Display: Page /// Category: layout -#[node] -pub struct PageNode { +#[element] +pub struct PageElem { /// A standard paper size to set width and height. When this is not /// specified, Typst defaults to `{"a4"}` paper. #[external] @@ -270,7 +270,7 @@ pub struct PageNode { pub body: Content, } -impl PageNode { +impl PageElem { /// Layout the page run into a sequence of frames, one per page. pub fn layout(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Fragment> { // When one of the lengths is infinite the page fits its content along @@ -296,7 +296,7 @@ impl PageNode { // Realize columns. let columns = self.columns(styles); if columns.get() > 1 { - child = ColumnsNode::new(child).with_count(columns).pack(); + child = ColumnsElem::new(child).with_count(columns).pack(); } // Realize margins. @@ -356,7 +356,7 @@ impl PageNode { let pod = Regions::one(area, Axes::splat(true)); let sub = content .clone() - .styled(AlignNode::set_alignment(align)) + .styled(AlignElem::set_alignment(align)) .layout(vt, styles, pod)? .into_frame(); if ptr::eq(marginal, &header) || ptr::eq(marginal, &background) { @@ -387,8 +387,8 @@ impl PageNode { /// /// Display: Page Break /// Category: layout -#[node] -pub struct PagebreakNode { +#[element] +pub struct PagebreakElem { /// If `{true}`, the page break is skipped if the current page is already /// empty. #[default(false)] @@ -467,7 +467,7 @@ macro_rules! papers { fn from_str(name: &str) -> Result<Self, Self::Err> { match name.to_lowercase().as_str() { $($pat => Ok(Self::$var),)* - _ => Err("invalid paper name"), + _ => Err("unknown paper size"), } } } diff --git a/library/src/layout/par.rs b/library/src/layout/par.rs index cef0d11c..db65b125 100644 --- a/library/src/layout/par.rs +++ b/library/src/layout/par.rs @@ -3,17 +3,15 @@ use unicode_bidi::{BidiInfo, Level as BidiLevel}; use unicode_script::{Script, UnicodeScript}; use xi_unicode::LineBreakIterator; -use typst::model::StyledNode; - -use super::{BoxNode, HNode, Sizing, Spacing}; -use crate::layout::AlignNode; -use crate::math::EquationNode; +use super::{BoxElem, HElem, Sizing, Spacing}; +use crate::layout::AlignElem; +use crate::math::EquationElem; use crate::prelude::*; use crate::text::{ - shape, LinebreakNode, Quoter, Quotes, ShapedText, SmartQuoteNode, SpaceNode, TextNode, + shape, LinebreakElem, Quoter, Quotes, ShapedText, SmartQuoteElem, SpaceElem, TextElem, }; -/// Arrange text, spacing and inline-level nodes into a paragraph. +/// Arrange text, spacing and inline-level elements into a paragraph. /// /// Although this function is primarily used in set rules to affect paragraph /// properties, it can also be used to explicitly render its argument onto a @@ -38,8 +36,8 @@ use crate::text::{ /// /// Display: Paragraph /// Category: layout -#[node(Construct)] -pub struct ParNode { +#[element(Construct)] +pub struct ParElem { /// The spacing between lines. /// /// The default value is `{0.65em}`. @@ -110,22 +108,22 @@ pub struct ParNode { pub children: Vec<Content>, } -impl Construct for ParNode { - fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { +impl Construct for ParElem { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { // The paragraph constructor is special: It doesn't create a paragraph - // node. Instead, it just ensures that the passed content lives in a + // element. Instead, it just ensures that the passed content lives in a // separate paragraph and styles it. let styles = Self::set(args)?; let body = args.expect::<Content>("body")?; - Ok(Content::sequence(vec![ - ParbreakNode::new().pack(), + Ok(Content::sequence([ + ParbreakElem::new().pack(), body.styled_with_map(styles), - ParbreakNode::new().pack(), + ParbreakElem::new().pack(), ])) } } -impl ParNode { +impl ParElem { /// Layout the paragraph into a collection of lines. pub fn layout( &self, @@ -137,7 +135,7 @@ impl ParNode { ) -> SourceResult<Fragment> { #[comemo::memoize] fn cached( - par: &ParNode, + par: &ParElem, world: Tracked<dyn World>, tracer: TrackedMut<Tracer>, provider: TrackedMut<StabilityProvider>, @@ -179,26 +177,6 @@ impl ParNode { } } -/// A horizontal alignment. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct HorizontalAlign(pub GenAlign); - -cast_from_value! { - HorizontalAlign, - align: GenAlign => match align.axis() { - Axis::X => Self(align), - Axis::Y => Err("must be horizontal")?, - }, -} - -impl Resolve for HorizontalAlign { - type Output = Align; - - fn resolve(self, styles: StyleChain) -> Self::Output { - self.0.resolve(styles) - } -} - /// How to determine line breaks in a paragraph. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] pub enum Linebreaks { @@ -232,10 +210,10 @@ pub enum Linebreaks { /// /// Display: Paragraph Break /// Category: layout -#[node(Unlabellable)] -pub struct ParbreakNode {} +#[element(Unlabellable)] +pub struct ParbreakElem {} -impl Unlabellable for ParbreakNode {} +impl Unlabellable for ParbreakElem {} /// Range of a substring of text. type Range = std::ops::Range<usize>; @@ -243,7 +221,7 @@ type Range = std::ops::Range<usize>; // The characters by which spacing, inline content and pins are replaced in the // paragraph's full text. const SPACING_REPLACE: char = ' '; // Space -const NODE_REPLACE: char = '\u{FFFC}'; // Object Replacement Character +const OBJ_REPLACE: char = '\u{FFFC}'; // Object Replacement Character /// A paragraph representation in which children are already layouted and text /// is already preshaped. @@ -254,7 +232,7 @@ const NODE_REPLACE: char = '\u{FFFC}'; // Object Replacement Character struct Preparation<'a> { /// Bidirectional text embedding levels for the paragraph. bidi: BidiInfo<'a>, - /// Text runs, spacing and layouted nodes. + /// Text runs, spacing and layouted elements. items: Vec<Item<'a>>, /// The span mapper. spans: SpanMapper, @@ -325,9 +303,9 @@ enum Segment<'a> { /// Horizontal spacing between other segments. Spacing(Spacing), /// A mathematical equation. - Equation(&'a EquationNode), + Equation(&'a EquationElem), /// A box with arbitrary content. - Box(&'a BoxNode, bool), + Box(&'a BoxElem, bool), /// Metadata. Meta, } @@ -339,7 +317,7 @@ impl Segment<'_> { Self::Text(len) => len, Self::Spacing(_) => SPACING_REPLACE.len_utf8(), Self::Box(_, true) => SPACING_REPLACE.len_utf8(), - Self::Equation(_) | Self::Box(_, _) | Self::Meta => NODE_REPLACE.len_utf8(), + Self::Equation(_) | Self::Box(_, _) | Self::Meta => OBJ_REPLACE.len_utf8(), } } } @@ -352,7 +330,7 @@ enum Item<'a> { /// Absolute spacing between other items. Absolute(Abs), /// Fractional spacing between other items. - Fractional(Fr, Option<(&'a BoxNode, StyleChain<'a>)>), + Fractional(Fr, Option<(&'a BoxElem, StyleChain<'a>)>), /// Layouted inline-level content. Frame(Frame), } @@ -371,7 +349,7 @@ impl<'a> Item<'a> { match self { Self::Text(shaped) => shaped.text.len(), Self::Absolute(_) | Self::Fractional(_, _) => SPACING_REPLACE.len_utf8(), - Self::Frame(_) => NODE_REPLACE.len_utf8(), + Self::Frame(_) => OBJ_REPLACE.len_utf8(), } } @@ -520,7 +498,7 @@ fn collect<'a>( let mut iter = children.iter().peekable(); if consecutive { - let first_line_indent = ParNode::first_line_indent_in(*styles); + let first_line_indent = ParElem::first_line_indent_in(*styles); if !first_line_indent.is_zero() && children .iter() @@ -529,7 +507,7 @@ fn collect<'a>( behaved.behaviour() == Behaviour::Ignorant }) { None - } else if child.is::<TextNode>() || child.is::<SmartQuoteNode>() { + } else if child.is::<TextElem>() || child.is::<SmartQuoteElem>() { Some(true) } else { Some(false) @@ -542,7 +520,7 @@ fn collect<'a>( } } - let hang = ParNode::hanging_indent_in(*styles); + let hang = ParElem::hanging_indent_in(*styles); if !hang.is_zero() { full.push(SPACING_REPLACE); segments.push((Segment::Spacing((-hang).into()), *styles)); @@ -551,61 +529,61 @@ fn collect<'a>( while let Some(mut child) = iter.next() { let outer = styles; let mut styles = *styles; - if let Some(node) = child.to::<StyledNode>() { - child = Box::leak(Box::new(node.body())); - styles = outer.chain(Box::leak(Box::new(node.styles()))); + if let Some((elem, local)) = child.to_styled() { + child = elem; + styles = outer.chain(local); } - let segment = if child.is::<SpaceNode>() { + let segment = if child.is::<SpaceElem>() { full.push(' '); Segment::Text(1) - } else if let Some(node) = child.to::<TextNode>() { + } else if let Some(elem) = child.to::<TextElem>() { let prev = full.len(); - if let Some(case) = TextNode::case_in(styles) { - full.push_str(&case.apply(&node.text())); + if let Some(case) = TextElem::case_in(styles) { + full.push_str(&case.apply(&elem.text())); } else { - full.push_str(&node.text()); + full.push_str(&elem.text()); } Segment::Text(full.len() - prev) - } else if let Some(node) = child.to::<HNode>() { + } else if let Some(elem) = child.to::<HElem>() { full.push(SPACING_REPLACE); - Segment::Spacing(node.amount()) - } else if let Some(node) = child.to::<LinebreakNode>() { - let c = if node.justify(styles) { '\u{2028}' } else { '\n' }; + Segment::Spacing(elem.amount()) + } else if let Some(elem) = child.to::<LinebreakElem>() { + let c = if elem.justify(styles) { '\u{2028}' } else { '\n' }; full.push(c); Segment::Text(c.len_utf8()) - } else if let Some(node) = child.to::<SmartQuoteNode>() { + } else if let Some(elem) = child.to::<SmartQuoteElem>() { let prev = full.len(); - if SmartQuoteNode::enabled_in(styles) { - let lang = TextNode::lang_in(styles); - let region = TextNode::region_in(styles); + if SmartQuoteElem::enabled_in(styles) { + let lang = TextElem::lang_in(styles); + let region = TextElem::region_in(styles); let quotes = Quotes::from_lang(lang, region); let peeked = iter.peek().and_then(|child| { - if let Some(node) = child.to::<TextNode>() { - node.text().chars().next() - } else if child.is::<SmartQuoteNode>() { + if let Some(elem) = child.to::<TextElem>() { + elem.text().chars().next() + } else if child.is::<SmartQuoteElem>() { Some('"') - } else if child.is::<SpaceNode>() || child.is::<HNode>() { + } else if child.is::<SpaceElem>() || child.is::<HElem>() { Some(SPACING_REPLACE) } else { - Some(NODE_REPLACE) + Some(OBJ_REPLACE) } }); - full.push_str(quoter.quote("es, node.double(styles), peeked)); + full.push_str(quoter.quote("es, elem.double(styles), peeked)); } else { - full.push(if node.double(styles) { '"' } else { '\'' }); + full.push(if elem.double(styles) { '"' } else { '\'' }); } Segment::Text(full.len() - prev) - } else if let Some(node) = child.to::<EquationNode>() { - full.push(NODE_REPLACE); - Segment::Equation(node) - } else if let Some(node) = child.to::<BoxNode>() { - let frac = node.width(styles).is_fractional(); - full.push(if frac { SPACING_REPLACE } else { NODE_REPLACE }); - Segment::Box(node, frac) - } else if child.is::<MetaNode>() { - full.push(NODE_REPLACE); + } else if let Some(elem) = child.to::<EquationElem>() { + full.push(OBJ_REPLACE); + Segment::Equation(elem) + } else if let Some(elem) = child.to::<BoxElem>() { + let frac = elem.width(styles).is_fractional(); + full.push(if frac { SPACING_REPLACE } else { OBJ_REPLACE }); + Segment::Box(elem, frac) + } else if child.is::<MetaElem>() { + full.push(OBJ_REPLACE); Segment::Meta } else { bail!(child.span(), "unexpected paragraph child"); @@ -645,7 +623,7 @@ fn prepare<'a>( ) -> SourceResult<Preparation<'a>> { let bidi = BidiInfo::new( text, - match TextNode::dir_in(styles) { + match TextElem::dir_in(styles) { Dir::LTR => Some(BidiLevel::ltr()), Dir::RTL => Some(BidiLevel::rtl()), _ => None, @@ -674,16 +652,16 @@ fn prepare<'a>( Segment::Equation(equation) => { let pod = Regions::one(region, Axes::splat(false)); let mut frame = equation.layout(vt, styles, pod)?.into_frame(); - frame.translate(Point::with_y(TextNode::baseline_in(styles))); + frame.translate(Point::with_y(TextElem::baseline_in(styles))); items.push(Item::Frame(frame)); } - Segment::Box(node, _) => { - if let Sizing::Fr(v) = node.width(styles) { - items.push(Item::Fractional(v, Some((node, styles)))); + Segment::Box(elem, _) => { + if let Sizing::Fr(v) = elem.width(styles) { + items.push(Item::Fractional(v, Some((elem, styles)))); } else { let pod = Regions::one(region, Axes::splat(false)); - let mut frame = node.layout(vt, styles, pod)?.into_frame(); - frame.translate(Point::with_y(TextNode::baseline_in(styles))); + let mut frame = elem.layout(vt, styles, pod)?.into_frame(); + frame.translate(Point::with_y(TextElem::baseline_in(styles))); items.push(Item::Frame(frame)); } } @@ -702,11 +680,11 @@ fn prepare<'a>( items, spans, styles, - hyphenate: shared_get(styles, children, TextNode::hyphenate_in), - lang: shared_get(styles, children, TextNode::lang_in), - align: AlignNode::alignment_in(styles).x.resolve(styles), - justify: ParNode::justify_in(styles), - hang: ParNode::hanging_indent_in(styles), + hyphenate: shared_get(styles, children, TextElem::hyphenate_in), + lang: shared_get(styles, children, TextElem::lang_in), + align: AlignElem::alignment_in(styles).x.resolve(styles), + justify: ParElem::justify_in(styles), + hang: ParElem::hanging_indent_in(styles), }) } @@ -775,15 +753,15 @@ fn shared_get<'a, T: PartialEq>( let value = getter(styles); children .iter() - .filter_map(|child| child.to::<StyledNode>()) - .all(|node| getter(styles.chain(&node.styles())) == value) + .filter_map(|child| child.to_styled()) + .all(|(_, local)| getter(styles.chain(&local)) == value) .then(|| value) } /// Find suitable linebreaks. fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { - let linebreaks = ParNode::linebreaks_in(p.styles).unwrap_or_else(|| { - if ParNode::justify_in(p.styles) { + let linebreaks = ParElem::linebreaks_in(p.styles).unwrap_or_else(|| { + if ParElem::justify_in(p.styles) { Linebreaks::Optimized } else { Linebreaks::Simple @@ -881,7 +859,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L line: line(vt, p, 0..0, false, false), }]; - let em = TextNode::size_in(p.styles); + let em = TextElem::size_in(p.styles); for (end, mandatory, hyphen) in breakpoints(p) { let k = table.len(); @@ -1046,7 +1024,7 @@ impl Breakpoints<'_> { .hyphenate .or_else(|| { let shaped = self.p.find(offset)?.text()?; - Some(TextNode::hyphenate_in(shaped.styles)) + Some(TextElem::hyphenate_in(shaped.styles)) }) .unwrap_or(false) } @@ -1055,7 +1033,7 @@ impl Breakpoints<'_> { fn lang(&self, offset: usize) -> Option<hypher::Lang> { let lang = self.p.lang.or_else(|| { let shaped = self.p.find(offset)?.text()?; - Some(TextNode::lang_in(shaped.styles)) + Some(TextElem::lang_in(shaped.styles)) })?; let bytes = lang.as_str().as_bytes().try_into().ok()?; @@ -1196,7 +1174,7 @@ fn finalize( .collect::<SourceResult<_>>()?; // Prevent orphans. - let leading = ParNode::leading_in(p.styles); + let leading = ParElem::leading_in(p.styles); if frames.len() >= 2 && !frames[1].is_empty() { let second = frames.remove(1); let first = &mut frames[0]; @@ -1243,7 +1221,7 @@ fn commit( if let Some(Item::Text(text)) = reordered.first() { if let Some(glyph) = text.glyphs.first() { if !text.dir.is_positive() - && TextNode::overhang_in(text.styles) + && TextElem::overhang_in(text.styles) && (reordered.len() > 1 || text.glyphs.len() > 1) { let amount = overhang(glyph.c) * glyph.x_advance.at(text.size); @@ -1257,7 +1235,7 @@ fn commit( if let Some(Item::Text(text)) = reordered.last() { if let Some(glyph) = text.glyphs.last() { if text.dir.is_positive() - && TextNode::overhang_in(text.styles) + && TextElem::overhang_in(text.styles) && (reordered.len() > 1 || text.glyphs.len() > 1) { let amount = overhang(glyph.c) * glyph.x_advance.at(text.size); @@ -1295,13 +1273,13 @@ fn commit( Item::Absolute(v) => { offset += *v; } - Item::Fractional(v, node) => { + Item::Fractional(v, elem) => { let amount = v.share(fr, remaining); - if let Some((node, styles)) = node { + if let Some((elem, styles)) = elem { let region = Size::new(amount, full); let pod = Regions::one(region, Axes::new(true, false)); - let mut frame = node.layout(vt, *styles, pod)?.into_frame(); - frame.translate(Point::with_y(TextNode::baseline_in(*styles))); + let mut frame = elem.layout(vt, *styles, pod)?.into_frame(); + frame.translate(Point::with_y(TextElem::baseline_in(*styles))); push(&mut offset, frame); } else { offset += amount; diff --git a/library/src/layout/place.rs b/library/src/layout/place.rs index bfabd0f3..057278df 100644 --- a/library/src/layout/place.rs +++ b/library/src/layout/place.rs @@ -23,8 +23,8 @@ use crate::prelude::*; /// /// Display: Place /// Category: layout -#[node(Layout, Behave)] -pub struct PlaceNode { +#[element(Layout, Behave)] +pub struct PlaceElem { /// Relative to which position in the parent container to place the content. /// /// When an axis of the page is `{auto}` sized, all alignments relative to that @@ -53,7 +53,7 @@ pub struct PlaceNode { pub body: Content, } -impl Layout for PlaceNode { +impl Layout for PlaceElem { fn layout( &self, vt: &mut Vt, @@ -86,16 +86,16 @@ impl Layout for PlaceNode { } } -impl PlaceNode { - /// Whether this node wants to be placed relative to its its parent's base - /// origin. Instead of relative to the parent's current flow/cursor +impl PlaceElem { + /// Whether this element wants to be placed relative to its its parent's + /// base origin. Instead of relative to the parent's current flow/cursor /// position. pub fn out_of_flow(&self, styles: StyleChain) -> bool { self.alignment(styles).y.is_some() } } -impl Behave for PlaceNode { +impl Behave for PlaceElem { fn behaviour(&self) -> Behaviour { Behaviour::Ignorant } diff --git a/library/src/layout/regions.rs b/library/src/layout/regions.rs index 94c81704..5a4db178 100644 --- a/library/src/layout/regions.rs +++ b/library/src/layout/regions.rs @@ -14,8 +14,8 @@ pub struct Regions<'a> { /// The height of the final region that is repeated once the backlog is /// drained. The width is the same for all regions. pub last: Option<Abs>, - /// Whether nodes should expand to fill the regions instead of shrinking to - /// fit the content. + /// Whether elements should expand to fill the regions instead of shrinking + /// to fit the content. pub expand: Axes<bool>, } diff --git a/library/src/layout/repeat.rs b/library/src/layout/repeat.rs index c8f63ac3..a44bd075 100644 --- a/library/src/layout/repeat.rs +++ b/library/src/layout/repeat.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -use super::AlignNode; +use super::AlignElem; /// Repeats content to the available space. /// @@ -23,14 +23,14 @@ use super::AlignNode; /// /// Display: Repeat /// Category: layout -#[node(Layout)] -pub struct RepeatNode { +#[element(Layout)] +pub struct RepeatElem { /// The content to repeat. #[required] pub body: Content, } -impl Layout for RepeatNode { +impl Layout for RepeatElem { fn layout( &self, vt: &mut Vt, @@ -39,7 +39,7 @@ impl Layout for RepeatNode { ) -> SourceResult<Fragment> { let pod = Regions::one(regions.size, Axes::new(false, false)); let piece = self.body().layout(vt, styles, pod)?.into_frame(); - let align = AlignNode::alignment_in(styles).x.resolve(styles); + let align = AlignElem::alignment_in(styles).x.resolve(styles); let fill = regions.size.x; let width = piece.width(); diff --git a/library/src/layout/spacing.rs b/library/src/layout/spacing.rs index e67fec03..9253c497 100644 --- a/library/src/layout/spacing.rs +++ b/library/src/layout/spacing.rs @@ -21,8 +21,8 @@ use crate::prelude::*; /// /// Display: Spacing (H) /// Category: layout -#[node(Behave)] -pub struct HNode { +#[element(Behave)] +pub struct HElem { /// How much spacing to insert. #[required] pub amount: Spacing, @@ -45,7 +45,7 @@ pub struct HNode { pub weak: bool, } -impl Behave for HNode { +impl Behave for HElem { fn behaviour(&self) -> Behaviour { if self.amount().is_fractional() { Behaviour::Destructive @@ -85,8 +85,8 @@ impl Behave for HNode { /// /// Display: Spacing (V) /// Category: layout -#[node(Behave)] -pub struct VNode { +#[element(Behave)] +pub struct VElem { /// How much spacing to insert. #[required] pub amount: Spacing, @@ -107,13 +107,13 @@ pub struct VNode { #[external] pub weak: bool, - /// The node's weakness level, see also [`Behaviour`]. + /// The elements's weakness level, see also [`Behaviour`]. #[internal] #[parse(args.named("weak")?.map(|v: bool| v as usize))] pub weakness: usize, } -impl VNode { +impl VElem { /// Normal strong spacing. pub fn strong(amount: Spacing) -> Self { Self::new(amount).with_weakness(0) @@ -129,18 +129,18 @@ impl VNode { Self::new(amount).with_weakness(2) } - /// Weak spacing with BlockNode::ABOVE/BELOW weakness. + /// Weak spacing with BlockElem::ABOVE/BELOW weakness. pub fn block_around(amount: Spacing) -> Self { Self::new(amount).with_weakness(3) } - /// Weak spacing with BlockNode::SPACING weakness. + /// Weak spacing with BlockElem::SPACING weakness. pub fn block_spacing(amount: Spacing) -> Self { Self::new(amount).with_weakness(4) } } -impl Behave for VNode { +impl Behave for VElem { fn behaviour(&self) -> Behaviour { if self.amount().is_fractional() { Behaviour::Destructive @@ -158,8 +158,8 @@ impl Behave for VNode { } cast_from_value! { - VNode, - v: Content => v.to::<Self>().cloned().ok_or("expected vnode")?, + VElem, + v: Content => v.to::<Self>().cloned().ok_or("expected `v` element")?, } /// Kinds of spacing. diff --git a/library/src/layout/stack.rs b/library/src/layout/stack.rs index 1dd81a60..77cd3f8f 100644 --- a/library/src/layout/stack.rs +++ b/library/src/layout/stack.rs @@ -1,6 +1,4 @@ -use typst::model::StyledNode; - -use super::{AlignNode, Spacing}; +use super::{AlignElem, Spacing}; use crate::prelude::*; /// Arrange content and spacing horizontally or vertically. @@ -20,8 +18,8 @@ use crate::prelude::*; /// /// Display: Stack /// Category: layout -#[node(Layout)] -pub struct StackNode { +#[element(Layout)] +pub struct StackElem { /// The direction along which the items are stacked. Possible values are: /// /// - `{ltr}`: Left to right. @@ -39,7 +37,7 @@ pub struct StackNode { pub children: Vec<StackChild>, } -impl Layout for StackNode { +impl Layout for StackElem { fn layout( &self, vt: &mut Vt, @@ -73,7 +71,7 @@ impl Layout for StackNode { } } -/// A child of a stack node. +/// A child of a stack element. #[derive(Hash)] pub enum StackChild { /// Spacing between other children. @@ -196,14 +194,13 @@ impl<'a> StackLayouter<'a> { self.finish_region(); } - // Block-axis alignment of the `AlignNode` is respected - // by the stack node. - let aligns = if let Some(align) = block.to::<AlignNode>() { + // Block-axis alignment of the `AlignElement` is respected by stacks. + let aligns = if let Some(align) = block.to::<AlignElem>() { align.alignment(styles) - } else if let Some(styled) = block.to::<StyledNode>() { - AlignNode::alignment_in(styles.chain(&styled.styles())) + } else if let Some((_, local)) = block.to_styled() { + AlignElem::alignment_in(styles.chain(&local)) } else { - AlignNode::alignment_in(styles) + AlignElem::alignment_in(styles) } .resolve(styles); diff --git a/library/src/layout/table.rs b/library/src/layout/table.rs index d4b6e7d7..809c7ea7 100644 --- a/library/src/layout/table.rs +++ b/library/src/layout/table.rs @@ -1,4 +1,4 @@ -use crate::layout::{AlignNode, GridLayouter, TrackSizings}; +use crate::layout::{AlignElem, GridLayouter, TrackSizings}; use crate::meta::LocalName; use crate::prelude::*; @@ -32,8 +32,8 @@ use crate::prelude::*; /// /// Display: Table /// Category: layout -#[node(Layout, LocalName)] -pub struct TableNode { +#[element(Layout, LocalName)] +pub struct TableElem { /// Defines the column sizes. See the [grid documentation]($func/grid) for /// more information on track sizing. pub columns: TrackSizings, @@ -109,7 +109,7 @@ pub struct TableNode { pub children: Vec<Content>, } -impl Layout for TableNode { +impl Layout for TableElem { fn layout( &self, vt: &mut Vt, @@ -132,7 +132,7 @@ impl Layout for TableNode { let x = i % cols; let y = i / cols; if let Smart::Custom(alignment) = align.resolve(vt, x, y)? { - child = child.styled(AlignNode::set_alignment(alignment)); + child = child.styled(AlignElem::set_alignment(alignment)); } Ok(child) @@ -168,7 +168,7 @@ impl Layout for TableNode { let hline = Geometry::Line(target).stroked(stroke); frame.prepend( Point::new(-half, offset), - Element::Shape(hline, self.span()), + FrameItem::Shape(hline, self.span()), ); } @@ -178,7 +178,7 @@ impl Layout for TableNode { let vline = Geometry::Line(target).stroked(stroke); frame.prepend( Point::new(offset, -half), - Element::Shape(vline, self.span()), + FrameItem::Shape(vline, self.span()), ); } } @@ -192,7 +192,7 @@ impl Layout for TableNode { let pos = Point::new(dx, dy); let size = Size::new(col, row.height); let rect = Geometry::Rect(size).filled(fill); - frame.prepend(pos, Element::Shape(rect, self.span())); + frame.prepend(pos, FrameItem::Shape(rect, self.span())); } dy += row.height; } @@ -271,7 +271,7 @@ impl<T: Into<Value>> From<Celled<T>> for Value { } } -impl LocalName for TableNode { +impl LocalName for TableElem { fn local_name(&self, lang: Lang) -> &'static str { match lang { Lang::GERMAN => "Tabelle", diff --git a/library/src/layout/terms.rs b/library/src/layout/terms.rs index 853dd32d..1200076f 100644 --- a/library/src/layout/terms.rs +++ b/library/src/layout/terms.rs @@ -1,7 +1,7 @@ -use super::{HNode, VNode}; -use crate::layout::{BlockNode, ParNode, Spacing}; +use super::{HElem, VElem}; +use crate::layout::{BlockElem, ParElem, Spacing}; use crate::prelude::*; -use crate::text::{SpaceNode, TextNode}; +use crate::text::{SpaceElem, TextElem}; /// A list of terms and their descriptions. /// @@ -22,8 +22,8 @@ use crate::text::{SpaceNode, TextNode}; /// /// Display: Term List /// Category: layout -#[node(Layout)] -pub struct TermsNode { +#[element(Layout)] +pub struct TermsElem { /// If this is `{false}`, the items are spaced apart with [term list /// spacing]($func/terms.spacing). If it is `{true}`, they use normal /// [leading]($func/par.leading) instead. This makes the term list more @@ -76,7 +76,7 @@ pub struct TermsNode { pub children: Vec<TermItem>, } -impl Layout for TermsNode { +impl Layout for TermsElem { fn layout( &self, vt: &mut Vt, @@ -86,27 +86,27 @@ impl Layout for TermsNode { let indent = self.indent(styles); let hanging_indent = self.hanging_indent(styles); let gutter = if self.tight(styles) { - ParNode::leading_in(styles).into() + ParElem::leading_in(styles).into() } else { self.spacing(styles) - .unwrap_or_else(|| BlockNode::below_in(styles).amount()) + .unwrap_or_else(|| BlockElem::below_in(styles).amount()) }; let mut seq = vec![]; for (i, child) in self.children().into_iter().enumerate() { if i > 0 { - seq.push(VNode::new(gutter).with_weakness(1).pack()); + seq.push(VElem::new(gutter).with_weakness(1).pack()); } if indent.is_zero() { - seq.push(HNode::new(indent.into()).pack()); + seq.push(HElem::new(indent.into()).pack()); } - seq.push((child.term() + TextNode::packed(':')).strong()); - seq.push(SpaceNode::new().pack()); + seq.push((child.term() + TextElem::packed(':')).strong()); + seq.push(SpaceElem::new().pack()); seq.push(child.description()); } Content::sequence(seq) - .styled(ParNode::set_hanging_indent(hanging_indent + indent)) + .styled(ParElem::set_hanging_indent(hanging_indent + indent)) .layout(vt, styles, regions) } } @@ -115,7 +115,7 @@ impl Layout for TermsNode { /// /// Display: Term List Item /// Category: layout -#[node] +#[element] pub struct TermItem { /// The term described by the list item. #[required] diff --git a/library/src/layout/transform.rs b/library/src/layout/transform.rs index 2afe8201..2045e9ed 100644 --- a/library/src/layout/transform.rs +++ b/library/src/layout/transform.rs @@ -23,8 +23,8 @@ use crate::prelude::*; /// /// Display: Move /// Category: layout -#[node(Layout)] -pub struct MoveNode { +#[element(Layout)] +pub struct MoveElem { /// The horizontal displacement of the content. pub dx: Rel<Length>, @@ -36,7 +36,7 @@ pub struct MoveNode { pub body: Content, } -impl Layout for MoveNode { +impl Layout for MoveElem { fn layout( &self, vt: &mut Vt, @@ -69,8 +69,8 @@ impl Layout for MoveNode { /// /// Display: Rotate /// Category: layout -#[node(Layout)] -pub struct RotateNode { +#[element(Layout)] +pub struct RotateElem { /// The amount of rotation. /// /// ```example @@ -104,7 +104,7 @@ pub struct RotateNode { pub body: Content, } -impl Layout for RotateNode { +impl Layout for RotateElem { fn layout( &self, vt: &mut Vt, @@ -137,8 +137,8 @@ impl Layout for RotateNode { /// /// Display: Scale /// Category: layout -#[node(Layout)] -pub struct ScaleNode { +#[element(Layout)] +pub struct ScaleElem { /// The horizontal scaling factor. /// /// The body will be mirrored horizontally if the parameter is negative. @@ -172,7 +172,7 @@ pub struct ScaleNode { pub body: Content, } -impl Layout for ScaleNode { +impl Layout for ScaleElem { fn layout( &self, vt: &mut Vt, diff --git a/library/src/lib.rs b/library/src/lib.rs index 2f951b92..1a998700 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -13,7 +13,7 @@ pub mod visualize; use typst::diag::At; use typst::eval::{LangItems, Library, Module, Scope}; use typst::geom::{Align, Color, Dir, GenAlign, Smart}; -use typst::model::{Node, NodeId, StyleMap}; +use typst::model::{Element, Styles}; use self::layout::LayoutRoot; @@ -30,69 +30,69 @@ fn global(math: Module, calc: Module) -> Module { let mut global = Scope::deduplicating(); // Text. - global.define("text", text::TextNode::id()); - global.define("linebreak", text::LinebreakNode::id()); - global.define("smartquote", text::SmartQuoteNode::id()); - global.define("strong", text::StrongNode::id()); - global.define("emph", text::EmphNode::id()); + global.define("text", text::TextElem::func()); + global.define("linebreak", text::LinebreakElem::func()); + global.define("smartquote", text::SmartQuoteElem::func()); + global.define("strong", text::StrongElem::func()); + global.define("emph", text::EmphElem::func()); global.define("lower", text::lower); global.define("upper", text::upper); global.define("smallcaps", text::smallcaps); - global.define("sub", text::SubNode::id()); - global.define("super", text::SuperNode::id()); - global.define("underline", text::UnderlineNode::id()); - global.define("strike", text::StrikeNode::id()); - global.define("overline", text::OverlineNode::id()); - global.define("raw", text::RawNode::id()); + global.define("sub", text::SubElem::func()); + global.define("super", text::SuperElem::func()); + global.define("underline", text::UnderlineElem::func()); + global.define("strike", text::StrikeElem::func()); + global.define("overline", text::OverlineElem::func()); + global.define("raw", text::RawElem::func()); global.define("lorem", text::lorem); // Math. global.define("math", math); // Layout. - global.define("page", layout::PageNode::id()); - global.define("pagebreak", layout::PagebreakNode::id()); - global.define("v", layout::VNode::id()); - global.define("par", layout::ParNode::id()); - global.define("parbreak", layout::ParbreakNode::id()); - global.define("h", layout::HNode::id()); - global.define("box", layout::BoxNode::id()); - global.define("block", layout::BlockNode::id()); - global.define("list", layout::ListNode::id()); - global.define("enum", layout::EnumNode::id()); - global.define("terms", layout::TermsNode::id()); - global.define("table", layout::TableNode::id()); - global.define("stack", layout::StackNode::id()); - global.define("grid", layout::GridNode::id()); - global.define("columns", layout::ColumnsNode::id()); - global.define("colbreak", layout::ColbreakNode::id()); - global.define("place", layout::PlaceNode::id()); - global.define("align", layout::AlignNode::id()); - global.define("pad", layout::PadNode::id()); - global.define("repeat", layout::RepeatNode::id()); - global.define("move", layout::MoveNode::id()); - global.define("scale", layout::ScaleNode::id()); - global.define("rotate", layout::RotateNode::id()); - global.define("hide", layout::HideNode::id()); + global.define("page", layout::PageElem::func()); + global.define("pagebreak", layout::PagebreakElem::func()); + global.define("v", layout::VElem::func()); + global.define("par", layout::ParElem::func()); + global.define("parbreak", layout::ParbreakElem::func()); + global.define("h", layout::HElem::func()); + global.define("box", layout::BoxElem::func()); + global.define("block", layout::BlockElem::func()); + global.define("list", layout::ListElem::func()); + global.define("enum", layout::EnumElem::func()); + global.define("terms", layout::TermsElem::func()); + global.define("table", layout::TableElem::func()); + global.define("stack", layout::StackElem::func()); + global.define("grid", layout::GridElem::func()); + global.define("columns", layout::ColumnsElem::func()); + global.define("colbreak", layout::ColbreakElem::func()); + global.define("place", layout::PlaceElem::func()); + global.define("align", layout::AlignElem::func()); + global.define("pad", layout::PadElem::func()); + global.define("repeat", layout::RepeatElem::func()); + global.define("move", layout::MoveElem::func()); + global.define("scale", layout::ScaleElem::func()); + global.define("rotate", layout::RotateElem::func()); + global.define("hide", layout::HideElem::func()); global.define("measure", layout::measure); // Visualize. - global.define("image", visualize::ImageNode::id()); - global.define("line", visualize::LineNode::id()); - global.define("rect", visualize::RectNode::id()); - global.define("square", visualize::SquareNode::id()); - global.define("ellipse", visualize::EllipseNode::id()); - global.define("circle", visualize::CircleNode::id()); + global.define("image", visualize::ImageElem::func()); + global.define("line", visualize::LineElem::func()); + global.define("rect", visualize::RectElem::func()); + global.define("square", visualize::SquareElem::func()); + global.define("ellipse", visualize::EllipseElem::func()); + global.define("circle", visualize::CircleElem::func()); // Meta. - global.define("document", meta::DocumentNode::id()); - global.define("ref", meta::RefNode::id()); - global.define("link", meta::LinkNode::id()); - global.define("outline", meta::OutlineNode::id()); - global.define("heading", meta::HeadingNode::id()); - global.define("figure", meta::FigureNode::id()); - global.define("cite", meta::CiteNode::id()); - global.define("bibliography", meta::BibliographyNode::id()); + global.define("document", meta::DocumentElem::func()); + global.define("ref", meta::RefElem::func()); + global.define("link", meta::LinkElem::func()); + global.define("outline", meta::OutlineElem::func()); + global.define("heading", meta::HeadingElem::func()); + global.define("figure", meta::FigureElem::func()); + global.define("cite", meta::CiteElem::func()); + global.define("bibliography", meta::BibliographyElem::func()); global.define("locate", meta::locate); global.define("style", meta::style); global.define("counter", meta::counter); @@ -166,71 +166,71 @@ fn global(math: Module, calc: Module) -> Module { } /// Construct the standard style map. -fn styles() -> StyleMap { - StyleMap::new() +fn styles() -> Styles { + Styles::new() } /// Construct the standard lang item mapping. fn items() -> LangItems { LangItems { layout: |world, content, styles| content.layout_root(world, styles), - em: text::TextNode::size_in, - dir: text::TextNode::dir_in, - space: || text::SpaceNode::new().pack(), - linebreak: || text::LinebreakNode::new().pack(), - text: |text| text::TextNode::new(text).pack(), - text_id: NodeId::of::<text::TextNode>(), - text_str: |content| Some(content.to::<text::TextNode>()?.text()), - smart_quote: |double| text::SmartQuoteNode::new().with_double(double).pack(), - parbreak: || layout::ParbreakNode::new().pack(), - strong: |body| text::StrongNode::new(body).pack(), - emph: |body| text::EmphNode::new(body).pack(), + em: text::TextElem::size_in, + dir: text::TextElem::dir_in, + space: || text::SpaceElem::new().pack(), + linebreak: || text::LinebreakElem::new().pack(), + text: |text| text::TextElem::new(text).pack(), + text_func: text::TextElem::func(), + text_str: |content| Some(content.to::<text::TextElem>()?.text()), + smart_quote: |double| text::SmartQuoteElem::new().with_double(double).pack(), + parbreak: || layout::ParbreakElem::new().pack(), + strong: |body| text::StrongElem::new(body).pack(), + emph: |body| text::EmphElem::new(body).pack(), raw: |text, lang, block| { - let mut node = text::RawNode::new(text).with_block(block); + let mut elem = text::RawElem::new(text).with_block(block); if let Some(lang) = lang { - node.push_lang(Some(lang)); + elem.push_lang(Some(lang)); } - node.pack() + elem.pack() }, - raw_languages: text::RawNode::languages, - link: |url| meta::LinkNode::from_url(url).pack(), + raw_languages: text::RawElem::languages, + link: |url| meta::LinkElem::from_url(url).pack(), reference: |target, supplement| { - let mut node = meta::RefNode::new(target); + let mut elem = meta::RefElem::new(target); if let Some(supplement) = supplement { - node.push_supplement(Smart::Custom(Some(meta::Supplement::Content( + elem.push_supplement(Smart::Custom(Some(meta::Supplement::Content( supplement, )))); } - node.pack() + elem.pack() }, - bibliography_keys: meta::BibliographyNode::keys, - heading: |level, title| meta::HeadingNode::new(title).with_level(level).pack(), + bibliography_keys: meta::BibliographyElem::keys, + heading: |level, title| meta::HeadingElem::new(title).with_level(level).pack(), list_item: |body| layout::ListItem::new(body).pack(), enum_item: |number, body| { - let mut node = layout::EnumItem::new(body); + let mut elem = layout::EnumItem::new(body); if let Some(number) = number { - node.push_number(Some(number)); + elem.push_number(Some(number)); } - node.pack() + elem.pack() }, term_item: |term, description| layout::TermItem::new(term, description).pack(), - equation: |body, block| math::EquationNode::new(body).with_block(block).pack(), - math_align_point: || math::AlignPointNode::new().pack(), - math_delimited: |open, body, close| math::LrNode::new(open + body + close).pack(), + equation: |body, block| math::EquationElem::new(body).with_block(block).pack(), + math_align_point: || math::AlignPointElem::new().pack(), + math_delimited: |open, body, close| math::LrElem::new(open + body + close).pack(), math_attach: |base, bottom, top| { - let mut node = math::AttachNode::new(base); + let mut elem = math::AttachElem::new(base); if let Some(bottom) = bottom { - node.push_bottom(Some(bottom)); + elem.push_bottom(Some(bottom)); } if let Some(top) = top { - node.push_top(Some(top)); + elem.push_top(Some(top)); } - node.pack() + elem.pack() }, math_accent: |base, accent| { - math::AccentNode::new(base, math::Accent::new(accent)).pack() + math::AccentElem::new(base, math::Accent::new(accent)).pack() }, - math_frac: |num, denom| math::FracNode::new(num, denom).pack(), + math_frac: |num, denom| math::FracElem::new(num, denom).pack(), library_method: |vm, dynamic, method, args, span| { if let Some(counter) = dynamic.downcast::<meta::Counter>().cloned() { counter.call_method(vm, method, args, span) diff --git a/library/src/math/accent.rs b/library/src/math/accent.rs index 9ef76279..471507c5 100644 --- a/library/src/math/accent.rs +++ b/library/src/math/accent.rs @@ -1,5 +1,3 @@ -use typst::eval::combining_accent; - use super::*; /// How much the accent can be shorter than the base. @@ -16,8 +14,8 @@ const ACCENT_SHORT_FALL: Em = Em::new(0.5); /// /// Display: Accent /// Category: math -#[node(LayoutMath)] -pub struct AccentNode { +#[element(LayoutMath)] +pub struct AccentElem { /// The base to which the accent is applied. /// May consist of multiple letters. /// @@ -50,7 +48,7 @@ pub struct AccentNode { pub accent: Accent, } -impl LayoutMath for AccentNode { +impl LayoutMath for AccentElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { ctx.style(ctx.style.with_cramped(true)); let base = ctx.layout_fragment(&self.base())?; @@ -116,15 +114,15 @@ pub struct Accent(char); impl Accent { /// Normalize a character into an accent. pub fn new(c: char) -> Self { - Self(combining_accent(c).unwrap_or(c)) + Self(Symbol::combining_accent(c).unwrap_or(c)) } } cast_from_value! { Accent, v: char => Self::new(v), - v: Content => match v.to::<TextNode>() { - Some(node) => Value::Str(node.text().into()).cast()?, + v: Content => match v.to::<TextElem>() { + Some(elem) => Value::Str(elem.text().into()).cast()?, None => Err("expected text")?, }, } diff --git a/library/src/math/align.rs b/library/src/math/align.rs index 6cf13a0f..d34379e2 100644 --- a/library/src/math/align.rs +++ b/library/src/math/align.rs @@ -4,10 +4,10 @@ use super::*; /// /// Display: Alignment Point /// Category: math -#[node(LayoutMath)] -pub struct AlignPointNode {} +#[element(LayoutMath)] +pub struct AlignPointElem {} -impl LayoutMath for AlignPointNode { +impl LayoutMath for AlignPointElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { ctx.push(MathFragment::Align); Ok(()) diff --git a/library/src/math/attach.rs b/library/src/math/attach.rs index 7d8749f2..1b315f77 100644 --- a/library/src/math/attach.rs +++ b/library/src/math/attach.rs @@ -13,8 +13,8 @@ use super::*; /// /// Display: Attachment /// Category: math -#[node(LayoutMath)] -pub struct AttachNode { +#[element(LayoutMath)] +pub struct AttachElem { /// The base to which things are attached. #[required] pub base: Content, @@ -26,25 +26,25 @@ pub struct AttachNode { pub bottom: Option<Content>, } -impl LayoutMath for AttachNode { +impl LayoutMath for AttachElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let base = self.base(); - let display_limits = base.is::<LimitsNode>(); - let display_scripts = base.is::<ScriptsNode>(); + let display_limits = base.is::<LimitsElem>(); + let display_scripts = base.is::<ScriptsElem>(); let base = ctx.layout_fragment(&base)?; ctx.style(ctx.style.for_subscript()); let top = self .top(ctx.styles()) - .map(|node| ctx.layout_fragment(&node)) + .map(|elem| ctx.layout_fragment(&elem)) .transpose()?; ctx.unstyle(); ctx.style(ctx.style.for_superscript()); let bottom = self .bottom(ctx.styles()) - .map(|node| ctx.layout_fragment(&node)) + .map(|elem| ctx.layout_fragment(&elem)) .transpose()?; ctx.unstyle(); @@ -75,14 +75,14 @@ impl LayoutMath for AttachNode { /// /// Display: Scripts /// Category: math -#[node(LayoutMath)] -pub struct ScriptsNode { +#[element(LayoutMath)] +pub struct ScriptsElem { /// The base to attach the scripts to. #[required] pub body: Content, } -impl LayoutMath for ScriptsNode { +impl LayoutMath for ScriptsElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { self.body().layout_math(ctx) } @@ -97,14 +97,14 @@ impl LayoutMath for ScriptsNode { /// /// Display: Limits /// Category: math -#[node(LayoutMath)] -pub struct LimitsNode { +#[element(LayoutMath)] +pub struct LimitsElem { /// The base to attach the limits to. #[required] pub body: Content, } -impl LayoutMath for LimitsNode { +impl LayoutMath for LimitsElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { self.body().layout_math(ctx) } diff --git a/library/src/math/ctx.rs b/library/src/math/ctx.rs index bd44546d..aed826b5 100644 --- a/library/src/math/ctx.rs +++ b/library/src/math/ctx.rs @@ -32,7 +32,7 @@ pub struct MathContext<'a, 'b, 'v> { pub constants: ttf_parser::math::Constants<'a>, pub space_width: Em, pub fragments: Vec<MathFragment>, - pub map: StyleMap, + pub local: Styles, pub style: MathStyle, pub size: Abs, outer: StyleChain<'a>, @@ -49,7 +49,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { ) -> Self { let table = font.ttf().tables().math.unwrap(); let constants = table.constants.unwrap(); - let size = TextNode::size_in(styles); + let size = TextElem::size_in(styles); let ttf = font.ttf(); let space_width = ttf .glyph_index(' ') @@ -67,7 +67,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { constants, space_width, fragments: vec![], - map: StyleMap::new(), + local: Styles::new(), style: MathStyle { variant: MathVariant::Serif, size: if block { MathSize::Display } else { MathSize::Text }, @@ -94,39 +94,39 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { pub fn layout_fragment( &mut self, - node: &dyn LayoutMath, + elem: &dyn LayoutMath, ) -> SourceResult<MathFragment> { - let row = self.layout_fragments(node)?; + let row = self.layout_fragments(elem)?; Ok(MathRow::new(row).to_fragment(self)) } pub fn layout_fragments( &mut self, - node: &dyn LayoutMath, + elem: &dyn LayoutMath, ) -> SourceResult<Vec<MathFragment>> { let prev = std::mem::take(&mut self.fragments); - node.layout_math(self)?; + elem.layout_math(self)?; Ok(std::mem::replace(&mut self.fragments, prev)) } - pub fn layout_row(&mut self, node: &dyn LayoutMath) -> SourceResult<MathRow> { - let fragments = self.layout_fragments(node)?; + pub fn layout_row(&mut self, elem: &dyn LayoutMath) -> SourceResult<MathRow> { + let fragments = self.layout_fragments(elem)?; Ok(MathRow::new(fragments)) } - pub fn layout_frame(&mut self, node: &dyn LayoutMath) -> SourceResult<Frame> { - Ok(self.layout_fragment(node)?.to_frame()) + pub fn layout_frame(&mut self, elem: &dyn LayoutMath) -> SourceResult<Frame> { + Ok(self.layout_fragment(elem)?.to_frame()) } pub fn layout_content(&mut self, content: &Content) -> SourceResult<Frame> { Ok(content - .layout(&mut self.vt, self.outer.chain(&self.map), self.regions)? + .layout(&mut self.vt, self.outer.chain(&self.local), self.regions)? .into_frame()) } - pub fn layout_text(&mut self, node: &TextNode) -> SourceResult<()> { - let text = node.text(); - let span = node.span(); + pub fn layout_text(&mut self, elem: &TextElem) -> SourceResult<()> { + let text = elem.text(); + let span = elem.span(); let mut chars = text.chars(); if let Some(glyph) = chars .next() @@ -160,7 +160,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { style = style.with_italic(false); } let text: EcoString = text.chars().map(|c| style.styled_char(c)).collect(); - let frame = self.layout_content(&TextNode::packed(text).spanned(span))?; + let frame = self.layout_content(&TextElem::packed(text).spanned(span))?; self.push( FrameFragment::new(self, frame) .with_class(MathClass::Alphabetic) @@ -172,21 +172,21 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { } pub fn styles(&self) -> StyleChain { - self.outer.chain(&self.map) + self.outer.chain(&self.local) } pub fn style(&mut self, style: MathStyle) { self.style_stack.push((self.style, self.size)); - let base_size = TextNode::size_in(self.styles()) / self.style.size.factor(self); + let base_size = TextElem::size_in(self.styles()) / self.style.size.factor(self); self.size = base_size * style.size.factor(self); - self.map.set(TextNode::set_size(TextSize(self.size.into()))); - self.map - .set(TextNode::set_style(if style.italic == Smart::Custom(true) { + self.local.set(TextElem::set_size(TextSize(self.size.into()))); + self.local + .set(TextElem::set_style(if style.italic == Smart::Custom(true) { FontStyle::Italic } else { FontStyle::Normal })); - self.map.set(TextNode::set_weight(if style.bold { + self.local.set(TextElem::set_weight(if style.bold { FontWeight::BOLD } else { FontWeight::REGULAR @@ -196,9 +196,9 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { pub fn unstyle(&mut self) { (self.style, self.size) = self.style_stack.pop().unwrap(); - self.map.unset(); - self.map.unset(); - self.map.unset(); + self.local.unset(); + self.local.unset(); + self.local.unset(); } } diff --git a/library/src/math/delimited.rs b/library/src/math/delimited.rs index 2b9ee5ed..3be17eae 100644 --- a/library/src/math/delimited.rs +++ b/library/src/math/delimited.rs @@ -16,8 +16,8 @@ pub(super) const DELIM_SHORT_FALL: Em = Em::new(0.1); /// /// Display: Left/Right /// Category: math -#[node(LayoutMath)] -pub struct LrNode { +#[element(LayoutMath)] +pub struct LrElem { /// The size of the brackets, relative to the height of the wrapped content. /// /// Defaults to `{100%}`. @@ -29,7 +29,7 @@ pub struct LrNode { let mut body = Content::empty(); for (i, arg) in args.all::<Content>()?.into_iter().enumerate() { if i > 0 { - body += TextNode::packed(','); + body += TextElem::packed(','); } body += arg; } @@ -38,12 +38,12 @@ pub struct LrNode { pub body: Content, } -impl LayoutMath for LrNode { +impl LayoutMath for LrElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let mut body = self.body(); - if let Some(node) = body.to::<LrNode>() { - if node.size(ctx.styles()).is_auto() { - body = node.body(); + if let Some(elem) = body.to::<LrElem>() { + if elem.size(ctx.styles()).is_auto() { + body = elem.body(); } } @@ -179,12 +179,11 @@ pub fn norm( } fn delimited(body: Content, left: char, right: char) -> Value { - Value::Content( - LrNode::new(Content::sequence(vec![ - TextNode::packed(left), - body, - TextNode::packed(right), - ])) - .pack(), - ) + LrElem::new(Content::sequence([ + TextElem::packed(left), + body, + TextElem::packed(right), + ])) + .pack() + .into() } diff --git a/library/src/math/frac.rs b/library/src/math/frac.rs index 90bc69b3..f19fb32e 100644 --- a/library/src/math/frac.rs +++ b/library/src/math/frac.rs @@ -19,8 +19,8 @@ const FRAC_AROUND: Em = Em::new(0.1); /// /// Display: Fraction /// Category: math -#[node(LayoutMath)] -pub struct FracNode { +#[element(LayoutMath)] +pub struct FracElem { /// The fraction's numerator. #[required] pub num: Content, @@ -30,7 +30,7 @@ pub struct FracNode { pub denom: Content, } -impl LayoutMath for FracNode { +impl LayoutMath for FracElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, &self.num(), &self.denom(), false, self.span()) } @@ -45,8 +45,8 @@ impl LayoutMath for FracNode { /// /// Display: Binomial /// Category: math -#[node(LayoutMath)] -pub struct BinomNode { +#[element(LayoutMath)] +pub struct BinomElem { /// The binomial's upper index. #[required] pub upper: Content, @@ -56,7 +56,7 @@ pub struct BinomNode { pub lower: Content, } -impl LayoutMath for BinomNode { +impl LayoutMath for BinomElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, &self.upper(), &self.lower(), true, self.span()) } @@ -132,9 +132,9 @@ fn layout( } else { frame.push( line_pos, - Element::Shape( + FrameItem::Shape( Geometry::Line(Point::with_x(line_width)).stroked(Stroke { - paint: TextNode::fill_in(ctx.styles()), + paint: TextElem::fill_in(ctx.styles()), thickness, }), span, diff --git a/library/src/math/fragment.rs b/library/src/math/fragment.rs index 87e28555..0d663d3f 100644 --- a/library/src/math/fragment.rs +++ b/library/src/math/fragment.rs @@ -181,8 +181,8 @@ impl GlyphFragment { id, c, font: ctx.font.clone(), - lang: TextNode::lang_in(ctx.styles()), - fill: TextNode::fill_in(ctx.styles()), + lang: TextElem::lang_in(ctx.styles()), + fill: TextElem::fill_in(ctx.styles()), style: ctx.style, font_size: ctx.size, width, @@ -215,7 +215,7 @@ impl GlyphFragment { } pub fn to_frame(&self) -> Frame { - let text = Text { + let item = TextItem { font: self.font.clone(), size: self.font_size, fill: self.fill, @@ -232,7 +232,7 @@ impl GlyphFragment { let size = Size::new(self.width, self.ascent + self.descent); let mut frame = Frame::new(size); frame.set_baseline(self.ascent); - frame.push(Point::with_y(self.ascent), Element::Text(text)); + frame.push(Point::with_y(self.ascent), FrameItem::Text(item)); frame } } diff --git a/library/src/math/matrix.rs b/library/src/math/matrix.rs index d79c7ca5..8fba10e7 100644 --- a/library/src/math/matrix.rs +++ b/library/src/math/matrix.rs @@ -16,8 +16,8 @@ const VERTICAL_PADDING: Ratio = Ratio::new(0.1); /// /// Display: Vector /// Category: math -#[node(LayoutMath)] -pub struct VecNode { +#[element(LayoutMath)] +pub struct VecElem { /// The delimiter to use. /// /// ```example @@ -32,7 +32,7 @@ pub struct VecNode { pub children: Vec<Content>, } -impl LayoutMath for VecNode { +impl LayoutMath for VecElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let delim = self.delim(ctx.styles()); let frame = layout_vec_body(ctx, &self.children(), Align::Center)?; @@ -68,8 +68,8 @@ impl LayoutMath for VecNode { /// /// Display: Matrix /// Category: math -#[node(LayoutMath)] -pub struct MatNode { +#[element(LayoutMath)] +pub struct MatElem { /// The delimiter to use. /// /// ```example @@ -114,7 +114,7 @@ pub struct MatNode { pub rows: Vec<Vec<Content>>, } -impl LayoutMath for MatNode { +impl LayoutMath for MatElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let delim = self.delim(ctx.styles()); let frame = layout_mat_body(ctx, &self.rows())?; @@ -144,8 +144,8 @@ impl LayoutMath for MatNode { /// /// Display: Cases /// Category: math -#[node(LayoutMath)] -pub struct CasesNode { +#[element(LayoutMath)] +pub struct CasesElem { /// The delimiter to use. /// /// ```example @@ -160,7 +160,7 @@ pub struct CasesNode { pub children: Vec<Content>, } -impl LayoutMath for CasesNode { +impl LayoutMath for CasesElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let delim = self.delim(ctx.styles()); let frame = layout_vec_body(ctx, &self.children(), Align::Left)?; @@ -221,8 +221,8 @@ fn layout_vec_body( let gap = ROW_GAP.scaled(ctx); ctx.style(ctx.style.for_denominator()); let mut flat = vec![]; - for element in column { - flat.push(ctx.layout_row(element)?); + for child in column { + flat.push(ctx.layout_row(child)?); } ctx.unstyle(); Ok(stack(ctx, flat, align, gap, 0)) diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index 7fb1aadf..cf665203 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -31,69 +31,69 @@ pub use self::underover::*; use ttf_parser::{GlyphId, Rect}; use typst::eval::{Module, Scope}; use typst::font::{Font, FontWeight}; -use typst::model::{Guard, SequenceNode, StyledNode}; +use typst::model::Guard; use unicode_math_class::MathClass; use self::ctx::*; use self::fragment::*; use self::row::*; use self::spacing::*; -use crate::layout::{HNode, ParNode, Spacing}; +use crate::layout::{HElem, ParElem, Spacing}; use crate::meta::{Count, Counter, CounterUpdate, LocalName, Numbering}; use crate::prelude::*; use crate::text::{ - families, variant, FontFamily, FontList, LinebreakNode, SpaceNode, TextNode, TextSize, + families, variant, FontFamily, FontList, LinebreakElem, SpaceElem, TextElem, TextSize, }; /// Create a module with all math definitions. pub fn module() -> Module { let mut math = Scope::deduplicating(); - math.define("equation", EquationNode::id()); - math.define("text", TextNode::id()); + math.define("equation", EquationElem::func()); + math.define("text", TextElem::func()); // Grouping. - math.define("lr", LrNode::id()); + math.define("lr", LrElem::func()); math.define("abs", abs); math.define("norm", norm); math.define("floor", floor); math.define("ceil", ceil); // Attachments and accents. - math.define("attach", AttachNode::id()); - math.define("scripts", ScriptsNode::id()); - math.define("limits", LimitsNode::id()); - math.define("accent", AccentNode::id()); - math.define("underline", UnderlineNode::id()); - math.define("overline", OverlineNode::id()); - math.define("underbrace", UnderbraceNode::id()); - math.define("overbrace", OverbraceNode::id()); - math.define("underbracket", UnderbracketNode::id()); - math.define("overbracket", OverbracketNode::id()); + math.define("attach", AttachElem::func()); + math.define("scripts", ScriptsElem::func()); + math.define("limits", LimitsElem::func()); + math.define("accent", AccentElem::func()); + math.define("underline", UnderlineElem::func()); + math.define("overline", OverlineElem::func()); + math.define("underbrace", UnderbraceElem::func()); + math.define("overbrace", OverbraceElem::func()); + math.define("underbracket", UnderbracketElem::func()); + math.define("overbracket", OverbracketElem::func()); // Fractions and matrix-likes. - math.define("frac", FracNode::id()); - math.define("binom", BinomNode::id()); - math.define("vec", VecNode::id()); - math.define("mat", MatNode::id()); - math.define("cases", CasesNode::id()); + math.define("frac", FracElem::func()); + math.define("binom", BinomElem::func()); + math.define("vec", VecElem::func()); + math.define("mat", MatElem::func()); + math.define("cases", CasesElem::func()); // Roots. - math.define("sqrt", SqrtNode::id()); - math.define("root", RootNode::id()); + math.define("sqrt", sqrt); + math.define("root", RootElem::func()); // Styles. - math.define("upright", UprightNode::id()); - math.define("bold", BoldNode::id()); - math.define("italic", ItalicNode::id()); - math.define("serif", SerifNode::id()); - math.define("sans", SansNode::id()); - math.define("cal", CalNode::id()); - math.define("frak", FrakNode::id()); - math.define("mono", MonoNode::id()); - math.define("bb", BbNode::id()); + math.define("upright", upright); + math.define("bold", bold); + math.define("italic", italic); + math.define("serif", serif); + math.define("sans", sans); + math.define("cal", cal); + math.define("frak", frak); + math.define("mono", mono); + math.define("bb", bb); // Text operators. - math.define("op", OpNode::id()); + math.define("op", OpElem::func()); op::define(&mut math); // Spacings. @@ -133,8 +133,8 @@ pub fn module() -> Module { /// /// Display: Equation /// Category: math -#[node(Locatable, Synthesize, Show, Finalize, Layout, LayoutMath, Count, LocalName)] -pub struct EquationNode { +#[element(Locatable, Synthesize, Show, Finalize, Layout, LayoutMath, Count, LocalName)] +pub struct EquationElem { /// Whether the equation is displayed as a separate block. #[default(false)] pub block: bool, @@ -157,16 +157,16 @@ pub struct EquationNode { pub body: Content, } -impl Synthesize for EquationNode { +impl Synthesize for EquationElem { fn synthesize(&mut self, _: &Vt, styles: StyleChain) { self.push_block(self.block(styles)); self.push_numbering(self.numbering(styles)); } } -impl Show for EquationNode { +impl Show for EquationElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - let mut realized = self.clone().pack().guarded(Guard::Base(NodeId::of::<Self>())); + let mut realized = self.clone().pack().guarded(Guard::Base(Self::func())); if self.block(styles) { realized = realized.aligned(Axes::with_x(Some(Align::Center.into()))) } @@ -174,17 +174,17 @@ impl Show for EquationNode { } } -impl Finalize for EquationNode { +impl Finalize for EquationElem { fn finalize(&self, realized: Content, _: StyleChain) -> Content { realized - .styled(TextNode::set_weight(FontWeight::from_number(450))) - .styled(TextNode::set_font(FontList(vec![FontFamily::new( + .styled(TextElem::set_weight(FontWeight::from_number(450))) + .styled(TextElem::set_font(FontList(vec![FontFamily::new( "New Computer Modern Math", )]))) } } -impl Layout for EquationNode { +impl Layout for EquationElem { fn layout( &self, vt: &mut Vt, @@ -215,7 +215,7 @@ impl Layout for EquationNode { if block { if let Some(numbering) = self.numbering(styles) { let pod = Regions::one(regions.base(), Axes::splat(false)); - let counter = Counter::of(Self::id()) + let counter = Counter::of(Self::func()) .display(numbering, false) .layout(vt, styles, pod)? .into_frame(); @@ -230,7 +230,7 @@ impl Layout for EquationNode { let height = frame.height().max(counter.height()); frame.resize(Size::new(width, height), Align::CENTER_HORIZON); - let x = if TextNode::dir_in(styles).is_positive() { + let x = if TextElem::dir_in(styles).is_positive() { frame.width() - counter.width() } else { Abs::zero() @@ -240,10 +240,10 @@ impl Layout for EquationNode { frame.push_frame(Point::new(x, y), counter) } } else { - let slack = ParNode::leading_in(styles) * 0.7; - let top_edge = TextNode::top_edge_in(styles).resolve(styles, font.metrics()); + let slack = ParElem::leading_in(styles) * 0.7; + let top_edge = TextElem::top_edge_in(styles).resolve(styles, font.metrics()); let bottom_edge = - -TextNode::bottom_edge_in(styles).resolve(styles, font.metrics()); + -TextElem::bottom_edge_in(styles).resolve(styles, font.metrics()); let ascent = top_edge.max(frame.ascent() - slack); let descent = bottom_edge.max(frame.descent() - slack); @@ -255,7 +255,7 @@ impl Layout for EquationNode { } } -impl Count for EquationNode { +impl Count for EquationElem { fn update(&self) -> Option<CounterUpdate> { (self.block(StyleChain::default()) && self.numbering(StyleChain::default()).is_some()) @@ -263,7 +263,7 @@ impl Count for EquationNode { } } -impl LocalName for EquationNode { +impl LocalName for EquationElem { fn local_name(&self, lang: Lang) -> &'static str { match lang { Lang::GERMAN => "Gleichung", @@ -276,7 +276,7 @@ pub trait LayoutMath { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()>; } -impl LayoutMath for EquationNode { +impl LayoutMath for EquationElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { self.body().layout_math(ctx) } @@ -284,45 +284,44 @@ impl LayoutMath for EquationNode { impl LayoutMath for Content { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - if let Some(node) = self.to::<SequenceNode>() { - for child in node.children() { + if let Some(children) = self.to_sequence() { + for child in children { child.layout_math(ctx)?; } return Ok(()); } - if let Some(styled) = self.to::<StyledNode>() { - let map = styled.styles(); - if TextNode::font_in(ctx.styles().chain(&map)) - != TextNode::font_in(ctx.styles()) + if let Some((elem, styles)) = self.to_styled() { + if TextElem::font_in(ctx.styles().chain(&styles)) + != TextElem::font_in(ctx.styles()) { let frame = ctx.layout_content(self)?; ctx.push(FrameFragment::new(ctx, frame).with_spaced(true)); return Ok(()); } - let prev_map = std::mem::replace(&mut ctx.map, map); + let prev_map = std::mem::replace(&mut ctx.local, styles.clone()); let prev_size = ctx.size; - ctx.map.apply(prev_map.clone()); - ctx.size = TextNode::size_in(ctx.styles()); - styled.body().layout_math(ctx)?; + ctx.local.apply(prev_map.clone()); + ctx.size = TextElem::size_in(ctx.styles()); + elem.layout_math(ctx)?; ctx.size = prev_size; - ctx.map = prev_map; + ctx.local = prev_map; return Ok(()); } - if self.is::<SpaceNode>() { + if self.is::<SpaceElem>() { ctx.push(MathFragment::Space(ctx.space_width.scaled(ctx))); return Ok(()); } - if self.is::<LinebreakNode>() { + if self.is::<LinebreakElem>() { ctx.push(MathFragment::Linebreak); return Ok(()); } - if let Some(node) = self.to::<HNode>() { - if let Spacing::Rel(rel) = node.amount() { + if let Some(elem) = self.to::<HElem>() { + if let Spacing::Rel(rel) = elem.amount() { if rel.rel.is_zero() { ctx.push(MathFragment::Spacing(rel.abs.resolve(ctx.styles()))); } @@ -330,13 +329,13 @@ impl LayoutMath for Content { return Ok(()); } - if let Some(node) = self.to::<TextNode>() { - ctx.layout_text(node)?; + if let Some(elem) = self.to::<TextElem>() { + ctx.layout_text(elem)?; return Ok(()); } - if let Some(node) = self.with::<dyn LayoutMath>() { - return node.layout_math(ctx); + if let Some(elem) = self.with::<dyn LayoutMath>() { + return elem.layout_math(ctx); } let mut frame = ctx.layout_content(self)?; diff --git a/library/src/math/op.rs b/library/src/math/op.rs index dae43c3a..e8db0c5d 100644 --- a/library/src/math/op.rs +++ b/library/src/math/op.rs @@ -20,8 +20,8 @@ use super::*; /// /// Display: Text Operator /// Category: math -#[node(LayoutMath)] -pub struct OpNode { +#[element(LayoutMath)] +pub struct OpElem { /// The operator's text. #[required] pub text: EcoString, @@ -33,9 +33,9 @@ pub struct OpNode { pub limits: bool, } -impl LayoutMath for OpNode { +impl LayoutMath for OpElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - let frame = ctx.layout_content(&TextNode::packed(self.text()))?; + let frame = ctx.layout_content(&TextElem::packed(self.text()))?; ctx.push( FrameFragment::new(ctx, frame) .with_class(MathClass::Large) @@ -50,14 +50,14 @@ macro_rules! ops { pub(super) fn define(math: &mut Scope) { $(math.define( stringify!($name), - OpNode::new(ops!(@name $name $(: $value)?).into()) + OpElem::new(ops!(@name $name $(: $value)?).into()) .with_limits(ops!(@limit $($tts)*)) .pack() );)* let dif = |d| { - HNode::new(THIN.into()).pack() - + UprightNode::new(TextNode::packed(d)).pack() + HElem::new(THIN.into()).pack() + + MathStyleElem::new(TextElem::packed(d)).with_italic(Some(false)).pack() }; math.define("dif", dif('d')); math.define("Dif", dif('D')); diff --git a/library/src/math/root.rs b/library/src/math/root.rs index b4756b9d..037c6ce7 100644 --- a/library/src/math/root.rs +++ b/library/src/math/root.rs @@ -9,17 +9,13 @@ use super::*; /// /// Display: Square Root /// Category: math -#[node(LayoutMath)] -pub struct SqrtNode { +/// Returns: content +#[func] +pub fn sqrt( /// The expression to take the square root of. - #[required] - pub radicand: Content, -} - -impl LayoutMath for SqrtNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - layout(ctx, None, &self.radicand(), self.span()) - } + radicand: Content, +) -> Value { + RootElem::new(radicand).pack().into() } /// A general root. @@ -31,20 +27,20 @@ impl LayoutMath for SqrtNode { /// /// Display: Root /// Category: math -#[node(LayoutMath)] -pub struct RootNode { +#[element(LayoutMath)] +pub struct RootElem { /// Which root of the radicand to take. - #[required] - index: Content, + #[positional] + index: Option<Content>, /// The expression to take the root of. #[required] radicand: Content, } -impl LayoutMath for RootNode { +impl LayoutMath for RootElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - layout(ctx, Some(&self.index()), &self.radicand(), self.span()) + layout(ctx, self.index(ctx.styles()).as_ref(), &self.radicand(), self.span()) } } @@ -88,7 +84,7 @@ fn layout( // Layout the index. // Script-script style looks too small, we use Script style instead. ctx.style(ctx.style.with_size(MathSize::Script)); - let index = index.map(|node| ctx.layout_frame(node)).transpose()?; + let index = index.map(|elem| ctx.layout_frame(elem)).transpose()?; ctx.unstyle(); let gap = gap.max((sqrt.height() - radicand.height() - thickness) / 2.0); @@ -124,9 +120,9 @@ fn layout( frame.push_frame(sqrt_pos, sqrt); frame.push( line_pos, - Element::Shape( + FrameItem::Shape( Geometry::Line(Point::with_x(radicand.width())) - .stroked(Stroke { paint: TextNode::fill_in(ctx.styles()), thickness }), + .stroked(Stroke { paint: TextElem::fill_in(ctx.styles()), thickness }), span, ), ); @@ -139,15 +135,15 @@ fn layout( /// Select a precomposed radical, if the font has it. fn precomposed(ctx: &MathContext, index: Option<&Content>, target: Abs) -> Option<Frame> { - let node = index?.to::<TextNode>()?; - let c = match node.text().as_str() { + let elem = index?.to::<TextElem>()?; + let c = match elem.text().as_str() { "3" => '∛', "4" => '∜', _ => return None, }; ctx.ttf.glyph_index(c)?; - let glyph = GlyphFragment::new(ctx, c, node.span()); + let glyph = GlyphFragment::new(ctx, c, elem.span()); let variant = glyph.stretch_vertical(ctx, target, Abs::zero()).frame; if variant.height() < target { return None; diff --git a/library/src/math/row.rs b/library/src/math/row.rs index ecb2e31e..67d9eeaf 100644 --- a/library/src/math/row.rs +++ b/library/src/math/row.rs @@ -1,4 +1,4 @@ -use crate::layout::AlignNode; +use crate::layout::AlignElem; use super::*; @@ -103,7 +103,7 @@ impl MathRow { pub fn to_frame(self, ctx: &MathContext) -> Frame { let styles = ctx.styles(); - let align = AlignNode::alignment_in(styles).x.resolve(styles); + let align = AlignElem::alignment_in(styles).x.resolve(styles); self.to_aligned_frame(ctx, &[], align) } @@ -124,7 +124,7 @@ impl MathRow { if self.iter().any(|frag| matches!(frag, MathFragment::Linebreak)) { let fragments: Vec<_> = std::mem::take(&mut self.0); let leading = if ctx.style.size >= MathSize::Text { - ParNode::leading_in(ctx.styles()) + ParElem::leading_in(ctx.styles()) } else { TIGHT_LEADING.scaled(ctx) }; diff --git a/library/src/math/spacing.rs b/library/src/math/spacing.rs index e1b9d408..848aca78 100644 --- a/library/src/math/spacing.rs +++ b/library/src/math/spacing.rs @@ -7,10 +7,10 @@ pub(super) const QUAD: Em = Em::new(1.0); /// Hook up all spacings. pub(super) fn define(math: &mut Scope) { - math.define("thin", HNode::new(THIN.into()).pack()); - math.define("med", HNode::new(MEDIUM.into()).pack()); - math.define("thick", HNode::new(THICK.into()).pack()); - math.define("quad", HNode::new(QUAD.into()).pack()); + math.define("thin", HElem::new(THIN.into()).pack()); + math.define("med", HElem::new(MEDIUM.into()).pack()); + math.define("thick", HElem::new(THICK.into()).pack()); + math.define("quad", HElem::new(QUAD.into()).pack()); } /// Create the spacing between two fragments in a given style. diff --git a/library/src/math/style.rs b/library/src/math/style.rs index a3383a0c..7a911a0a 100644 --- a/library/src/math/style.rs +++ b/library/src/math/style.rs @@ -9,20 +9,13 @@ use super::*; /// /// Display: Bold /// Category: math -#[node(LayoutMath)] -pub struct BoldNode { +/// Returns: content +#[func] +pub fn bold( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for BoldNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_bold(true)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body).with_bold(Some(true)).pack().into() } /// Upright (non-italic) font style in math. @@ -34,20 +27,13 @@ impl LayoutMath for BoldNode { /// /// Display: Upright /// Category: math -#[node(LayoutMath)] -pub struct UprightNode { +/// Returns: content +#[func] +pub fn upright( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for UprightNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_italic(false)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body).with_italic(Some(false)).pack().into() } /// Italic font style in math. @@ -56,42 +42,30 @@ impl LayoutMath for UprightNode { /// /// Display: Italic /// Category: math -#[node(LayoutMath)] -pub struct ItalicNode { +/// Returns: content +#[func] +pub fn italic( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for ItalicNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_italic(true)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body).with_italic(Some(true)).pack().into() } - /// Serif (roman) font style in math. /// /// This is already the default. /// /// Display: Serif /// Category: math -#[node(LayoutMath)] -pub struct SerifNode { +/// Returns: content +#[func] +pub fn serif( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for SerifNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_variant(MathVariant::Serif)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body) + .with_variant(Some(MathVariant::Serif)) + .pack() + .into() } /// Sans-serif font style in math. @@ -103,20 +77,16 @@ impl LayoutMath for SerifNode { /// /// Display: Sans-serif /// Category: math -#[node(LayoutMath)] -pub struct SansNode { +/// Returns: content +#[func] +pub fn sans( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for SansNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_variant(MathVariant::Sans)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body) + .with_variant(Some(MathVariant::Sans)) + .pack() + .into() } /// Calligraphic font style in math. @@ -128,20 +98,16 @@ impl LayoutMath for SansNode { /// /// Display: Calligraphic /// Category: math -#[node(LayoutMath)] -pub struct CalNode { +/// Returns: content +#[func] +pub fn cal( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for CalNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_variant(MathVariant::Cal)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body) + .with_variant(Some(MathVariant::Cal)) + .pack() + .into() } /// Fraktur font style in math. @@ -153,20 +119,16 @@ impl LayoutMath for CalNode { /// /// Display: Fraktur /// Category: math -#[node(LayoutMath)] -pub struct FrakNode { +/// Returns: content +#[func] +pub fn frak( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for FrakNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_variant(MathVariant::Frak)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body) + .with_variant(Some(MathVariant::Frak)) + .pack() + .into() } /// Monospace font style in math. @@ -178,20 +140,16 @@ impl LayoutMath for FrakNode { /// /// Display: Monospace /// Category: math -#[node(LayoutMath)] -pub struct MonoNode { +/// Returns: content +#[func] +pub fn mono( /// The content to style. - #[required] - pub body: Content, -} - -impl LayoutMath for MonoNode { - fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_variant(MathVariant::Mono)); - self.body().layout_math(ctx)?; - ctx.unstyle(); - Ok(()) - } + body: Content, +) -> Value { + MathStyleElem::new(body) + .with_variant(Some(MathVariant::Mono)) + .pack() + .into() } /// Blackboard bold (double-struck) font style in math. @@ -208,16 +166,51 @@ impl LayoutMath for MonoNode { /// /// Display: Blackboard Bold /// Category: math -#[node(LayoutMath)] -pub struct BbNode { +/// Returns: content +#[func] +pub fn bb( + /// The content to style. + body: Content, +) -> Value { + MathStyleElem::new(body) + .with_variant(Some(MathVariant::Bb)) + .pack() + .into() +} + +/// A font variant in math. +/// +/// Display: Bold +/// Category: math +#[element(LayoutMath)] +pub struct MathStyleElem { /// The content to style. #[required] pub body: Content, + + /// The variant to select. + pub variant: Option<MathVariant>, + + /// Whether to use bold glyphs. + pub bold: Option<bool>, + + /// Whether to use italic glyphs. + pub italic: Option<bool>, } -impl LayoutMath for BbNode { +impl LayoutMath for MathStyleElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - ctx.style(ctx.style.with_variant(MathVariant::Bb)); + let mut style = ctx.style; + if let Some(variant) = self.variant(StyleChain::default()) { + style = style.with_variant(variant); + } + if let Some(bold) = self.bold(StyleChain::default()) { + style = style.with_bold(bold); + } + if let Some(italic) = self.italic(StyleChain::default()) { + style = style.with_italic(italic); + } + ctx.style(style); self.body().layout_math(ctx)?; ctx.unstyle(); Ok(()) @@ -324,7 +317,7 @@ impl MathSize { } /// A mathematical style variant, as defined by Unicode. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Cast)] pub enum MathVariant { Serif, Sans, diff --git a/library/src/math/underover.rs b/library/src/math/underover.rs index cfbb30b6..654da354 100644 --- a/library/src/math/underover.rs +++ b/library/src/math/underover.rs @@ -13,14 +13,14 @@ const BRACKET_GAP: Em = Em::new(0.25); /// /// Display: Underline /// Category: math -#[node(LayoutMath)] -pub struct UnderlineNode { +#[element(LayoutMath)] +pub struct UnderlineElem { /// The content above the line. #[required] pub body: Content, } -impl LayoutMath for UnderlineNode { +impl LayoutMath for UnderlineElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, &self.body(), &None, '\u{305}', LINE_GAP, false, self.span()) } @@ -35,14 +35,14 @@ impl LayoutMath for UnderlineNode { /// /// Display: Overline /// Category: math -#[node(LayoutMath)] -pub struct OverlineNode { +#[element(LayoutMath)] +pub struct OverlineElem { /// The content below the line. #[required] pub body: Content, } -impl LayoutMath for OverlineNode { +impl LayoutMath for OverlineElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, &self.body(), &None, '\u{332}', LINE_GAP, true, self.span()) } @@ -57,8 +57,8 @@ impl LayoutMath for OverlineNode { /// /// Display: Underbrace /// Category: math -#[node(LayoutMath)] -pub struct UnderbraceNode { +#[element(LayoutMath)] +pub struct UnderbraceElem { /// The content above the brace. #[required] pub body: Content, @@ -68,7 +68,7 @@ pub struct UnderbraceNode { pub annotation: Option<Content>, } -impl LayoutMath for UnderbraceNode { +impl LayoutMath for UnderbraceElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout( ctx, @@ -91,8 +91,8 @@ impl LayoutMath for UnderbraceNode { /// /// Display: Overbrace /// Category: math -#[node(LayoutMath)] -pub struct OverbraceNode { +#[element(LayoutMath)] +pub struct OverbraceElem { /// The content below the brace. #[required] pub body: Content, @@ -102,7 +102,7 @@ pub struct OverbraceNode { pub annotation: Option<Content>, } -impl LayoutMath for OverbraceNode { +impl LayoutMath for OverbraceElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout( ctx, @@ -125,8 +125,8 @@ impl LayoutMath for OverbraceNode { /// /// Display: Underbracket /// Category: math -#[node(LayoutMath)] -pub struct UnderbracketNode { +#[element(LayoutMath)] +pub struct UnderbracketElem { /// The content above the bracket. #[required] pub body: Content, @@ -136,7 +136,7 @@ pub struct UnderbracketNode { pub annotation: Option<Content>, } -impl LayoutMath for UnderbracketNode { +impl LayoutMath for UnderbracketElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout( ctx, @@ -159,8 +159,8 @@ impl LayoutMath for UnderbracketNode { /// /// Display: Overbracket /// Category: math -#[node(LayoutMath)] -pub struct OverbracketNode { +#[element(LayoutMath)] +pub struct OverbracketElem { /// The content below the bracket. #[required] pub body: Content, @@ -170,7 +170,7 @@ pub struct OverbracketNode { pub annotation: Option<Content>, } -impl LayoutMath for OverbracketNode { +impl LayoutMath for OverbracketElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout( ctx, diff --git a/library/src/meta/bibliography.rs b/library/src/meta/bibliography.rs index 64ac1f8e..5f244a8f 100644 --- a/library/src/meta/bibliography.rs +++ b/library/src/meta/bibliography.rs @@ -8,18 +8,18 @@ use hayagriva::io::{BibLaTeXError, YamlBibliographyError}; use hayagriva::style::{self, Brackets, Citation, Database, DisplayString, Formatting}; use hayagriva::Entry; -use super::{LocalName, RefNode}; -use crate::layout::{BlockNode, GridNode, ParNode, Sizing, TrackSizings, VNode}; -use crate::meta::HeadingNode; +use super::{LocalName, RefElem}; +use crate::layout::{BlockElem, GridElem, ParElem, Sizing, TrackSizings, VElem}; +use crate::meta::HeadingElem; use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; /// A bibliography / reference listing. /// /// Display: Bibliography /// Category: meta -#[node(Locatable, Synthesize, Show, LocalName)] -pub struct BibliographyNode { +#[element(Locatable, Synthesize, Show, LocalName)] +pub struct BibliographyElem { /// Path to a Hayagriva `.yml` or BibLaTeX `.bib` file. #[required] #[parse( @@ -45,11 +45,11 @@ pub struct BibliographyNode { pub style: BibliographyStyle, } -impl BibliographyNode { +impl BibliographyElem { /// Find the document's bibliography. pub fn find(introspector: Tracked<Introspector>) -> StrResult<Self> { - let mut iter = introspector.query(Selector::node::<Self>()).into_iter(); - let Some(node) = iter.next() else { + let mut iter = introspector.query(Self::func().select()).into_iter(); + let Some(elem) = iter.next() else { return Err("the document does not contain a bibliography".into()); }; @@ -57,15 +57,15 @@ impl BibliographyNode { Err("multiple bibliographies are not supported")?; } - Ok(node.to::<Self>().unwrap().clone()) + Ok(elem.to::<Self>().unwrap().clone()) } /// Whether the bibliography contains the given key. pub fn has(vt: &Vt, key: &str) -> bool { vt.introspector - .query(Selector::node::<Self>()) + .query(Self::func().select()) .into_iter() - .flat_map(|node| load(vt.world, &node.to::<Self>().unwrap().path())) + .flat_map(|elem| load(vt.world, &elem.to::<Self>().unwrap().path())) .flatten() .any(|entry| entry.key() == key) } @@ -76,7 +76,7 @@ impl BibliographyNode { introspector: Tracked<Introspector>, ) -> Vec<(EcoString, Option<EcoString>)> { Self::find(introspector) - .and_then(|node| load(world, &node.path())) + .and_then(|elem| load(world, &elem.path())) .into_iter() .flatten() .map(|entry| { @@ -89,13 +89,13 @@ impl BibliographyNode { } } -impl Synthesize for BibliographyNode { +impl Synthesize for BibliographyElem { fn synthesize(&mut self, _: &Vt, styles: StyleChain) { self.push_style(self.style(styles)); } } -impl Show for BibliographyNode { +impl Show for BibliographyElem { fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { const COLUMN_GUTTER: Em = Em::new(0.65); const INDENT: Em = Em::new(1.5); @@ -103,12 +103,12 @@ impl Show for BibliographyNode { let mut seq = vec![]; if let Some(title) = self.title(styles) { let title = title.clone().unwrap_or_else(|| { - TextNode::packed(self.local_name(TextNode::lang_in(styles))) + TextElem::packed(self.local_name(TextElem::lang_in(styles))) .spanned(self.span()) }); seq.push( - HeadingNode::new(title) + HeadingElem::new(title) .with_level(NonZeroUsize::ONE) .with_numbering(None) .pack(), @@ -121,7 +121,7 @@ impl Show for BibliographyNode { let works = Works::new(vt).at(self.span())?; - let row_gutter = BlockNode::below_in(styles).amount(); + let row_gutter = BlockElem::below_in(styles).amount(); if works.references.iter().any(|(prefix, _)| prefix.is_some()) { let mut cells = vec![]; for (prefix, reference) in &works.references { @@ -129,9 +129,9 @@ impl Show for BibliographyNode { cells.push(reference.clone()); } - seq.push(VNode::new(row_gutter).with_weakness(3).pack()); + seq.push(VElem::new(row_gutter).with_weakness(3).pack()); seq.push( - GridNode::new(cells) + GridElem::new(cells) .with_columns(TrackSizings(vec![Sizing::Auto; 2])) .with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()])) .with_row_gutter(TrackSizings(vec![row_gutter.into()])) @@ -140,13 +140,13 @@ impl Show for BibliographyNode { } else { let mut entries = vec![]; for (_, reference) in &works.references { - entries.push(VNode::new(row_gutter).with_weakness(3).pack()); + entries.push(VElem::new(row_gutter).with_weakness(3).pack()); entries.push(reference.clone()); } seq.push( Content::sequence(entries) - .styled(ParNode::set_hanging_indent(INDENT.into())), + .styled(ParElem::set_hanging_indent(INDENT.into())), ); } @@ -154,7 +154,7 @@ impl Show for BibliographyNode { } } -impl LocalName for BibliographyNode { +impl LocalName for BibliographyElem { fn local_name(&self, lang: Lang) -> &'static str { match lang { Lang::GERMAN => "Bibliographie", @@ -196,8 +196,8 @@ impl BibliographyStyle { /// /// Display: Citation /// Category: meta -#[node(Locatable, Synthesize, Show)] -pub struct CiteNode { +#[element(Locatable, Synthesize, Show)] +pub struct CiteElem { /// The citation key. #[variadic] pub keys: Vec<EcoString>, @@ -217,7 +217,7 @@ pub struct CiteNode { pub style: Smart<CitationStyle>, } -impl Synthesize for CiteNode { +impl Synthesize for CiteElem { fn synthesize(&mut self, _: &Vt, styles: StyleChain) { self.push_supplement(self.supplement(styles)); self.push_brackets(self.brackets(styles)); @@ -225,17 +225,17 @@ impl Synthesize for CiteNode { } } -impl Show for CiteNode { +impl Show for CiteElem { fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { if !vt.introspector.init() { return Ok(Content::empty()); } let works = Works::new(vt).at(self.span())?; - let id = self.0.stable_id().unwrap(); + let location = self.0.location().unwrap(); works .citations - .get(&id) + .get(&location) .cloned() .flatten() .ok_or("bibliography does not contain this key") @@ -264,24 +264,24 @@ pub enum CitationStyle { /// Fully formatted citations and references. #[derive(Default)] struct Works { - citations: HashMap<StableId, Option<Content>>, + citations: HashMap<Location, Option<Content>>, references: Vec<(Option<Content>, Content)>, } impl Works { /// Prepare all things need to cite a work or format a bibliography. fn new(vt: &Vt) -> StrResult<Arc<Self>> { - let bibliography = BibliographyNode::find(vt.introspector)?; + let bibliography = BibliographyElem::find(vt.introspector)?; let citations = vt .introspector .query(Selector::Any(eco_vec![ - Selector::node::<RefNode>(), - Selector::node::<CiteNode>(), + RefElem::func().select(), + CiteElem::func().select(), ])) .into_iter() - .map(|node| match node.to::<RefNode>() { + .map(|elem| match elem.to::<RefElem>() { Some(reference) => reference.to_citation(StyleChain::default()), - _ => node.to::<CiteNode>().unwrap().clone(), + _ => elem.to::<CiteElem>().unwrap().clone(), }) .collect(); Ok(create(vt.world, bibliography, citations)) @@ -292,19 +292,19 @@ impl Works { #[comemo::memoize] fn create( world: Tracked<dyn World>, - bibliography: BibliographyNode, - citations: Vec<CiteNode>, + bibliography: BibliographyElem, + citations: Vec<CiteElem>, ) -> Arc<Works> { let span = bibliography.span(); let entries = load(world, &bibliography.path()).unwrap(); let style = bibliography.style(StyleChain::default()); - let bib_id = bibliography.0.stable_id().unwrap(); - let ref_id = |target: &Entry| { + let bib_location = bibliography.0.location().unwrap(); + let ref_location = |target: &Entry| { let i = entries .iter() .position(|entry| entry.key() == target.key()) .unwrap_or_default(); - bib_id.variant(i) + bib_location.variant(i) }; let mut db = Database::new(); @@ -312,7 +312,7 @@ fn create( let mut preliminary = vec![]; for citation in citations { - let cite_id = citation.0.stable_id().unwrap(); + let cite_id = citation.0.location().unwrap(); let entries = citation .keys() .into_iter() @@ -333,8 +333,8 @@ fn create( let citations = preliminary .into_iter() .map(|(citation, cited)| { - let id = citation.0.stable_id().unwrap(); - let Some(cited) = cited else { return (id, None) }; + let location = citation.0.location().unwrap(); + let Some(cited) = cited else { return (location, None) }; let mut supplement = citation.supplement(StyleChain::default()); let brackets = citation.brackets(StyleChain::default()); @@ -376,27 +376,27 @@ fn create( } if i > 0 { - content += TextNode::packed(",\u{a0}"); + content += TextElem::packed(",\u{a0}"); } // Format and link to the reference entry. content += format_display_string(&display, supplement, citation.span()) - .linked(Link::Node(ref_id(entry))); + .linked(Destination::Location(ref_location(entry))); } if brackets && len > 1 { content = match citation_style.brackets() { Brackets::None => content, Brackets::Round => { - TextNode::packed('(') + content + TextNode::packed(')') + TextElem::packed('(') + content + TextElem::packed(')') } Brackets::Square => { - TextNode::packed('[') + content + TextNode::packed(']') + TextElem::packed('[') + content + TextElem::packed(']') } }; } - (id, Some(content)) + (location, Some(content)) }) .collect(); @@ -414,15 +414,15 @@ fn create( // Make link from citation to here work. let backlink = { let mut content = Content::empty(); - content.set_stable_id(ref_id(&reference.entry)); - MetaNode::set_data(vec![Meta::Node(content)]) + content.set_location(ref_location(&reference.entry)); + MetaElem::set_data(vec![Meta::Elem(content)]) }; let prefix = reference.prefix.map(|prefix| { // Format and link to first citation. let bracketed = prefix.with_default_brackets(&*citation_style); format_display_string(&bracketed, None, span) - .linked(Link::Node(ids[reference.entry.key()])) + .linked(Destination::Location(ids[reference.entry.key()])) .styled(backlink.clone()) }); @@ -510,7 +510,7 @@ fn format_display_string( let mut content = if segment == SUPPLEMENT && supplement.is_some() { supplement.take().unwrap_or_default() } else { - TextNode::packed(segment).spanned(span) + TextElem::packed(segment).spanned(span) }; for (range, fmt) in &string.formatting { @@ -522,7 +522,7 @@ fn format_display_string( Formatting::Bold => content.strong(), Formatting::Italic => content.emph(), Formatting::Link(link) => { - content.linked(Link::Dest(Destination::Url(link.as_str().into()))) + content.linked(Destination::Url(link.as_str().into())) } }; } diff --git a/library/src/meta/context.rs b/library/src/meta/context.rs index 9e542847..dbb84812 100644 --- a/library/src/meta/context.rs +++ b/library/src/meta/context.rs @@ -10,28 +10,28 @@ pub fn locate( /// The function to call with the location. func: Func, ) -> Value { - LocateNode::new(func).pack().into() + LocateElem::new(func).pack().into() } /// Executes a `locate` call. /// /// Display: Styled /// Category: special -#[node(Locatable, Show)] -struct LocateNode { +#[element(Locatable, Show)] +struct LocateElem { /// The function to call with the location. #[required] func: Func, } -impl Show for LocateNode { +impl Show for LocateElem { fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { if !vt.introspector.init() { return Ok(Content::empty()); } - let id = self.0.stable_id().unwrap(); - Ok(self.func().call_vt(vt, [id.into()])?.display()) + let location = self.0.location().unwrap(); + Ok(self.func().call_vt(vt, [location.into()])?.display()) } } @@ -45,21 +45,21 @@ pub fn style( /// The function to call with the styles. func: Func, ) -> Value { - StyleNode::new(func).pack().into() + StyleElem::new(func).pack().into() } /// Executes a style access. /// /// Display: Style /// Category: special -#[node(Show)] -struct StyleNode { +#[element(Show)] +struct StyleElem { /// The function to call with the styles. #[required] func: Func, } -impl Show for StyleNode { +impl Show for StyleElem { fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { Ok(self.func().call_vt(vt, [styles.to_map().into()])?.display()) } diff --git a/library/src/meta/counter.rs b/library/src/meta/counter.rs index f033a04f..3cfc2cd5 100644 --- a/library/src/meta/counter.rs +++ b/library/src/meta/counter.rs @@ -6,7 +6,7 @@ use smallvec::{smallvec, SmallVec}; use typst::eval::Tracer; use super::{Numbering, NumberingPattern}; -use crate::layout::PageNode; +use crate::layout::PageElem; use crate::prelude::*; /// Count through pages, elements, and more. @@ -32,9 +32,9 @@ impl Counter { Self(key) } - /// The counter for the given node. - pub fn of(id: NodeId) -> Self { - Self::new(CounterKey::Selector(Selector::Node(id, None))) + /// The counter for the given element. + pub fn of(func: ElemFunc) -> Self { + Self::new(CounterKey::Selector(Selector::Elem(func, None))) } /// Call a method on counter. @@ -69,23 +69,23 @@ impl Counter { /// Display the current value of the counter. pub fn display(self, numbering: Numbering, both: bool) -> Content { - DisplayNode::new(self, numbering, both).pack() + DisplayElem::new(self, numbering, both).pack() } /// Get the value of the state at the given location. - pub fn at(&self, vt: &mut Vt, id: StableId) -> SourceResult<CounterState> { + pub fn at(&self, vt: &mut Vt, location: Location) -> SourceResult<CounterState> { let sequence = self.sequence(vt)?; - let offset = vt.introspector.query_before(self.selector(), id).len(); + let offset = vt.introspector.query_before(self.selector(), location).len(); let (mut state, page) = sequence[offset].clone(); if self.is_page() { - let delta = vt.introspector.page(id).get() - page.get(); + let delta = vt.introspector.page(location).get() - page.get(); state.step(NonZeroUsize::ONE, delta); } Ok(state) } /// Get the value of the state at the final location. - pub fn final_(&self, vt: &mut Vt, _: StableId) -> SourceResult<CounterState> { + pub fn final_(&self, vt: &mut Vt, _: Location) -> SourceResult<CounterState> { let sequence = self.sequence(vt)?; let (mut state, page) = sequence.last().unwrap().clone(); if self.is_page() { @@ -96,13 +96,13 @@ impl Counter { } /// Get the current and final value of the state combined in one state. - pub fn both(&self, vt: &mut Vt, id: StableId) -> SourceResult<CounterState> { + pub fn both(&self, vt: &mut Vt, location: Location) -> SourceResult<CounterState> { let sequence = self.sequence(vt)?; - let offset = vt.introspector.query_before(self.selector(), id).len(); + let offset = vt.introspector.query_before(self.selector(), location).len(); let (mut at_state, at_page) = sequence[offset].clone(); let (mut final_state, final_page) = sequence.last().unwrap().clone(); if self.is_page() { - let at_delta = vt.introspector.page(id).get() - at_page.get(); + let at_delta = vt.introspector.page(location).get() - at_page.get(); at_state.step(NonZeroUsize::ONE, at_delta); let final_delta = vt.introspector.pages().get() - final_page.get(); final_state.step(NonZeroUsize::ONE, final_delta); @@ -112,7 +112,7 @@ impl Counter { /// Produce content that performs a state update. pub fn update(self, update: CounterUpdate) -> Content { - UpdateNode::new(self, update).pack() + UpdateElem::new(self, update).pack() } /// Produce the whole sequence of counter states. @@ -148,11 +148,11 @@ impl Counter { let mut page = NonZeroUsize::ONE; let mut stops = eco_vec![(state.clone(), page)]; - for node in introspector.query(self.selector()) { + for elem in introspector.query(self.selector()) { if self.is_page() { - let id = node.stable_id().unwrap(); + let location = elem.location().unwrap(); let prev = page; - page = introspector.page(id); + page = introspector.page(location); let delta = page.get() - prev.get(); if delta > 0 { @@ -160,9 +160,9 @@ impl Counter { } } - if let Some(update) = match node.to::<UpdateNode>() { - Some(node) => Some(node.update()), - None => match node.with::<dyn Count>() { + if let Some(update) = match elem.to::<UpdateElem>() { + Some(elem) => Some(elem.update()), + None => match elem.with::<dyn Count>() { Some(countable) => countable.update(), None => Some(CounterUpdate::Step(NonZeroUsize::ONE)), }, @@ -178,10 +178,8 @@ impl Counter { /// The selector relevant for this counter's updates. fn selector(&self) -> Selector { - let mut selector = Selector::Node( - NodeId::of::<UpdateNode>(), - Some(dict! { "counter" => self.clone() }), - ); + let mut selector = + Selector::Elem(UpdateElem::func(), Some(dict! { "counter" => self.clone() })); if let CounterKey::Selector(key) = &self.0 { selector = Selector::Any(eco_vec![selector, key.clone()]); @@ -224,20 +222,16 @@ cast_from_value! { CounterKey, v: Str => Self::Str(v), label: Label => Self::Selector(Selector::Label(label)), - func: Func => { - let Some(id) = func.id() else { - return Err("this function is not selectable".into()); - }; - - if id == NodeId::of::<PageNode>() { + element: ElemFunc => { + if element == PageElem::func() { return Ok(Self::Page); } - if !Content::new(id).can::<dyn Locatable>() { - Err(eco_format!("cannot count through {}s", id.name))?; + if !Content::new(element).can::<dyn Locatable>() { + Err(eco_format!("cannot count through {}s", element.name()))?; } - Self::Selector(Selector::Node(id, None)) + Self::Selector(Selector::Elem(element, None)) } } @@ -274,9 +268,9 @@ cast_from_value! { v: Func => Self::Func(v), } -/// Nodes that have special counting behaviour. +/// Elements that have special counting behaviour. pub trait Count { - /// Get the counter update for this node. + /// Get the counter update for this element. fn update(&self) -> Option<CounterUpdate>; } @@ -342,8 +336,8 @@ cast_to_value! { /// /// Display: State /// Category: special -#[node(Locatable, Show)] -struct DisplayNode { +#[element(Locatable, Show)] +struct DisplayElem { /// The counter. #[required] counter: Counter, @@ -357,12 +351,16 @@ struct DisplayNode { both: bool, } -impl Show for DisplayNode { +impl Show for DisplayElem { fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - let id = self.0.stable_id().unwrap(); + let location = self.0.location().unwrap(); let counter = self.counter(); let numbering = self.numbering(); - let state = if self.both() { counter.both(vt, id) } else { counter.at(vt, id) }?; + let state = if self.both() { + counter.both(vt, location)? + } else { + counter.at(vt, location)? + }; state.display(vt, &numbering) } } @@ -371,8 +369,8 @@ impl Show for DisplayNode { /// /// Display: State /// Category: special -#[node(Locatable, Show)] -struct UpdateNode { +#[element(Locatable, Show)] +struct UpdateElem { /// The counter. #[required] counter: Counter, @@ -382,7 +380,7 @@ struct UpdateNode { update: CounterUpdate, } -impl Show for UpdateNode { +impl Show for UpdateElem { fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } diff --git a/library/src/meta/document.rs b/library/src/meta/document.rs index 75e78184..99e5c6b6 100644 --- a/library/src/meta/document.rs +++ b/library/src/meta/document.rs @@ -1,6 +1,4 @@ -use typst::model::StyledNode; - -use crate::layout::{LayoutRoot, PageNode}; +use crate::layout::{LayoutRoot, PageElem}; use crate::prelude::*; /// The root element of a document and its metadata. @@ -14,8 +12,8 @@ use crate::prelude::*; /// /// Display: Document /// Category: meta -#[node(LayoutRoot)] -pub struct DocumentNode { +#[element(LayoutRoot)] +pub struct DocumentElem { /// The document's title. This is often rendered as the title of the /// PDF viewer window. pub title: Option<EcoString>, @@ -29,22 +27,20 @@ pub struct DocumentNode { pub children: Vec<Content>, } -impl LayoutRoot for DocumentNode { +impl LayoutRoot for DocumentElem { /// Layout the document into a sequence of frames, one per page. fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> { let mut pages = vec![]; - for mut child in self.children() { - let map; + for mut child in &self.children() { let outer = styles; - let mut styles = outer; - if let Some(node) = child.to::<StyledNode>() { - map = node.styles(); - styles = outer.chain(&map); - child = node.body(); + let mut styles = styles; + if let Some((elem, local)) = child.to_styled() { + styles = outer.chain(local); + child = elem; } - if let Some(page) = child.to::<PageNode>() { + if let Some(page) = child.to::<PageElem>() { let fragment = page.layout(vt, styles)?; pages.extend(fragment); } else { diff --git a/library/src/meta/figure.rs b/library/src/meta/figure.rs index 6f9011b8..9251f3ef 100644 --- a/library/src/meta/figure.rs +++ b/library/src/meta/figure.rs @@ -1,9 +1,9 @@ use std::str::FromStr; use super::{Count, Counter, CounterUpdate, LocalName, Numbering, NumberingPattern}; -use crate::layout::{BlockNode, VNode}; +use crate::layout::{BlockElem, VElem}; use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; /// A figure with an optional caption. /// @@ -23,8 +23,8 @@ use crate::text::TextNode; /// /// Display: Figure /// Category: meta -#[node(Locatable, Synthesize, Count, Show, LocalName)] -pub struct FigureNode { +#[element(Locatable, Synthesize, Count, Show, LocalName)] +pub struct FigureElem { /// The content of the figure. Often, an [image]($func/image). #[required] pub body: Content, @@ -42,32 +42,32 @@ pub struct FigureNode { pub gap: Length, } -impl Synthesize for FigureNode { +impl Synthesize for FigureElem { fn synthesize(&mut self, _: &Vt, styles: StyleChain) { self.push_numbering(self.numbering(styles)); } } -impl Show for FigureNode { +impl Show for FigureElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body(); if let Some(mut caption) = self.caption(styles) { if let Some(numbering) = self.numbering(styles) { - let name = self.local_name(TextNode::lang_in(styles)); - caption = TextNode::packed(eco_format!("{name}\u{a0}")) - + Counter::of(Self::id()) + let name = self.local_name(TextElem::lang_in(styles)); + caption = TextElem::packed(eco_format!("{name}\u{a0}")) + + Counter::of(Self::func()) .display(numbering, false) .spanned(self.span()) - + TextNode::packed(": ") + + TextElem::packed(": ") + caption; } - realized += VNode::weak(self.gap(styles).into()).pack(); + realized += VElem::weak(self.gap(styles).into()).pack(); realized += caption; } - Ok(BlockNode::new() + Ok(BlockElem::new() .with_body(Some(realized)) .with_breakable(false) .pack() @@ -75,7 +75,7 @@ impl Show for FigureNode { } } -impl Count for FigureNode { +impl Count for FigureElem { fn update(&self) -> Option<CounterUpdate> { self.numbering(StyleChain::default()) .is_some() @@ -83,7 +83,7 @@ impl Count for FigureNode { } } -impl LocalName for FigureNode { +impl LocalName for FigureElem { fn local_name(&self, lang: Lang) -> &'static str { match lang { Lang::GERMAN => "Abbildung", diff --git a/library/src/meta/heading.rs b/library/src/meta/heading.rs index 61605e67..1eaca187 100644 --- a/library/src/meta/heading.rs +++ b/library/src/meta/heading.rs @@ -1,10 +1,10 @@ use typst::font::FontWeight; use super::{Counter, CounterUpdate, LocalName, Numbering}; -use crate::layout::{BlockNode, HNode, VNode}; +use crate::layout::{BlockElem, HElem, VElem}; use crate::meta::Count; use crate::prelude::*; -use crate::text::{TextNode, TextSize}; +use crate::text::{TextElem, TextSize}; /// A section heading. /// @@ -41,8 +41,8 @@ use crate::text::{TextNode, TextSize}; /// /// Display: Heading /// Category: meta -#[node(Locatable, Synthesize, Count, Show, Finalize, LocalName)] -pub struct HeadingNode { +#[element(Locatable, Synthesize, Count, Show, Finalize, LocalName)] +pub struct HeadingElem { /// The logical nesting depth of the heading, starting from one. #[default(NonZeroUsize::ONE)] pub level: NonZeroUsize, @@ -79,7 +79,7 @@ pub struct HeadingNode { pub body: Content, } -impl Synthesize for HeadingNode { +impl Synthesize for HeadingElem { fn synthesize(&mut self, _: &Vt, styles: StyleChain) { self.push_level(self.level(styles)); self.push_numbering(self.numbering(styles)); @@ -87,20 +87,21 @@ impl Synthesize for HeadingNode { } } -impl Show for HeadingNode { +impl Show for HeadingElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body(); if let Some(numbering) = self.numbering(styles) { - realized = - Counter::of(Self::id()).display(numbering, false).spanned(self.span()) - + HNode::new(Em::new(0.3).into()).with_weak(true).pack() - + realized; + realized = Counter::of(Self::func()) + .display(numbering, false) + .spanned(self.span()) + + HElem::new(Em::new(0.3).into()).with_weak(true).pack() + + realized; } - Ok(BlockNode::new().with_body(Some(realized)).pack()) + Ok(BlockElem::new().with_body(Some(realized)).pack()) } } -impl Finalize for HeadingNode { +impl Finalize for HeadingElem { fn finalize(&self, realized: Content, styles: StyleChain) -> Content { let level = self.level(styles).get(); let scale = match level { @@ -113,17 +114,17 @@ impl Finalize for HeadingNode { let above = Em::new(if level == 1 { 1.8 } else { 1.44 }) / scale; let below = Em::new(0.75) / scale; - let mut map = StyleMap::new(); - map.set(TextNode::set_size(TextSize(size.into()))); - map.set(TextNode::set_weight(FontWeight::BOLD)); - map.set(BlockNode::set_above(VNode::block_around(above.into()))); - map.set(BlockNode::set_below(VNode::block_around(below.into()))); - map.set(BlockNode::set_sticky(true)); - realized.styled_with_map(map) + let mut styles = Styles::new(); + styles.set(TextElem::set_size(TextSize(size.into()))); + styles.set(TextElem::set_weight(FontWeight::BOLD)); + styles.set(BlockElem::set_above(VElem::block_around(above.into()))); + styles.set(BlockElem::set_below(VElem::block_around(below.into()))); + styles.set(BlockElem::set_sticky(true)); + realized.styled_with_map(styles) } } -impl Count for HeadingNode { +impl Count for HeadingElem { fn update(&self) -> Option<CounterUpdate> { self.numbering(StyleChain::default()) .is_some() @@ -132,11 +133,11 @@ impl Count for HeadingNode { } cast_from_value! { - HeadingNode, + HeadingElem, v: Content => v.to::<Self>().ok_or("expected heading")?.clone(), } -impl LocalName for HeadingNode { +impl LocalName for HeadingElem { fn local_name(&self, lang: Lang) -> &'static str { match lang { Lang::GERMAN => "Abschnitt", diff --git a/library/src/meta/link.rs b/library/src/meta/link.rs index e9b8bcc6..c82a7443 100644 --- a/library/src/meta/link.rs +++ b/library/src/meta/link.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use crate::text::{Hyphenate, TextNode}; +use crate::text::{Hyphenate, TextElem}; /// Link to a URL or another location in the document. /// @@ -25,19 +25,20 @@ use crate::text::{Hyphenate, TextNode}; /// /// Display: Link /// Category: meta -#[node(Show, Finalize)] -pub struct LinkNode { +#[element(Show, Finalize)] +pub struct LinkElem { /// The destination the link points to. /// - /// - To link to web pages, `dest` should be a valid URL string. If the URL is - /// in the `mailto:` or `tel:` scheme and the `body` parameter is omitted, - /// the email address or phone number will be the link's body, without the - /// scheme. + /// - To link to web pages, `dest` should be a valid URL string. If the URL + /// is in the `mailto:` or `tel:` scheme and the `body` parameter is + /// omitted, the email address or phone number will be the link's body, + /// without the scheme. /// - /// - To link to another part of the document, `dest` must contain a - /// dictionary with a `page` key of type `integer` and `x` and `y` - /// coordinates of type `length`. Pages are counted from one, and the - /// coordinates are relative to the page's top left corner. + /// - To link to another part of the document, `dest` can take one of two + /// forms: A [`location`]($func/locate) or a dictionary with a `page` key + /// of type `integer` and `x` and `y` coordinates of type `length`. Pages + /// are counted from one, and the coordinates are relative to the page's + /// top left corner. /// /// ```example /// #link("mailto:hello@typst.app") \ @@ -45,7 +46,6 @@ pub struct LinkNode { /// Go to top /// ] /// ``` - /// #[required] #[parse( let dest = args.expect::<Destination>("destination")?; @@ -64,30 +64,30 @@ pub struct LinkNode { Some(body) => body, None => body_from_url(url), }, - Destination::Internal(_) => args.expect("body")?, + _ => args.expect("body")?, })] pub body: Content, } -impl LinkNode { - /// Create a link node from a URL with its bare text. +impl LinkElem { + /// Create a link element from a URL with its bare text. pub fn from_url(url: EcoString) -> Self { let body = body_from_url(&url); Self::new(Destination::Url(url), body) } } -impl Show for LinkNode { +impl Show for LinkElem { fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { Ok(self.body()) } } -impl Finalize for LinkNode { +impl Finalize for LinkElem { fn finalize(&self, realized: Content, _: StyleChain) -> Content { realized - .linked(Link::Dest(self.dest())) - .styled(TextNode::set_hyphenate(Hyphenate(Smart::Custom(false)))) + .linked(self.dest()) + .styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))) } } @@ -97,5 +97,5 @@ fn body_from_url(url: &EcoString) -> Content { text = text.trim_start_matches(prefix); } let shorter = text.len() < url.len(); - TextNode::packed(if shorter { text.into() } else { url.clone() }) + TextElem::packed(if shorter { text.into() } else { url.clone() }) } diff --git a/library/src/meta/outline.rs b/library/src/meta/outline.rs index a0a23897..002d757e 100644 --- a/library/src/meta/outline.rs +++ b/library/src/meta/outline.rs @@ -1,7 +1,7 @@ -use super::{Counter, HeadingNode, LocalName}; -use crate::layout::{BoxNode, HNode, HideNode, ParbreakNode, RepeatNode}; +use super::{Counter, HeadingElem, LocalName}; +use crate::layout::{BoxElem, HElem, HideElem, ParbreakElem, RepeatElem}; use crate::prelude::*; -use crate::text::{LinebreakNode, SpaceNode, TextNode}; +use crate::text::{LinebreakElem, SpaceElem, TextElem}; /// A section outline / table of contents. /// @@ -22,8 +22,8 @@ use crate::text::{LinebreakNode, SpaceNode, TextNode}; /// /// Display: Outline /// Category: meta -#[node(Show, LocalName)] -pub struct OutlineNode { +#[element(Show, LocalName)] +pub struct OutlineElem { /// The title of the outline. /// /// - When set to `{auto}`, an appropriate title for the [text @@ -65,21 +65,21 @@ pub struct OutlineNode { /// /// = A New Beginning /// ``` - #[default(Some(RepeatNode::new(TextNode::packed(".")).pack()))] + #[default(Some(RepeatElem::new(TextElem::packed(".")).pack()))] pub fill: Option<Content>, } -impl Show for OutlineNode { +impl Show for OutlineElem { fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - let mut seq = vec![ParbreakNode::new().pack()]; + let mut seq = vec![ParbreakElem::new().pack()]; if let Some(title) = self.title(styles) { let title = title.clone().unwrap_or_else(|| { - TextNode::packed(self.local_name(TextNode::lang_in(styles))) + TextElem::packed(self.local_name(TextElem::lang_in(styles))) .spanned(self.span()) }); seq.push( - HeadingNode::new(title) + HeadingElem::new(title) .with_level(NonZeroUsize::ONE) .with_numbering(None) .with_outlined(false) @@ -90,15 +90,15 @@ impl Show for OutlineNode { let indent = self.indent(styles); let depth = self.depth(styles); - let mut ancestors: Vec<&HeadingNode> = vec![]; - let nodes = vt.introspector.query(Selector::Node( - NodeId::of::<HeadingNode>(), + let mut ancestors: Vec<&HeadingElem> = vec![]; + let elems = vt.introspector.query(Selector::Elem( + HeadingElem::func(), Some(dict! { "outlined" => true }), )); - for node in &nodes { - let heading = node.to::<HeadingNode>().unwrap(); - let stable_id = heading.0.stable_id().unwrap(); + for elem in &elems { + let heading = elem.to::<HeadingElem>().unwrap(); + let location = heading.0.location().unwrap(); if !heading.outlined(StyleChain::default()) { continue; } @@ -120,60 +120,60 @@ impl Show for OutlineNode { let mut hidden = Content::empty(); for ancestor in &ancestors { if let Some(numbering) = ancestor.numbering(StyleChain::default()) { - let numbers = Counter::of(HeadingNode::id()) - .at(vt, ancestor.0.stable_id().unwrap())? + let numbers = Counter::of(HeadingElem::func()) + .at(vt, ancestor.0.location().unwrap())? .display(vt, &numbering)?; - hidden += numbers + SpaceNode::new().pack(); + hidden += numbers + SpaceElem::new().pack(); }; } if !ancestors.is_empty() { - seq.push(HideNode::new(hidden).pack()); - seq.push(SpaceNode::new().pack()); + seq.push(HideElem::new(hidden).pack()); + seq.push(SpaceElem::new().pack()); } } // Format the numbering. let mut start = heading.body(); if let Some(numbering) = heading.numbering(StyleChain::default()) { - let numbers = Counter::of(HeadingNode::id()) - .at(vt, stable_id)? + let numbers = Counter::of(HeadingElem::func()) + .at(vt, location)? .display(vt, &numbering)?; - start = numbers + SpaceNode::new().pack() + start; + start = numbers + SpaceElem::new().pack() + start; }; // Add the numbering and section name. - seq.push(start.linked(Link::Node(stable_id))); + seq.push(start.linked(Destination::Location(location))); // Add filler symbols between the section name and page number. if let Some(filler) = self.fill(styles) { - seq.push(SpaceNode::new().pack()); + seq.push(SpaceElem::new().pack()); seq.push( - BoxNode::new() + BoxElem::new() .with_body(Some(filler.clone())) .with_width(Fr::one().into()) .pack(), ); - seq.push(SpaceNode::new().pack()); + seq.push(SpaceElem::new().pack()); } else { - seq.push(HNode::new(Fr::one().into()).pack()); + seq.push(HElem::new(Fr::one().into()).pack()); } // Add the page number and linebreak. - let page = vt.introspector.page(stable_id); - let end = TextNode::packed(eco_format!("{page}")); - seq.push(end.linked(Link::Node(stable_id))); - seq.push(LinebreakNode::new().pack()); + let page = vt.introspector.page(location); + let end = TextElem::packed(eco_format!("{page}")); + seq.push(end.linked(Destination::Location(location))); + seq.push(LinebreakElem::new().pack()); ancestors.push(heading); } - seq.push(ParbreakNode::new().pack()); + seq.push(ParbreakElem::new().pack()); Ok(Content::sequence(seq)) } } -impl LocalName for OutlineNode { +impl LocalName for OutlineElem { fn local_name(&self, lang: Lang) -> &'static str { match lang { Lang::GERMAN => "Inhaltsverzeichnis", diff --git a/library/src/meta/query.rs b/library/src/meta/query.rs index 23e310fe..94b25cbc 100644 --- a/library/src/meta/query.rs +++ b/library/src/meta/query.rs @@ -11,24 +11,24 @@ pub fn query( target: Target, /// The location. #[external] - location: StableId, + location: Location, /// The location before which to query. #[named] #[external] - before: StableId, + before: Location, /// The location after which to query. #[named] #[external] - after: StableId, + after: Location, ) -> Value { let selector = target.0; let introspector = vm.vt.introspector; - let elements = if let Some(id) = args.named("before")? { - introspector.query_before(selector, id) - } else if let Some(id) = args.named("after")? { - introspector.query_after(selector, id) + let elements = if let Some(location) = args.named("before")? { + introspector.query_before(selector, location) + } else if let Some(location) = args.named("after")? { + introspector.query_after(selector, location) } else { - let _: StableId = args.expect("id")?; + let _: Location = args.expect("location")?; introspector.query(selector) }; elements.into() @@ -40,15 +40,11 @@ struct Target(Selector); cast_from_value! { Target, label: Label => Self(Selector::Label(label)), - func: Func => { - let Some(id) = func.id() else { - return Err("this function is not selectable".into()); - }; - - if !Content::new(id).can::<dyn Locatable>() { - Err(eco_format!("cannot query for {}s", id.name))?; + element: ElemFunc => { + if !Content::new(element).can::<dyn Locatable>() { + Err(eco_format!("cannot query for {}s", element.name()))?; } - Self(Selector::Node(id, None)) + Self(Selector::Elem(element, None)) } } diff --git a/library/src/meta/reference.rs b/library/src/meta/reference.rs index 000080d8..6e794d2d 100644 --- a/library/src/meta/reference.rs +++ b/library/src/meta/reference.rs @@ -1,6 +1,6 @@ -use super::{BibliographyNode, CiteNode, Counter, LocalName, Numbering}; +use super::{BibliographyElem, CiteElem, Counter, LocalName, Numbering}; use crate::prelude::*; -use crate::text::TextNode; +use crate::text::TextElem; /// A reference to a label. /// @@ -35,8 +35,8 @@ use crate::text::TextNode; /// /// Display: Reference /// Category: meta -#[node(Locatable, Show)] -pub struct RefNode { +#[element(Locatable, Show)] +pub struct RefElem { /// The target label that should be referenced. #[required] pub target: Label, @@ -63,7 +63,7 @@ pub struct RefNode { pub supplement: Smart<Option<Supplement>>, } -impl Show for RefNode { +impl Show for RefElem { fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { if !vt.introspector.init() { return Ok(Content::empty()); @@ -72,7 +72,7 @@ impl Show for RefNode { let target = self.target(); let matches = vt.introspector.query(Selector::Label(self.target())); - if BibliographyNode::has(vt, &target.0) { + if BibliographyElem::has(vt, &target.0) { if !matches.is_empty() { bail!(self.span(), "label occurs in the document and its bibliography"); } @@ -80,7 +80,7 @@ impl Show for RefNode { return self.to_citation(styles).show(vt, styles); } - let [node] = matches.as_slice() else { + let [elem] = matches.as_slice() else { bail!(self.span(), if matches.is_empty() { "label does not exist in the document" } else { @@ -88,50 +88,50 @@ impl Show for RefNode { }); }; - if !node.can::<dyn Locatable>() { - bail!(self.span(), "cannot reference {}", node.id().name); + if !elem.can::<dyn Locatable>() { + bail!(self.span(), "cannot reference {}", elem.func().name()); } let supplement = self.supplement(styles); let mut supplement = match supplement { - Smart::Auto => node + Smart::Auto => elem .with::<dyn LocalName>() - .map(|node| node.local_name(TextNode::lang_in(styles))) - .map(TextNode::packed) + .map(|elem| elem.local_name(TextElem::lang_in(styles))) + .map(TextElem::packed) .unwrap_or_default(), Smart::Custom(None) => Content::empty(), Smart::Custom(Some(Supplement::Content(content))) => content.clone(), Smart::Custom(Some(Supplement::Func(func))) => { - func.call_vt(vt, [node.clone().into()])?.display() + func.call_vt(vt, [elem.clone().into()])?.display() } }; if !supplement.is_empty() { - supplement += TextNode::packed('\u{a0}'); + supplement += TextElem::packed('\u{a0}'); } - let Some(numbering) = node.cast_field::<Numbering>("numbering") else { + let Some(numbering) = elem.cast_field::<Numbering>("numbering") else { bail!(self.span(), "only numbered elements can be referenced"); }; - let numbers = Counter::of(node.id()) - .at(vt, node.stable_id().unwrap())? + let numbers = Counter::of(elem.func()) + .at(vt, elem.location().unwrap())? .display(vt, &numbering.trimmed())?; - Ok((supplement + numbers).linked(Link::Node(node.stable_id().unwrap()))) + Ok((supplement + numbers).linked(Destination::Location(elem.location().unwrap()))) } } -impl RefNode { +impl RefElem { /// Turn the rference into a citation. - pub fn to_citation(&self, styles: StyleChain) -> CiteNode { - let mut node = CiteNode::new(vec![self.target().0]); - node.push_supplement(match self.supplement(styles) { + pub fn to_citation(&self, styles: StyleChain) -> CiteElem { + let mut elem = CiteElem::new(vec![self.target().0]); + elem.push_supplement(match self.supplement(styles) { Smart::Custom(Some(Supplement::Content(content))) => Some(content), _ => None, }); - node.0.set_stable_id(self.0.stable_id().unwrap()); - node + elem.0.set_location(self.0.location().unwrap()); + elem } } diff --git a/library/src/meta/state.rs b/library/src/meta/state.rs index b19a2671..090f1ccf 100644 --- a/library/src/meta/state.rs +++ b/library/src/meta/state.rs @@ -52,25 +52,25 @@ impl State { /// Display the current value of the state. pub fn display(self, func: Option<Func>) -> Content { - DisplayNode::new(self, func).pack() + DisplayElem::new(self, func).pack() } /// Get the value of the state at the given location. - pub fn at(self, vt: &mut Vt, id: StableId) -> SourceResult<Value> { + pub fn at(self, vt: &mut Vt, location: Location) -> SourceResult<Value> { let sequence = self.sequence(vt)?; - let offset = vt.introspector.query_before(self.selector(), id).len(); + let offset = vt.introspector.query_before(self.selector(), location).len(); Ok(sequence[offset].clone()) } /// Get the value of the state at the final location. - pub fn final_(self, vt: &mut Vt, _: StableId) -> SourceResult<Value> { + pub fn final_(self, vt: &mut Vt, _: Location) -> SourceResult<Value> { let sequence = self.sequence(vt)?; Ok(sequence.last().unwrap().clone()) } /// Produce content that performs a state update. pub fn update(self, update: StateUpdate) -> Content { - UpdateNode::new(self, update).pack() + UpdateElem::new(self, update).pack() } /// Produce the whole sequence of states. @@ -99,9 +99,9 @@ impl State { let mut state = self.init.clone(); let mut stops = eco_vec![state.clone()]; - for node in introspector.query(self.selector()) { - let node = node.to::<UpdateNode>().unwrap(); - match node.update() { + for elem in introspector.query(self.selector()) { + let elem = elem.to::<UpdateElem>().unwrap(); + match elem.update() { StateUpdate::Set(value) => state = value, StateUpdate::Func(func) => state = func.call_vt(&mut vt, [state])?, } @@ -113,10 +113,7 @@ impl State { /// The selector for this state's updates. fn selector(&self) -> Selector { - Selector::Node( - NodeId::of::<UpdateNode>(), - Some(dict! { "state" => self.clone() }), - ) + Selector::Elem(UpdateElem::func(), Some(dict! { "state" => self.clone() })) } } @@ -159,8 +156,8 @@ cast_from_value! { /// /// Display: State /// Category: special -#[node(Locatable, Show)] -struct DisplayNode { +#[element(Locatable, Show)] +struct DisplayElem { /// The state. #[required] state: State, @@ -170,10 +167,10 @@ struct DisplayNode { func: Option<Func>, } -impl Show for DisplayNode { +impl Show for DisplayElem { fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - let id = self.0.stable_id().unwrap(); - let value = self.state().at(vt, id)?; + let location = self.0.location().unwrap(); + let value = self.state().at(vt, location)?; Ok(match self.func() { Some(func) => func.call_vt(vt, [value])?.display(), None => value.display(), @@ -185,8 +182,8 @@ impl Show for DisplayNode { /// /// Display: State /// Category: special -#[node(Locatable, Show)] -struct UpdateNode { +#[element(Locatable, Show)] +struct UpdateElem { /// The state. #[required] state: State, @@ -196,7 +193,7 @@ struct UpdateNode { update: StateUpdate, } -impl Show for UpdateNode { +impl Show for UpdateElem { fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } diff --git a/library/src/prelude.rs b/library/src/prelude.rs index 55e5f17b..4c83cf31 100644 --- a/library/src/prelude.rs +++ b/library/src/prelude.rs @@ -22,9 +22,9 @@ pub use typst::eval::{ pub use typst::geom::*; #[doc(no_inline)] pub use typst::model::{ - node, Behave, Behaviour, Construct, Content, Finalize, Fold, Introspector, Label, - Locatable, MetaNode, Node, NodeId, Resolve, Selector, Set, Show, StabilityProvider, - StableId, StyleChain, StyleMap, StyleVec, Synthesize, Unlabellable, Vt, + element, Behave, Behaviour, Construct, Content, ElemFunc, Element, Finalize, Fold, + Introspector, Label, Locatable, Location, MetaElem, Resolve, Selector, Set, Show, + StabilityProvider, StyleChain, StyleVec, Styles, Synthesize, Unlabellable, Vt, }; #[doc(no_inline)] pub use typst::syntax::{Span, Spanned}; @@ -36,4 +36,4 @@ pub use typst::World; #[doc(no_inline)] pub use crate::layout::{Fragment, Layout, Regions}; #[doc(no_inline)] -pub use crate::shared::{ContentExt, StyleMapExt}; +pub use crate::shared::{ContentExt, StylesExt}; diff --git a/library/src/shared/behave.rs b/library/src/shared/behave.rs index eff41c0b..6a1aa127 100644 --- a/library/src/shared/behave.rs +++ b/library/src/shared/behave.rs @@ -1,14 +1,15 @@ -//! Node interaction. +//! Element interaction. use typst::model::{Behave, Behaviour, Content, StyleChain, StyleVec, StyleVecBuilder}; -/// A wrapper around a [`StyleVecBuilder`] that allows items to interact. +/// A wrapper around a [`StyleVecBuilder`] that allows elements to interact. #[derive(Debug)] pub struct BehavedBuilder<'a> { /// The internal builder. builder: StyleVecBuilder<'a, Content>, - /// Staged weak and ignorant items that we can't yet commit to the builder. - /// The option is `Some(_)` for weak items and `None` for ignorant items. + /// Staged weak and ignorant elements that we can't yet commit to the + /// builder. The option is `Some(_)` for weak elements and `None` for + /// ignorant elements. staged: Vec<(Content, Behaviour, StyleChain<'a>)>, /// What the last non-ignorant item was. last: Behaviour, @@ -29,7 +30,7 @@ impl<'a> BehavedBuilder<'a> { self.builder.is_empty() && self.staged.is_empty() } - /// Whether the builder is empty except for some weak items that will + /// Whether the builder is empty except for some weak elements that will /// probably collapse. pub fn is_basically_empty(&self) -> bool { self.builder.is_empty() @@ -40,15 +41,15 @@ impl<'a> BehavedBuilder<'a> { } /// Push an item into the sequence. - pub fn push(&mut self, item: Content, styles: StyleChain<'a>) { - let interaction = item + pub fn push(&mut self, elem: Content, styles: StyleChain<'a>) { + let interaction = elem .with::<dyn Behave>() .map_or(Behaviour::Supportive, Behave::behaviour); match interaction { Behaviour::Weak(level) => { if matches!(self.last, Behaviour::Weak(_)) { - let item = item.with::<dyn Behave>().unwrap(); + let item = elem.with::<dyn Behave>().unwrap(); let i = self.staged.iter().position(|prev| { let Behaviour::Weak(prev_level) = prev.1 else { return false }; level < prev_level @@ -59,29 +60,29 @@ impl<'a> BehavedBuilder<'a> { } if self.last != Behaviour::Destructive { - self.staged.push((item, interaction, styles)); + self.staged.push((elem, interaction, styles)); self.last = interaction; } } Behaviour::Supportive => { self.flush(true); - self.builder.push(item, styles); + self.builder.push(elem, styles); self.last = interaction; } Behaviour::Destructive => { self.flush(false); - self.builder.push(item, styles); + self.builder.push(elem, styles); self.last = interaction; } Behaviour::Ignorant => { - self.staged.push((item, interaction, styles)); + self.staged.push((elem, interaction, styles)); } } } - /// Iterate over the contained items. - pub fn items(&self) -> impl DoubleEndedIterator<Item = &Content> { - self.builder.items().chain(self.staged.iter().map(|(item, ..)| item)) + /// Iterate over the contained elements. + pub fn elems(&self) -> impl DoubleEndedIterator<Item = &Content> { + self.builder.elems().chain(self.staged.iter().map(|(item, ..)| item)) } /// Return the finish style vec and the common prefix chain. @@ -90,7 +91,7 @@ impl<'a> BehavedBuilder<'a> { self.builder.finish() } - /// Push the staged items, filtering out weak items if `supportive` is + /// Push the staged elements, filtering out weak elements if `supportive` is /// false. fn flush(&mut self, supportive: bool) { for (item, interaction, styles) in self.staged.drain(..) { diff --git a/library/src/shared/ext.rs b/library/src/shared/ext.rs index 14674c9d..72a82749 100644 --- a/library/src/shared/ext.rs +++ b/library/src/shared/ext.rs @@ -1,8 +1,8 @@ //! Extension traits. -use crate::layout::{AlignNode, MoveNode, PadNode}; +use crate::layout::{AlignElem, MoveElem, PadElem}; use crate::prelude::*; -use crate::text::{EmphNode, FontFamily, FontList, StrongNode, TextNode, UnderlineNode}; +use crate::text::{EmphElem, FontFamily, FontList, StrongElem, TextElem, UnderlineElem}; /// Additional methods on content. pub trait ContentExt { @@ -16,7 +16,7 @@ pub trait ContentExt { fn underlined(self) -> Self; /// Link the content somewhere. - fn linked(self, link: Link) -> Self; + fn linked(self, dest: Destination) -> Self; /// Set alignments for this content. fn aligned(self, aligns: Axes<Option<GenAlign>>) -> Self; @@ -30,27 +30,27 @@ pub trait ContentExt { impl ContentExt for Content { fn strong(self) -> Self { - StrongNode::new(self).pack() + StrongElem::new(self).pack() } fn emph(self) -> Self { - EmphNode::new(self).pack() + EmphElem::new(self).pack() } fn underlined(self) -> Self { - UnderlineNode::new(self).pack() + UnderlineElem::new(self).pack() } - fn linked(self, link: Link) -> Self { - self.styled(MetaNode::set_data(vec![Meta::Link(link)])) + fn linked(self, dest: Destination) -> Self { + self.styled(MetaElem::set_data(vec![Meta::Link(dest)])) } fn aligned(self, aligns: Axes<Option<GenAlign>>) -> Self { - self.styled(AlignNode::set_alignment(aligns)) + self.styled(AlignElem::set_alignment(aligns)) } fn padded(self, padding: Sides<Rel<Length>>) -> Self { - PadNode::new(self) + PadElem::new(self) .with_left(padding.left) .with_top(padding.top) .with_right(padding.right) @@ -59,22 +59,22 @@ impl ContentExt for Content { } fn moved(self, delta: Axes<Rel<Length>>) -> Self { - MoveNode::new(self).with_dx(delta.x).with_dy(delta.y).pack() + MoveElem::new(self).with_dx(delta.x).with_dy(delta.y).pack() } } -/// Additional methods for style maps. -pub trait StyleMapExt { +/// Additional methods for style lists. +pub trait StylesExt { /// Set a font family composed of a preferred family and existing families /// from a style chain. fn set_family(&mut self, preferred: FontFamily, existing: StyleChain); } -impl StyleMapExt for StyleMap { +impl StylesExt for Styles { fn set_family(&mut self, preferred: FontFamily, existing: StyleChain) { - self.set(TextNode::set_font(FontList( + self.set(TextElem::set_font(FontList( std::iter::once(preferred) - .chain(TextNode::font_in(existing)) + .chain(TextElem::font_in(existing)) .collect(), ))); } diff --git a/library/src/symbols/emoji.rs b/library/src/symbols/emoji.rs index 07c7004b..5db3a799 100644 --- a/library/src/symbols/emoji.rs +++ b/library/src/symbols/emoji.rs @@ -993,7 +993,7 @@ const EMOJI: &[(&'static str, Symbol)] = symbols! { piano: '🎹', pick: '⛏', pie: '🥧', - pig: ['🐖', face: '🐷', node: '🐽'], + pig: ['🐖', face: '🐷', nose: '🐽'], pill: '💊', pin: ['📌', round: '📍'], pinata: '🪅', diff --git a/library/src/text/deco.rs b/library/src/text/deco.rs index a29564f3..90a6ca85 100644 --- a/library/src/text/deco.rs +++ b/library/src/text/deco.rs @@ -1,7 +1,7 @@ use kurbo::{BezPath, Line, ParamCurve}; use ttf_parser::{GlyphId, OutlineBuilder}; -use super::TextNode; +use super::TextElem; use crate::prelude::*; /// Underline text. @@ -13,8 +13,8 @@ use crate::prelude::*; /// /// Display: Underline /// Category: text -#[node(Show)] -pub struct UnderlineNode { +#[element(Show)] +pub struct UnderlineElem { /// How to stroke the line. The text color and thickness are read from the /// font tables if `{auto}`. /// @@ -65,9 +65,9 @@ pub struct UnderlineNode { pub body: Content, } -impl Show for UnderlineNode { +impl Show for UnderlineElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(self.body().styled(TextNode::set_deco(Decoration { + Ok(self.body().styled(TextElem::set_deco(Decoration { line: DecoLine::Underline, stroke: self.stroke(styles).unwrap_or_default(), offset: self.offset(styles), @@ -86,8 +86,8 @@ impl Show for UnderlineNode { /// /// Display: Overline /// Category: text -#[node(Show)] -pub struct OverlineNode { +#[element(Show)] +pub struct OverlineElem { /// How to stroke the line. The text color and thickness are read from the /// font tables if `{auto}`. /// @@ -144,9 +144,9 @@ pub struct OverlineNode { pub body: Content, } -impl Show for OverlineNode { +impl Show for OverlineElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(self.body().styled(TextNode::set_deco(Decoration { + Ok(self.body().styled(TextElem::set_deco(Decoration { line: DecoLine::Overline, stroke: self.stroke(styles).unwrap_or_default(), offset: self.offset(styles), @@ -165,8 +165,8 @@ impl Show for OverlineNode { /// /// Display: Strikethrough /// Category: text -#[node(Show)] -pub struct StrikeNode { +#[element(Show)] +pub struct StrikeElem { /// How to stroke the line. The text color and thickness are read from the /// font tables if `{auto}`. /// @@ -208,9 +208,9 @@ pub struct StrikeNode { pub body: Content, } -impl Show for StrikeNode { +impl Show for StrikeElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(self.body().styled(TextNode::set_deco(Decoration { + Ok(self.body().styled(TextElem::set_deco(Decoration { line: DecoLine::Strikethrough, stroke: self.stroke(styles).unwrap_or_default(), offset: self.offset(styles), @@ -255,7 +255,7 @@ pub enum DecoLine { pub(super) fn decorate( frame: &mut Frame, deco: &Decoration, - text: &Text, + text: &TextItem, shift: Abs, pos: Point, width: Abs, @@ -285,7 +285,7 @@ pub(super) fn decorate( if target.x >= min_width || !deco.evade { let shape = Geometry::Line(target).stroked(stroke); - frame.push(origin, Element::Shape(shape, Span::detached())); + frame.push(origin, FrameItem::Shape(shape, Span::detached())); } }; diff --git a/library/src/text/misc.rs b/library/src/text/misc.rs index 5a5c8514..e1d9c0f2 100644 --- a/library/src/text/misc.rs +++ b/library/src/text/misc.rs @@ -1,20 +1,20 @@ -use super::TextNode; +use super::TextElem; use crate::prelude::*; /// A text space. /// /// Display: Space /// Category: text -#[node(Unlabellable, Behave)] -pub struct SpaceNode {} +#[element(Unlabellable, Behave)] +pub struct SpaceElem {} -impl Behave for SpaceNode { +impl Behave for SpaceElem { fn behaviour(&self) -> Behaviour { Behaviour::Weak(2) } } -impl Unlabellable for SpaceNode {} +impl Unlabellable for SpaceElem {} /// Inserts a line break. /// @@ -36,8 +36,8 @@ impl Unlabellable for SpaceNode {} /// /// Display: Line Break /// Category: text -#[node(Behave)] -pub struct LinebreakNode { +#[element(Behave)] +pub struct LinebreakElem { /// Whether to justify the line before the break. /// /// This is useful if you found a better line break opportunity in your @@ -55,7 +55,7 @@ pub struct LinebreakNode { pub justify: bool, } -impl Behave for LinebreakNode { +impl Behave for LinebreakElem { fn behaviour(&self) -> Behaviour { Behaviour::Destructive } @@ -82,8 +82,8 @@ impl Behave for LinebreakNode { /// /// Display: Strong Emphasis /// Category: text -#[node(Show)] -pub struct StrongNode { +#[element(Show)] +pub struct StrongElem { /// The delta to apply on the font weight. /// /// ```example @@ -98,9 +98,9 @@ pub struct StrongNode { pub body: Content, } -impl Show for StrongNode { +impl Show for StrongElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(self.body().styled(TextNode::set_delta(Delta(self.delta(styles))))) + Ok(self.body().styled(TextElem::set_delta(Delta(self.delta(styles))))) } } @@ -151,16 +151,16 @@ impl Fold for Delta { /// /// Display: Emphasis /// Category: text -#[node(Show)] -pub struct EmphNode { +#[element(Show)] +pub struct EmphElem { /// The content to emphasize. #[required] pub body: Content, } -impl Show for EmphNode { +impl Show for EmphElem { fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(self.body().styled(TextNode::set_emph(Toggle))) + Ok(self.body().styled(TextElem::set_emph(Toggle))) } } @@ -229,7 +229,7 @@ pub fn upper( fn case(text: ToCase, case: Case) -> Value { match text { ToCase::Str(v) => Value::Str(case.apply(&v).into()), - ToCase::Content(v) => Value::Content(v.styled(TextNode::set_case(Some(case)))), + ToCase::Content(v) => Value::Content(v.styled(TextElem::set_case(Some(case)))), } } @@ -295,7 +295,7 @@ pub fn smallcaps( /// The text to display to small capitals. body: Content, ) -> Value { - Value::Content(body.styled(TextNode::set_smallcaps(true))) + Value::Content(body.styled(TextElem::set_smallcaps(true))) } /// Create blind text. diff --git a/library/src/text/mod.rs b/library/src/text/mod.rs index 845ffe29..16268aad 100644 --- a/library/src/text/mod.rs +++ b/library/src/text/mod.rs @@ -19,7 +19,7 @@ use std::borrow::Cow; use rustybuzz::Tag; use typst::font::{FontMetrics, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; -use crate::layout::ParNode; +use crate::layout::ParElem; use crate::prelude::*; /// Customize the look and layout of text in a variety of ways. @@ -40,8 +40,8 @@ use crate::prelude::*; /// /// Display: Text /// Category: text -#[node(Construct)] -pub struct TextNode { +#[element(Construct)] +pub struct TextElem { /// A prioritized sequence of font families. /// /// When processing text, Typst tries all specified font families in order @@ -291,7 +291,7 @@ pub struct TextNode { /// هذا عربي. /// ``` #[resolve] - pub dir: HorizontalDir, + pub dir: TextDir, /// Whether to hyphenate text to improve line breaking. When `{auto}`, text /// will be hyphenated if and only if justification is enabled. @@ -479,16 +479,16 @@ pub struct TextNode { pub smallcaps: bool, } -impl TextNode { - /// Create a new packed text node. +impl TextElem { + /// Create a new packed text element. pub fn packed(text: impl Into<EcoString>) -> Content { Self::new(text.into()).pack() } } -impl Construct for TextNode { - fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { - // The text constructor is special: It doesn't create a text node. +impl Construct for TextElem { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { + // The text constructor is special: It doesn't create a text element. // Instead, it leaves the passed argument structurally unchanged, but // styles all text in it. let styles = Self::set(args)?; @@ -606,28 +606,28 @@ cast_to_value! { /// The direction of text and inline objects in their line. #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] -pub struct HorizontalDir(pub Smart<Dir>); +pub struct TextDir(pub Smart<Dir>); cast_from_value! { - HorizontalDir, + TextDir, v: Smart<Dir> => { if v.map_or(false, |dir| dir.axis() == Axis::Y) { - Err("must be horizontal")?; + Err("text direction must be horizontal")?; } Self(v) }, } cast_to_value! { - v: HorizontalDir => v.0.into() + v: TextDir => v.0.into() } -impl Resolve for HorizontalDir { +impl Resolve for TextDir { type Output = Dir; fn resolve(self, styles: StyleChain) -> Self::Output { match self.0 { - Smart::Auto => TextNode::lang_in(styles).dir(), + Smart::Auto => TextElem::lang_in(styles).dir(), Smart::Custom(dir) => dir, } } @@ -651,7 +651,7 @@ impl Resolve for Hyphenate { fn resolve(self, styles: StyleChain) -> Self::Output { match self.0 { - Smart::Auto => ParNode::justify_in(styles), + Smart::Auto => ParElem::justify_in(styles), Smart::Custom(v) => v, } } @@ -677,7 +677,7 @@ cast_from_value! { StylisticSet, v: i64 => match v { 1 ..= 20 => Self::new(v as u8), - _ => Err("must be between 1 and 20")?, + _ => Err("stylistic set must be between 1 and 20")?, }, } diff --git a/library/src/text/quotes.rs b/library/src/text/quotes.rs index 863cc3bd..be923304 100644 --- a/library/src/text/quotes.rs +++ b/library/src/text/quotes.rs @@ -24,8 +24,8 @@ use crate::prelude::*; /// /// Display: Smart Quote /// Category: text -#[node] -pub struct SmartQuoteNode { +#[element] +pub struct SmartQuoteElem { /// Whether this should be a double quote. #[default(true)] pub double: bool, diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs index b6cc0d3d..d24254ed 100644 --- a/library/src/text/raw.rs +++ b/library/src/text/raw.rs @@ -3,9 +3,9 @@ use syntect::highlighting as synt; use typst::syntax::{self, LinkedNode}; use super::{ - FontFamily, FontList, Hyphenate, LinebreakNode, SmartQuoteNode, TextNode, TextSize, + FontFamily, FontList, Hyphenate, LinebreakElem, SmartQuoteElem, TextElem, TextSize, }; -use crate::layout::BlockNode; +use crate::layout::BlockElem; use crate::prelude::*; /// Raw text with optional syntax highlighting. @@ -35,8 +35,8 @@ use crate::prelude::*; /// /// Display: Raw Text / Code /// Category: text -#[node(Synthesize, Show, Finalize)] -pub struct RawNode { +#[element(Synthesize, Show, Finalize)] +pub struct RawElem { /// The raw text. /// /// You can also use raw blocks creatively to create custom syntaxes for @@ -103,7 +103,7 @@ pub struct RawNode { pub lang: Option<EcoString>, } -impl RawNode { +impl RawElem { /// The supported language names and tags. pub fn languages() -> Vec<(&'static str, Vec<&'static str>)> { SYNTAXES @@ -120,13 +120,13 @@ impl RawNode { } } -impl Synthesize for RawNode { +impl Synthesize for RawElem { fn synthesize(&mut self, _: &Vt, styles: StyleChain) { self.push_lang(self.lang(styles)); } } -impl Show for RawNode { +impl Show for RawElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { let text = self.text(); let lang = self.lang(styles).as_ref().map(|s| s.to_lowercase()); @@ -162,7 +162,7 @@ impl Show for RawNode { let mut highlighter = syntect::easy::HighlightLines::new(syntax, &THEME); for (i, line) in text.lines().enumerate() { if i != 0 { - seq.push(LinebreakNode::new().pack()); + seq.push(LinebreakElem::new().pack()); } for (style, piece) in @@ -174,26 +174,27 @@ impl Show for RawNode { Content::sequence(seq) } else { - TextNode::packed(text) + TextElem::packed(text) }; if self.block(styles) { - realized = BlockNode::new().with_body(Some(realized)).pack(); + realized = BlockElem::new().with_body(Some(realized)).pack(); } Ok(realized) } } -impl Finalize for RawNode { +impl Finalize for RawElem { fn finalize(&self, realized: Content, _: StyleChain) -> Content { - let mut map = StyleMap::new(); - map.set(TextNode::set_overhang(false)); - map.set(TextNode::set_hyphenate(Hyphenate(Smart::Custom(false)))); - map.set(TextNode::set_size(TextSize(Em::new(0.8).into()))); - map.set(TextNode::set_font(FontList(vec![FontFamily::new("DejaVu Sans Mono")]))); - map.set(SmartQuoteNode::set_enabled(false)); - realized.styled_with_map(map) + let mut styles = Styles::new(); + styles.set(TextElem::set_overhang(false)); + styles.set(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))); + styles.set(TextElem::set_size(TextSize(Em::new(0.8).into()))); + styles + .set(TextElem::set_font(FontList(vec![FontFamily::new("DejaVu Sans Mono")]))); + styles.set(SmartQuoteElem::set_enabled(false)); + realized.styled_with_map(styles) } } @@ -224,11 +225,11 @@ fn highlight_themed<F>( /// Style a piece of text with a syntect style. fn styled(piece: &str, foreground: Paint, style: synt::Style) -> Content { - let mut body = TextNode::packed(piece); + let mut body = TextElem::packed(piece); let paint = to_typst(style.foreground).into(); if paint != foreground { - body = body.styled(TextNode::set_fill(paint)); + body = body.styled(TextElem::set_fill(paint)); } if style.font_style.contains(synt::FontStyle::BOLD) { diff --git a/library/src/text/shaping.rs b/library/src/text/shaping.rs index 244e7afe..15fbcd3f 100644 --- a/library/src/text/shaping.rs +++ b/library/src/text/shaping.rs @@ -95,10 +95,10 @@ impl<'a> ShapedText<'a> { let mut frame = Frame::new(size); frame.set_baseline(top); - let shift = TextNode::baseline_in(self.styles); - let lang = TextNode::lang_in(self.styles); - let decos = TextNode::deco_in(self.styles); - let fill = TextNode::fill_in(self.styles); + let shift = TextElem::baseline_in(self.styles); + let lang = TextElem::lang_in(self.styles); + let decos = TextElem::deco_in(self.styles); + let fill = TextElem::fill_in(self.styles); for ((font, y_offset), group) in self.glyphs.as_ref().group_by_key(|g| (g.font.clone(), g.y_offset)) @@ -122,16 +122,16 @@ impl<'a> ShapedText<'a> { }) .collect(); - let text = Text { font, size: self.size, lang, fill, glyphs }; - let text_layer = frame.layer(); - let width = text.width(); + let item = TextItem { font, size: self.size, lang, fill, glyphs }; + let layer = frame.layer(); + let width = item.width(); // Apply line decorations. for deco in &decos { - decorate(&mut frame, deco, &text, shift, pos, width); + decorate(&mut frame, deco, &item, shift, pos, width); } - frame.insert(text_layer, pos, Element::Text(text)); + frame.insert(layer, pos, FrameItem::Text(item)); offset += width; } @@ -146,8 +146,8 @@ impl<'a> ShapedText<'a> { let mut top = Abs::zero(); let mut bottom = Abs::zero(); - let top_edge = TextNode::top_edge_in(self.styles); - let bottom_edge = TextNode::bottom_edge_in(self.styles); + let top_edge = TextElem::top_edge_in(self.styles); + let bottom_edge = TextElem::bottom_edge_in(self.styles); // Expand top and bottom by reading the font's vertical metrics. let mut expand = |font: &Font| { @@ -343,7 +343,7 @@ pub fn shape<'a>( styles: StyleChain<'a>, dir: Dir, ) -> ShapedText<'a> { - let size = TextNode::size_in(styles); + let size = TextElem::size_in(styles); let mut ctx = ShapingContext { vt, base, @@ -354,7 +354,7 @@ pub fn shape<'a>( styles, variant: variant(styles), tags: tags(styles), - fallback: TextNode::fallback_in(styles), + fallback: TextElem::fallback_in(styles), dir, }; @@ -531,9 +531,9 @@ fn shape_tofus(ctx: &mut ShapingContext, base: usize, text: &str, font: Font) { /// Apply tracking and spacing to the shaped glyphs. fn track_and_space(ctx: &mut ShapingContext) { - let tracking = Em::from_length(TextNode::tracking_in(ctx.styles), ctx.size); + let tracking = Em::from_length(TextElem::tracking_in(ctx.styles), ctx.size); let spacing = - TextNode::spacing_in(ctx.styles).map(|abs| Em::from_length(abs, ctx.size)); + TextElem::spacing_in(ctx.styles).map(|abs| Em::from_length(abs, ctx.size)); let mut glyphs = ctx.glyphs.iter_mut().peekable(); while let Some(glyph) = glyphs.next() { @@ -562,17 +562,17 @@ fn nbsp_delta(font: &Font) -> Option<Em> { /// Resolve the font variant. pub fn variant(styles: StyleChain) -> FontVariant { let mut variant = FontVariant::new( - TextNode::style_in(styles), - TextNode::weight_in(styles), - TextNode::stretch_in(styles), + TextElem::style_in(styles), + TextElem::weight_in(styles), + TextElem::stretch_in(styles), ); - let delta = TextNode::delta_in(styles); + let delta = TextElem::delta_in(styles); variant.weight = variant .weight .thicken(delta.clamp(i16::MIN as i64, i16::MAX as i64) as i16); - if TextNode::emph_in(styles) { + if TextElem::emph_in(styles) { variant.style = match variant.style { FontStyle::Normal => FontStyle::Italic, FontStyle::Italic => FontStyle::Normal, @@ -593,8 +593,8 @@ pub fn families(styles: StyleChain) -> impl Iterator<Item = FontFamily> + Clone "segoe ui emoji", ]; - let tail = if TextNode::fallback_in(styles) { FALLBACKS } else { &[] }; - TextNode::font_in(styles) + let tail = if TextElem::fallback_in(styles) { FALLBACKS } else { &[] }; + TextElem::font_in(styles) .into_iter() .chain(tail.iter().copied().map(FontFamily::new)) } @@ -607,59 +607,59 @@ fn tags(styles: StyleChain) -> Vec<Feature> { }; // Features that are on by default in Harfbuzz are only added if disabled. - if !TextNode::kerning_in(styles) { + if !TextElem::kerning_in(styles) { feat(b"kern", 0); } // Features that are off by default in Harfbuzz are only added if enabled. - if TextNode::smallcaps_in(styles) { + if TextElem::smallcaps_in(styles) { feat(b"smcp", 1); } - if TextNode::alternates_in(styles) { + if TextElem::alternates_in(styles) { feat(b"salt", 1); } let storage; - if let Some(set) = TextNode::stylistic_set_in(styles) { + if let Some(set) = TextElem::stylistic_set_in(styles) { storage = [b's', b's', b'0' + set.get() / 10, b'0' + set.get() % 10]; feat(&storage, 1); } - if !TextNode::ligatures_in(styles) { + if !TextElem::ligatures_in(styles) { feat(b"liga", 0); feat(b"clig", 0); } - if TextNode::discretionary_ligatures_in(styles) { + if TextElem::discretionary_ligatures_in(styles) { feat(b"dlig", 1); } - if TextNode::historical_ligatures_in(styles) { + if TextElem::historical_ligatures_in(styles) { feat(b"hilg", 1); } - match TextNode::number_type_in(styles) { + match TextElem::number_type_in(styles) { Smart::Auto => {} Smart::Custom(NumberType::Lining) => feat(b"lnum", 1), Smart::Custom(NumberType::OldStyle) => feat(b"onum", 1), } - match TextNode::number_width_in(styles) { + match TextElem::number_width_in(styles) { Smart::Auto => {} Smart::Custom(NumberWidth::Proportional) => feat(b"pnum", 1), Smart::Custom(NumberWidth::Tabular) => feat(b"tnum", 1), } - if TextNode::slashed_zero_in(styles) { + if TextElem::slashed_zero_in(styles) { feat(b"zero", 1); } - if TextNode::fractions_in(styles) { + if TextElem::fractions_in(styles) { feat(b"frac", 1); } - for (tag, value) in TextNode::features_in(styles).0 { + for (tag, value) in TextElem::features_in(styles).0 { tags.push(Feature::new(tag, value, ..)) } @@ -669,8 +669,8 @@ fn tags(styles: StyleChain) -> Vec<Feature> { /// Process the language and and region of a style chain into a /// rustybuzz-compatible BCP 47 language. fn language(styles: StyleChain) -> rustybuzz::Language { - let mut bcp: EcoString = TextNode::lang_in(styles).as_str().into(); - if let Some(region) = TextNode::region_in(styles) { + let mut bcp: EcoString = TextElem::lang_in(styles).as_str().into(); + if let Some(region) = TextElem::region_in(styles) { bcp.push('-'); bcp.push_str(region.as_str()); } diff --git a/library/src/text/shift.rs b/library/src/text/shift.rs index 74bb70c7..1bea3673 100644 --- a/library/src/text/shift.rs +++ b/library/src/text/shift.rs @@ -1,6 +1,4 @@ -use typst::model::SequenceNode; - -use super::{variant, SpaceNode, TextNode, TextSize}; +use super::{variant, SpaceElem, TextElem, TextSize}; use crate::prelude::*; /// Set text in subscript. @@ -14,8 +12,8 @@ use crate::prelude::*; /// /// Display: Subscript /// Category: text -#[node(Show)] -pub struct SubNode { +#[element(Show)] +pub struct SubElem { /// Whether to prefer the dedicated subscript characters of the font. /// /// If this is enabled, Typst first tries to transform the text to subscript @@ -46,21 +44,21 @@ pub struct SubNode { pub body: Content, } -impl Show for SubNode { +impl Show for SubElem { fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { let body = self.body(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, true) { if is_shapable(vt, &text, styles) { - transformed = Some(TextNode::packed(text)); + transformed = Some(TextElem::packed(text)); } } }; Ok(transformed.unwrap_or_else(|| { - body.styled(TextNode::set_baseline(self.baseline(styles))) - .styled(TextNode::set_size(self.size(styles))) + body.styled(TextElem::set_baseline(self.baseline(styles))) + .styled(TextElem::set_size(self.size(styles))) })) } } @@ -76,8 +74,8 @@ impl Show for SubNode { /// /// Display: Superscript /// Category: text -#[node(Show)] -pub struct SuperNode { +#[element(Show)] +pub struct SuperElem { /// Whether to prefer the dedicated superscript characters of the font. /// /// If this is enabled, Typst first tries to transform the text to @@ -108,35 +106,35 @@ pub struct SuperNode { pub body: Content, } -impl Show for SuperNode { +impl Show for SuperElem { fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { let body = self.body(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, false) { if is_shapable(vt, &text, styles) { - transformed = Some(TextNode::packed(text)); + transformed = Some(TextElem::packed(text)); } } }; Ok(transformed.unwrap_or_else(|| { - body.styled(TextNode::set_baseline(self.baseline(styles))) - .styled(TextNode::set_size(self.size(styles))) + body.styled(TextElem::set_baseline(self.baseline(styles))) + .styled(TextElem::set_size(self.size(styles))) })) } } /// Find and transform the text contained in `content` to the given script kind -/// if and only if it only consists of `Text`, `Space`, and `Empty` leaf nodes. +/// if and only if it only consists of `Text`, `Space`, and `Empty` leafs. fn search_text(content: &Content, sub: bool) -> Option<EcoString> { - if content.is::<SpaceNode>() { + if content.is::<SpaceElem>() { Some(' '.into()) - } else if let Some(node) = content.to::<TextNode>() { - convert_script(&node.text(), sub) - } else if let Some(seq) = content.to::<SequenceNode>() { + } else if let Some(elem) = content.to::<TextElem>() { + convert_script(&elem.text(), sub) + } else if let Some(children) = content.to_sequence() { let mut full = EcoString::new(); - for item in seq.children() { + for item in children { match search_text(&item, sub) { Some(text) => full.push_str(&text), None => return None, @@ -152,7 +150,7 @@ fn search_text(content: &Content, sub: bool) -> Option<EcoString> { /// given string. fn is_shapable(vt: &Vt, text: &str, styles: StyleChain) -> bool { let world = vt.world; - for family in TextNode::font_in(styles) { + for family in TextElem::font_in(styles) { if let Some(font) = world .book() .select(family.as_str(), variant(styles)) diff --git a/library/src/visualize/image.rs b/library/src/visualize/image.rs index c5016436..8a81a40e 100644 --- a/library/src/visualize/image.rs +++ b/library/src/visualize/image.rs @@ -22,8 +22,8 @@ use crate::prelude::*; /// /// Display: Image /// Category: visualize -#[node(Layout)] -pub struct ImageNode { +#[element(Layout)] +pub struct ImageElem { /// Path to an image file. #[required] #[parse( @@ -46,7 +46,7 @@ pub struct ImageNode { pub fit: ImageFit, } -impl Layout for ImageNode { +impl Layout for ImageElem { fn layout( &self, vt: &mut Vt, @@ -97,7 +97,7 @@ impl Layout for ImageNode { // the frame to the target size, center aligning the image in the // process. let mut frame = Frame::new(fitted); - frame.push(Point::zero(), Element::Image(image, fitted, self.span())); + frame.push(Point::zero(), FrameItem::Image(image, fitted, self.span())); frame.resize(target, Align::CENTER_HORIZON); // Create a clipping group if only part of the image should be visible. diff --git a/library/src/visualize/line.rs b/library/src/visualize/line.rs index 6614e3ee..0932a9f1 100644 --- a/library/src/visualize/line.rs +++ b/library/src/visualize/line.rs @@ -11,8 +11,8 @@ use crate::prelude::*; /// /// Display: Line /// Category: visualize -#[node(Layout)] -pub struct LineNode { +#[element(Layout)] +pub struct LineElem { /// The start point of the line. /// /// Must be an array of exactly two relative lengths. @@ -49,7 +49,7 @@ pub struct LineNode { pub stroke: PartialStroke, } -impl Layout for LineNode { +impl Layout for LineElem { fn layout( &self, _: &mut Vt, @@ -76,7 +76,7 @@ impl Layout for LineNode { let mut frame = Frame::new(target); let shape = Geometry::Line(delta.to_point()).stroked(stroke); - frame.push(start.to_point(), Element::Shape(shape, self.span())); + frame.push(start.to_point(), FrameItem::Shape(shape, self.span())); Ok(Fragment::frame(frame)) } } diff --git a/library/src/visualize/shape.rs b/library/src/visualize/shape.rs index 8aef3629..601f0d85 100644 --- a/library/src/visualize/shape.rs +++ b/library/src/visualize/shape.rs @@ -18,8 +18,8 @@ use crate::prelude::*; /// /// Display: Rectangle /// Category: visualize -#[node(Layout)] -pub struct RectNode { +#[element(Layout)] +pub struct RectElem { /// The rectangle's width, relative to its parent container. pub width: Smart<Rel<Length>>, @@ -139,7 +139,7 @@ pub struct RectNode { pub body: Option<Content>, } -impl Layout for RectNode { +impl Layout for RectElem { fn layout( &self, vt: &mut Vt, @@ -179,8 +179,8 @@ impl Layout for RectNode { /// /// Display: Square /// Category: visualize -#[node(Layout)] -pub struct SquareNode { +#[element(Layout)] +pub struct SquareElem { /// The square's side length. This is mutually exclusive with `width` and /// `height`. #[external] @@ -249,7 +249,7 @@ pub struct SquareNode { pub body: Option<Content>, } -impl Layout for SquareNode { +impl Layout for SquareElem { fn layout( &self, vt: &mut Vt, @@ -290,8 +290,8 @@ impl Layout for SquareNode { /// /// Display: Ellipse /// Category: visualize -#[node(Layout)] -pub struct EllipseNode { +#[element(Layout)] +pub struct EllipseElem { /// The ellipse's width, relative to its parent container. pub width: Smart<Rel<Length>>, @@ -331,7 +331,7 @@ pub struct EllipseNode { pub body: Option<Content>, } -impl Layout for EllipseNode { +impl Layout for EllipseElem { fn layout( &self, vt: &mut Vt, @@ -372,8 +372,8 @@ impl Layout for EllipseNode { /// /// Display: Circle /// Category: visualize -#[node(Layout)] -pub struct CircleNode { +#[element(Layout)] +pub struct CircleElem { /// The circle's radius. This is mutually exclusive with `width` and /// `height`. #[external] @@ -438,7 +438,7 @@ pub struct CircleNode { pub body: Option<Content>, } -impl Layout for CircleNode { +impl Layout for CircleElem { fn layout( &self, vt: &mut Vt, @@ -529,7 +529,7 @@ fn layout( let size = frame.size() + outset.sum_by_axis(); let pos = Point::new(-outset.left, -outset.top); let shape = ellipse(size, fill, stroke.left); - frame.prepend(pos, Element::Shape(shape, span)); + frame.prepend(pos, FrameItem::Shape(shape, span)); } else { frame.fill_and_stroke(fill, stroke, outset, radius, span); } |
