From e089b6ea40015e012302dc55ac5d6cb42ca4876e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 8 Feb 2022 16:39:37 +0100 Subject: Set rules for everything --- src/eval/template.rs | 217 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 133 insertions(+), 84 deletions(-) (limited to 'src/eval/template.rs') diff --git a/src/eval/template.rs b/src/eval/template.rs index a6693c84..84888b95 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -6,12 +6,15 @@ use std::ops::{Add, AddAssign}; use typed_arena::Arena; -use super::{CollapsingBuilder, Interruption, Property, StyleMap, StyleVecBuilder}; +use super::{ + CollapsingBuilder, Interruption, Property, Show, ShowNode, StyleMap, StyleVecBuilder, +}; use crate::diag::StrResult; -use crate::layout::{Layout, PackedNode}; +use crate::layout::{Layout, LayoutNode}; use crate::library::prelude::*; use crate::library::{ - FlowChild, FlowNode, PageNode, ParChild, ParNode, PlaceNode, SpacingKind, TextNode, + DecoNode, FlowChild, FlowNode, PageNode, ParChild, ParNode, PlaceNode, SpacingKind, + TextNode, Underline, }; use crate::util::EcoString; use crate::Context; @@ -52,7 +55,7 @@ pub enum Template { /// Plain text. Text(EcoString), /// An inline-level node. - Inline(PackedNode), + Inline(LayoutNode), /// A paragraph break. Parbreak, /// A column break. @@ -60,21 +63,23 @@ pub enum Template { /// Vertical spacing. Vertical(SpacingKind), /// A block-level node. - Block(PackedNode), + Block(LayoutNode), /// A page break. Pagebreak, /// A page node. Page(PageNode), + /// A node that can be realized with styles. + Show(ShowNode), /// A template with attached styles. - Styled(Box, StyleMap), + Styled(Arc<(Self, StyleMap)>), /// A sequence of multiple subtemplates. - Sequence(Vec), + Sequence(Arc>), } impl Template { /// Create an empty template. pub fn new() -> Self { - Self::Sequence(vec![]) + Self::sequence(vec![]) } /// Create a template from an inline-level node. @@ -93,42 +98,63 @@ impl Template { Self::Block(node.pack()) } - /// Layout this template into a collection of pages. - pub fn layout(&self, ctx: &mut Context) -> Vec> { - let (mut ctx, styles) = LayoutContext::new(ctx); - let (pages, shared) = Builder::build_pages(self); - let styles = shared.chain(&styles); - pages - .iter() - .flat_map(|(page, map)| page.layout(&mut ctx, map.chain(&styles))) - .collect() + /// Create a template from a showable node. + pub fn show(node: T) -> Self + where + T: Show + Debug + Hash + Sync + Send + 'static, + { + Self::Show(node.pack()) } /// Style this template with a single property. pub fn styled(mut self, key: P, value: P::Value) -> Self { - if let Self::Styled(_, map) = &mut self { - map.set(key, value); - self - } else { - self.styled_with_map(StyleMap::with(key, value)) + if let Self::Styled(styled) = &mut self { + if let Some((_, map)) = Arc::get_mut(styled) { + if !map.has_scoped() { + map.set(key, value); + } + return self; + } } + + self.styled_with_map(StyleMap::with(key, value)) } /// Style this template with a full style map. pub fn styled_with_map(mut self, styles: StyleMap) -> Self { if styles.is_empty() { - self - } else if let Self::Styled(_, map) = &mut self { - map.apply(&styles); - self - } else { - Self::Styled(Box::new(self), styles) + return self; } + + if let Self::Styled(styled) = &mut self { + if let Some((_, map)) = Arc::get_mut(styled) { + if !styles.has_scoped() && !map.has_scoped() { + map.apply(&styles); + return self; + } + } + } + + Self::Styled(Arc::new((self, styles))) } /// Style this template in monospace. pub fn monospaced(self) -> Self { - self.styled(TextNode::MONOSPACE, true) + self.styled(TextNode::MONOSPACED, true) + } + + /// Underline this template. + pub fn underlined(self) -> Self { + Self::show(DecoNode { kind: Underline, body: self }) + } + + /// Create a new sequence template. + pub fn sequence(seq: Vec) -> Self { + if seq.len() == 1 { + seq.into_iter().next().unwrap() + } else { + Self::Sequence(Arc::new(seq)) + } } /// Repeat this template `n` times. @@ -136,7 +162,24 @@ impl Template { let count = usize::try_from(n) .map_err(|_| format!("cannot repeat this template {} times", n))?; - Ok(Self::Sequence(vec![self.clone(); count])) + Ok(Self::sequence(vec![self.clone(); count])) + } + + /// Layout this template into a collection of pages. + pub fn layout(&self, ctx: &mut Context) -> Vec> { + let style_arena = Arena::new(); + let template_arena = Arena::new(); + let (mut ctx, styles) = LayoutContext::new(ctx); + + let mut builder = Builder::new(&style_arena, &template_arena, true); + builder.process(self, styles); + builder.finish_page(true, false, styles); + + let (pages, shared) = builder.pages.unwrap().finish(); + pages + .iter() + .flat_map(|(page, map)| page.layout(&mut ctx, map.chain(&shared))) + .collect() } } @@ -168,11 +211,17 @@ impl Debug for Template { } Self::Pagebreak => f.pad("Pagebreak"), Self::Page(page) => page.fmt(f), - Self::Styled(sub, map) => { + Self::Show(node) => { + f.write_str("Show(")?; + node.fmt(f)?; + f.write_str(")") + } + Self::Styled(styled) => { + let (sub, map) = styled.as_ref(); map.fmt(f)?; sub.fmt(f) } - Self::Sequence(seq) => f.debug_list().entries(seq).finish(), + Self::Sequence(seq) => f.debug_list().entries(seq.iter()).finish(), } } } @@ -183,20 +232,22 @@ impl Add for Template { fn add(self, rhs: Self) -> Self::Output { Self::Sequence(match (self, rhs) { (Self::Sequence(mut lhs), Self::Sequence(rhs)) => { - lhs.extend(rhs); + let mutable = Arc::make_mut(&mut lhs); + match Arc::try_unwrap(rhs) { + Ok(vec) => mutable.extend(vec), + Err(rc) => mutable.extend(rc.iter().cloned()), + } lhs } (Self::Sequence(mut lhs), rhs) => { - lhs.push(rhs); + Arc::make_mut(&mut lhs).push(rhs); lhs } (lhs, Self::Sequence(mut rhs)) => { - rhs.insert(0, lhs); + Arc::make_mut(&mut rhs).insert(0, lhs); rhs } - (lhs, rhs) => { - vec![lhs, rhs] - } + (lhs, rhs) => Arc::new(vec![lhs, rhs]), }) } } @@ -209,7 +260,7 @@ impl AddAssign for Template { impl Sum for Template { fn sum>(iter: I) -> Self { - Self::Sequence(iter.collect()) + Self::sequence(iter.collect()) } } @@ -220,14 +271,21 @@ impl Layout for Template { regions: &Regions, styles: StyleChain, ) -> Vec>> { - let (flow, shared) = Builder::build_flow(self); - flow.layout(ctx, regions, shared.chain(&styles)) + let style_arena = Arena::new(); + let template_arena = Arena::new(); + + let mut builder = Builder::new(&style_arena, &template_arena, false); + builder.process(self, styles); + builder.finish_par(styles); + + let (flow, shared) = builder.flow.finish(); + FlowNode(flow).layout(ctx, regions, shared) } - fn pack(self) -> PackedNode { + fn pack(self) -> LayoutNode { match self { Template::Block(node) => node, - other => PackedNode::new(other), + other => LayoutNode::new(other), } } } @@ -235,7 +293,9 @@ impl Layout for Template { /// Builds a flow or page nodes from a template. struct Builder<'a> { /// An arena where intermediate style chains are stored. - arena: &'a Arena>, + style_arena: &'a Arena>, + /// An arena where intermediate templates are stored. + template_arena: &'a Arena