diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-02-08 16:39:37 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-02-09 12:34:19 +0100 |
| commit | e089b6ea40015e012302dc55ac5d6cb42ca4876e (patch) | |
| tree | dbb66237cb996bc880560dfd94ac9b682e1ac985 /src/eval | |
| parent | 68503b9a07b00bce3f4d377bcfe945452de815ea (diff) | |
Set rules for everything
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/collapse.rs | 26 | ||||
| -rw-r--r-- | src/eval/mod.rs | 150 | ||||
| -rw-r--r-- | src/eval/show.rs | 96 | ||||
| -rw-r--r-- | src/eval/styles.rs | 30 | ||||
| -rw-r--r-- | src/eval/template.rs | 217 | ||||
| -rw-r--r-- | src/eval/value.rs | 2 |
6 files changed, 294 insertions, 227 deletions
diff --git a/src/eval/collapse.rs b/src/eval/collapse.rs index 0e91cae6..ef8a5255 100644 --- a/src/eval/collapse.rs +++ b/src/eval/collapse.rs @@ -3,7 +3,7 @@ use super::{StyleChain, StyleVec, StyleVecBuilder}; /// A wrapper around a [`StyleVecBuilder`] that allows to collapse items. pub struct CollapsingBuilder<'a, T> { builder: StyleVecBuilder<'a, T>, - staged: Vec<(T, StyleChain<'a>, bool)>, + staged: Vec<(T, StyleChain<'a>, Option<u8>)>, last: Last, } @@ -29,9 +29,21 @@ impl<'a, T: Merge> CollapsingBuilder<'a, T> { /// and to its right, with no destructive items or weak items in between to /// its left and no destructive items in between to its right. There may be /// ignorant items in between in both directions. - pub fn weak(&mut self, item: T, styles: StyleChain<'a>) { - if self.last == Last::Supportive { - self.staged.push((item, styles, true)); + pub fn weak(&mut self, item: T, strength: u8, styles: StyleChain<'a>) { + if self.last != Last::Destructive { + if self.last == Last::Weak { + if let Some(i) = self + .staged + .iter() + .position(|(.., prev)| prev.map_or(false, |p| p < strength)) + { + self.staged.remove(i); + } else { + return; + } + } + + self.staged.push((item, styles, Some(strength))); self.last = Last::Weak; } } @@ -52,7 +64,7 @@ impl<'a, T: Merge> CollapsingBuilder<'a, T> { /// Has no influence on other items. pub fn ignorant(&mut self, item: T, styles: StyleChain<'a>) { - self.staged.push((item, styles, false)); + self.staged.push((item, styles, None)); } /// Return the finish style vec and the common prefix chain. @@ -63,8 +75,8 @@ impl<'a, T: Merge> CollapsingBuilder<'a, T> { /// Push the staged items, filtering out weak items if `supportive` is false. fn flush(&mut self, supportive: bool) { - for (item, styles, weak) in self.staged.drain(..) { - if !weak || supportive { + for (item, styles, strength) in self.staged.drain(..) { + if supportive || strength.is_none() { push_merging(&mut self.builder, item, styles); } } diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 98b0152c..5a67555c 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -14,6 +14,7 @@ mod collapse; mod func; mod ops; mod scope; +mod show; mod template; pub use array::*; @@ -23,6 +24,7 @@ pub use collapse::*; pub use dict::*; pub use func::*; pub use scope::*; +pub use show::*; pub use styles::*; pub use template::*; pub use value::*; @@ -33,34 +35,23 @@ use std::io; use std::mem; use std::path::PathBuf; -use once_cell::sync::Lazy; -use syntect::easy::HighlightLines; -use syntect::highlighting::{FontStyle, Highlighter, Style as SynStyle, Theme, ThemeSet}; -use syntect::parsing::SyntaxSet; use unicode_segmentation::UnicodeSegmentation; use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult}; -use crate::geom::{Angle, Color, Fractional, Length, Paint, Relative}; +use crate::geom::{Angle, Fractional, Length, Relative}; use crate::image::ImageStore; use crate::layout::Layout; -use crate::library::{self, DecoLine, TextNode}; +use crate::library::{self}; use crate::loading::Loader; -use crate::parse; use crate::source::{SourceId, SourceStore}; -use crate::syntax; use crate::syntax::ast::*; -use crate::syntax::{RedNode, Span, Spanned}; +use crate::syntax::{Span, Spanned}; use crate::util::{EcoString, RefMutExt}; use crate::Context; -static THEME: Lazy<Theme> = - Lazy::new(|| ThemeSet::load_defaults().themes.remove("InspiredGitHub").unwrap()); - -static SYNTAXES: Lazy<SyntaxSet> = Lazy::new(|| SyntaxSet::load_defaults_newlines()); - /// An evaluated module, ready for importing or conversion to a root layout /// tree. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Clone)] pub struct Module { /// The top-level definitions that were bound in this module. pub scope: Scope, @@ -194,17 +185,13 @@ fn eval_markup( MarkupNode::Expr(Expr::Wrap(wrap)) => { let tail = eval_markup(ctx, nodes)?; ctx.scopes.def_mut(wrap.binding().take(), tail); - wrap.body().eval(ctx)?.show() + wrap.body().eval(ctx)?.display() } _ => node.eval(ctx)?, }); } - if seq.len() == 1 { - Ok(seq.into_iter().next().unwrap()) - } else { - Ok(Template::Sequence(seq)) - } + Ok(Template::sequence(seq)) } impl Eval for MarkupNode { @@ -223,7 +210,7 @@ impl Eval for MarkupNode { Self::Heading(heading) => heading.eval(ctx)?, Self::List(list) => list.eval(ctx)?, Self::Enum(enum_) => enum_.eval(ctx)?, - Self::Expr(expr) => expr.eval(ctx)?.show(), + Self::Expr(expr) => expr.eval(ctx)?.display(), }) } } @@ -232,7 +219,7 @@ impl Eval for StrongNode { type Output = Template; fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { - Ok(self.body().eval(ctx)?.styled(TextNode::STRONG, true)) + Ok(Template::show(library::StrongNode(self.body().eval(ctx)?))) } } @@ -240,7 +227,7 @@ impl Eval for EmphNode { type Output = Template; fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { - Ok(self.body().eval(ctx)?.styled(TextNode::EMPH, true)) + Ok(Template::show(library::EmphNode(self.body().eval(ctx)?))) } } @@ -248,104 +235,25 @@ impl Eval for RawNode { type Output = Template; fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> { - let code = self.highlighted(); - Ok(if self.block { Template::Block(code.pack()) } else { code }) - } -} - -impl RawNode { - /// Styled template for a code block, with optional syntax highlighting. - pub fn highlighted(&self) -> Template { - let mut seq: Vec<Template> = vec![]; - - let syntax = if let Some(syntax) = self - .lang - .as_ref() - .and_then(|token| SYNTAXES.find_syntax_by_token(&token)) - { - Some(syntax) - } else if matches!( - self.lang.as_ref().map(|s| s.to_ascii_lowercase()).as_deref(), - Some("typ" | "typst") - ) { - None - } else { - return Template::Text(self.text.clone()).monospaced(); - }; - - let foreground = THEME - .settings - .foreground - .map(Color::from) - .unwrap_or(Color::BLACK) - .into(); - - match syntax { - Some(syntax) => { - let mut highlighter = HighlightLines::new(syntax, &THEME); - for (i, line) in self.text.lines().enumerate() { - if i != 0 { - seq.push(Template::Linebreak); - } - - for (style, piece) in highlighter.highlight(line, &SYNTAXES) { - seq.push(style_piece(piece, foreground, style)); - } - } - } - None => { - let green = parse::parse(&self.text); - let red = RedNode::from_root(green, SourceId::from_raw(0)); - let highlighter = Highlighter::new(&THEME); - - syntax::highlight_syntect( - red.as_ref(), - &highlighter, - &mut |range, style| { - seq.push(style_piece(&self.text[range], foreground, style)); - }, - ) - } - } - - Template::Sequence(seq).monospaced() - } -} - -/// Style a piece of text with a syntect style. -fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Template { - let mut styles = StyleMap::new(); - - let paint = style.foreground.into(); - if paint != foreground { - styles.set(TextNode::FILL, paint); - } - - if style.font_style.contains(FontStyle::BOLD) { - styles.set(TextNode::STRONG, true); - } - - if style.font_style.contains(FontStyle::ITALIC) { - styles.set(TextNode::EMPH, true); - } - - if style.font_style.contains(FontStyle::UNDERLINE) { - styles.set(TextNode::LINES, vec![DecoLine::Underline.into()]); + let template = Template::show(library::RawNode { + text: self.text.clone(), + block: self.block, + }); + Ok(match self.lang { + Some(_) => template.styled(library::RawNode::LANG, self.lang.clone()), + None => template, + }) } - - Template::Text(piece.into()).styled_with_map(styles) } impl Eval for MathNode { type Output = Template; fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> { - let text = Template::Text(self.formula.trim().into()).monospaced(); - Ok(if self.display { - Template::Block(text.pack()) - } else { - text - }) + Ok(Template::show(library::MathNode { + formula: self.formula.clone(), + display: self.display, + })) } } @@ -353,8 +261,8 @@ impl Eval for HeadingNode { type Output = Template; fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { - Ok(Template::block(library::HeadingNode { - child: self.body().eval(ctx)?.pack(), + Ok(Template::show(library::HeadingNode { + body: self.body().eval(ctx)?, level: self.level(), })) } @@ -364,9 +272,9 @@ impl Eval for ListNode { type Output = Template; fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { - Ok(Template::block(library::ListNode { + Ok(Template::show(library::ListNode { child: self.body().eval(ctx)?.pack(), - kind: library::Unordered, + label: library::Unordered, })) } } @@ -375,9 +283,9 @@ impl Eval for EnumNode { type Output = Template; fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { - Ok(Template::block(library::ListNode { + Ok(Template::show(library::ListNode { child: self.body().eval(ctx)?.pack(), - kind: library::Ordered(self.number()), + label: library::Ordered(self.number()), })) } } diff --git a/src/eval/show.rs b/src/eval/show.rs new file mode 100644 index 00000000..6157485d --- /dev/null +++ b/src/eval/show.rs @@ -0,0 +1,96 @@ +use std::any::{Any, TypeId}; +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; +use std::sync::Arc; + +use super::{StyleChain, Template}; +use crate::util::Prehashed; + +/// A node that can be realized given some styles. +pub trait Show { + /// Realize the template in the given styles. + fn show(&self, styles: StyleChain) -> Template; + + /// Convert to a packed show node. + fn pack(self) -> ShowNode + where + Self: Debug + Hash + Sized + Sync + Send + 'static, + { + ShowNode::new(self) + } +} + +/// A type-erased showable node with a precomputed hash. +#[derive(Clone, Hash)] +pub struct ShowNode(Arc<Prehashed<dyn Bounds>>); + +impl ShowNode { + /// Pack any showable node. + pub fn new<T>(node: T) -> Self + where + T: Show + Debug + Hash + Sync + Send + 'static, + { + Self(Arc::new(Prehashed::new(node))) + } + + /// The type id of this node. + pub fn id(&self) -> TypeId { + self.0.as_any().type_id() + } +} + +impl Show for ShowNode { + fn show(&self, styles: StyleChain) -> Template { + self.0.show(styles) + } + + fn pack(self) -> ShowNode { + self + } +} + +impl Debug for ShowNode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl PartialEq for ShowNode { + fn eq(&self, other: &Self) -> bool { + // We cast to thin pointers for comparison because we don't want to + // compare vtables (which can be different across codegen units). + std::ptr::eq( + Arc::as_ptr(&self.0) as *const (), + Arc::as_ptr(&other.0) as *const (), + ) + } +} + +trait Bounds: Show + Debug + Sync + Send + 'static { + fn as_any(&self) -> &dyn Any; + fn hash64(&self) -> u64; +} + +impl<T> Bounds for T +where + T: Show + Debug + Hash + Sync + Send + 'static, +{ + fn as_any(&self) -> &dyn Any { + self + } + + fn hash64(&self) -> u64 { + // Also hash the TypeId since nodes with different types but + // equal data should be different. + let mut state = fxhash::FxHasher64::default(); + self.type_id().hash(&mut state); + self.hash(&mut state); + state.finish() + } +} + +impl Hash for dyn Bounds { + fn hash<H: Hasher>(&self, state: &mut H) { + state.write_u64(self.hash64()); + } +} diff --git a/src/eval/styles.rs b/src/eval/styles.rs index 863dcc6f..2bf3f239 100644 --- a/src/eval/styles.rs +++ b/src/eval/styles.rs @@ -49,6 +49,11 @@ impl StyleMap { self } + /// Whether this map contains scoped styles. + pub fn has_scoped(&self) -> bool { + self.0.iter().any(|e| e.scoped) + } + /// Make `self` the first link of the style chain `outer`. /// /// The resulting style chain contains styles from `self` as well as @@ -136,20 +141,6 @@ impl<'a> StyleChain<'a> { self.links().count() } - /// Convert to an owned style map. - /// - /// Panics if the chain contains barrier links. - pub fn to_map(self) -> StyleMap { - let mut suffix = StyleMap::new(); - for link in self.links() { - match link { - Link::Map(map) => suffix.apply(map), - Link::Barrier(_) => panic!("chain contains barrier"), - } - } - suffix - } - /// Build a style map from the suffix (all links beyond the `len`) of the /// chain. /// @@ -170,6 +161,17 @@ impl<'a> StyleChain<'a> { pub fn pop(&mut self) { *self = self.outer.copied().unwrap_or_default(); } + + /// Return the chain, but without the last link if that one contains only + /// scoped styles. This is a hack. + pub(crate) fn unscoped(mut self, node: TypeId) -> Self { + if let Some(Link::Map(map)) = self.link { + if map.0.iter().all(|e| e.scoped && e.is_of_id(node)) { + self.pop(); + } + } + self + } } impl<'a> StyleChain<'a> { 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<Self>, StyleMap), + Styled(Arc<(Self, StyleMap)>), /// A sequence of multiple subtemplates. - Sequence(Vec<Self>), + Sequence(Arc<Vec<Self>>), } 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<Arc<Frame>> { - 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<T>(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<P: Property>(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>) -> 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<Arc<Frame>> { + 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<I: Iterator<Item = Self>>(iter: I) -> Self { - Self::Sequence(iter.collect()) + Self::sequence(iter.collect()) } } @@ -220,14 +271,21 @@ impl Layout for Template { regions: &Regions, styles: StyleChain, ) -> Vec<Constrained<Arc<Frame>>> { - 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<StyleChain<'a>>, + style_arena: &'a Arena<StyleChain<'a>>, + /// An arena where intermediate templates are stored. + template_arena: &'a Arena<Template>, /// The already built page runs. pages: Option<StyleVecBuilder<'a, PageNode>>, /// The currently built flow. @@ -247,34 +307,15 @@ struct Builder<'a> { } impl<'a> Builder<'a> { - /// Build page runs from a template. - fn build_pages(template: &Template) -> (StyleVec<PageNode>, StyleMap) { - let arena = Arena::new(); - - let mut builder = Builder::prepare(&arena, true); - builder.process(template, StyleChain::default()); - builder.finish_page(true, false, StyleChain::default()); - - let (pages, shared) = builder.pages.unwrap().finish(); - (pages, shared.to_map()) - } - - /// Build a subflow from a template. - fn build_flow(template: &Template) -> (FlowNode, StyleMap) { - let arena = Arena::new(); - - let mut builder = Builder::prepare(&arena, false); - builder.process(template, StyleChain::default()); - builder.finish_par(); - - let (flow, shared) = builder.flow.finish(); - (FlowNode(flow), shared.to_map()) - } - /// Prepare the builder. - fn prepare(arena: &'a Arena<StyleChain<'a>>, top: bool) -> Self { + fn new( + style_arena: &'a Arena<StyleChain<'a>>, + template_arena: &'a Arena<Template>, + top: bool, + ) -> Self { Self { - arena, + style_arena, + template_arena, pages: top.then(|| StyleVecBuilder::new()), flow: CollapsingBuilder::new(), par: CollapsingBuilder::new(), @@ -286,7 +327,7 @@ impl<'a> Builder<'a> { fn process(&mut self, template: &'a Template, styles: StyleChain<'a>) { match template { Template::Space => { - self.par.weak(ParChild::Text(' '.into()), styles); + self.par.weak(ParChild::Text(' '.into()), 0, styles); } Template::Linebreak => { self.par.destructive(ParChild::Text('\n'.into()), styles); @@ -306,15 +347,15 @@ impl<'a> Builder<'a> { self.par.supportive(ParChild::Node(node.clone()), styles); } Template::Parbreak => { - self.finish_par(); - self.flow.weak(FlowChild::Parbreak, styles); + self.finish_par(styles); + self.flow.weak(FlowChild::Parbreak, 1, styles); } Template::Colbreak => { - self.finish_par(); + self.finish_par(styles); self.flow.destructive(FlowChild::Colbreak, styles); } Template::Vertical(kind) => { - self.finish_par(); + self.finish_par(styles); let child = FlowChild::Spacing(*kind); if kind.is_fractional() { self.flow.destructive(child, styles); @@ -323,13 +364,14 @@ impl<'a> Builder<'a> { } } Template::Block(node) => { - self.finish_par(); + self.finish_par(styles); let child = FlowChild::Node(node.clone()); if node.is::<PlaceNode>() { self.flow.ignorant(child, styles); } else { self.flow.supportive(child, styles); } + self.finish_par(styles); } Template::Pagebreak => { self.finish_page(true, true, styles); @@ -340,26 +382,32 @@ impl<'a> Builder<'a> { pages.push(page.clone(), styles); } } - Template::Styled(sub, map) => { + Template::Show(node) => { + let template = self.template_arena.alloc(node.show(styles)); + self.process(template, styles.unscoped(node.id())); + } + Template::Styled(styled) => { + let (sub, map) = styled.as_ref(); + let stored = self.style_arena.alloc(styles); + let styles = map.chain(stored); + let interruption = map.interruption(); match interruption { Some(Interruption::Page) => self.finish_page(false, true, styles), - Some(Interruption::Par) => self.finish_par(), + Some(Interruption::Par) => self.finish_par(styles), None => {} } - let outer = self.arena.alloc(styles); - let styles = map.chain(outer); self.process(sub, styles); match interruption { Some(Interruption::Page) => self.finish_page(true, false, styles), - Some(Interruption::Par) => self.finish_par(), + Some(Interruption::Par) => self.finish_par(styles), None => {} } } Template::Sequence(seq) => { - for sub in seq { + for sub in seq.iter() { self.process(sub, styles); } } @@ -367,17 +415,18 @@ impl<'a> Builder<'a> { } /// Finish the currently built paragraph. - fn finish_par(&mut self) { + fn finish_par(&mut self, styles: StyleChain<'a>) { let (par, shared) = mem::take(&mut self.par).finish(); if !par.is_empty() { let node = ParNode(par).pack(); self.flow.supportive(FlowChild::Node(node), shared); } + self.flow.weak(FlowChild::Leading, 0, styles); } /// Finish the currently built page run. fn finish_page(&mut self, keep_last: bool, keep_next: bool, styles: StyleChain<'a>) { - self.finish_par(); + self.finish_par(styles); if let Some(pages) = &mut self.pages { let (flow, shared) = mem::take(&mut self.flow).finish(); if !flow.is_empty() || (keep_last && self.keep_next) { diff --git a/src/eval/value.rs b/src/eval/value.rs index d0b822f1..2d37b34f 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -115,7 +115,7 @@ impl Value { } /// Return the display representation of the value. - pub fn show(self) -> Template { + pub fn display(self) -> Template { match self { Value::None => Template::new(), Value::Int(v) => Template::Text(format_eco!("{}", v)), |
