use std::convert::TryFrom; use std::fmt::{self, Debug, Formatter}; use std::mem; use std::ops::{Add, AddAssign}; use std::rc::Rc; use super::Str; use crate::diag::StrResult; use crate::geom::{Align, Dir, Gen, GenAxis, Length, Linear, Sides, Size}; use crate::layout::{ Decoration, LayoutNode, LayoutTree, PadNode, PageRun, ParChild, ParNode, StackChild, StackNode, }; use crate::style::Style; use crate::util::EcoString; /// A template value: `[*Hi* there]`. #[derive(Default, Clone)] pub struct Template(Rc>); /// One node in a template. #[derive(Clone)] enum TemplateNode { /// A word space. Space(Vec), /// A line break. Linebreak, /// A paragraph break. Parbreak, /// A page break. Pagebreak(bool), /// Plain text. Text(EcoString, Vec), /// Spacing. Spacing(GenAxis, Linear), /// An inline node builder. Inline(Rc LayoutNode>, Vec), /// An block node builder. Block(Rc LayoutNode>), /// Save the current style. Save, /// Restore the last saved style. Restore, /// A function that can modify the current style. Modify(Rc), } impl Template { /// Create a new, empty template. pub fn new() -> Self { Self(Rc::new(vec![])) } /// Create a template from a builder for an inline-level node. pub fn from_inline(f: F) -> Self where F: Fn(&Style) -> T + 'static, T: Into, { let node = TemplateNode::Inline(Rc::new(move |s| f(s).into()), vec![]); Self(Rc::new(vec![node])) } /// Create a template from a builder for a block-level node. pub fn from_block(f: F) -> Self where F: Fn(&Style) -> T + 'static, T: Into, { let node = TemplateNode::Block(Rc::new(move |s| f(s).into())); Self(Rc::new(vec![node])) } /// Add a word space to the template. pub fn space(&mut self) { self.make_mut().push(TemplateNode::Space(vec![])); } /// Add a line break to the template. pub fn linebreak(&mut self) { self.make_mut().push(TemplateNode::Linebreak); } /// Add a paragraph break to the template. pub fn parbreak(&mut self) { self.make_mut().push(TemplateNode::Parbreak); } /// Add a page break to the template. pub fn pagebreak(&mut self, keep: bool) { self.make_mut().push(TemplateNode::Pagebreak(keep)); } /// Add text to the template. pub fn text(&mut self, text: impl Into) { self.make_mut().push(TemplateNode::Text(text.into(), vec![])); } /// Add text, but in monospace. pub fn monospace(&mut self, text: impl Into) { self.save(); self.modify(|style| style.text_mut().monospace = true); self.text(text); self.restore(); } /// Add spacing along an axis. pub fn spacing(&mut self, axis: GenAxis, spacing: Linear) { self.make_mut().push(TemplateNode::Spacing(axis, spacing)); } /// Add a decoration to all contained nodes. pub fn decorate(&mut self, deco: Decoration) { for node in self.make_mut() { let decos = match node { TemplateNode::Space(decos) => decos, TemplateNode::Text(_, decos) => decos, TemplateNode::Inline(_, decos) => decos, _ => continue, }; decos.push(deco.clone()); } } /// Register a restorable snapshot. pub fn save(&mut self) { self.make_mut().push(TemplateNode::Save); } /// Ensure that later nodes are untouched by style modifications made since /// the last snapshot. pub fn restore(&mut self) { self.make_mut().push(TemplateNode::Restore); } /// Modify the style. pub fn modify(&mut self, f: F) where F: Fn(&mut Style) + 'static, { self.make_mut().push(TemplateNode::Modify(Rc::new(f))); } /// Return a new template which is modified from start to end. pub fn modified(self, f: F) -> Self where F: Fn(&mut Style) + 'static, { let mut wrapper = Self::new(); wrapper.save(); wrapper.modify(f); wrapper += self; wrapper.restore(); wrapper } /// Build the stack node resulting from instantiating the template with the /// given style. pub fn to_stack(&self, style: &Style) -> StackNode { let mut builder = Builder::new(style, false); builder.template(self); builder.build_stack() } /// Build the layout tree resulting from instantiating the template with the /// given style. pub fn to_tree(&self, style: &Style) -> LayoutTree { let mut builder = Builder::new(style, true); builder.template(self); builder.build_tree() } /// Repeat this template `n` times. pub fn repeat(&self, n: i64) -> StrResult { let count = usize::try_from(n) .ok() .and_then(|n| self.0.len().checked_mul(n)) .ok_or_else(|| format!("cannot repeat this template {} times", n))?; Ok(Self(Rc::new( self.0.iter().cloned().cycle().take(count).collect(), ))) } /// Return a mutable reference to the inner vector. fn make_mut(&mut self) -> &mut Vec { Rc::make_mut(&mut self.0) } } impl Debug for Template { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.pad("