summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-02-08 16:39:37 +0100
committerLaurenz <laurmaedje@gmail.com>2022-02-09 12:34:19 +0100
commite089b6ea40015e012302dc55ac5d6cb42ca4876e (patch)
treedbb66237cb996bc880560dfd94ac9b682e1ac985 /src/eval
parent68503b9a07b00bce3f4d377bcfe945452de815ea (diff)
Set rules for everything
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/collapse.rs26
-rw-r--r--src/eval/mod.rs150
-rw-r--r--src/eval/show.rs96
-rw-r--r--src/eval/styles.rs30
-rw-r--r--src/eval/template.rs217
-rw-r--r--src/eval/value.rs2
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)),