From 5afb42ad89abb518a01a09051f0f9b6f75bd383e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 9 Jun 2021 00:37:13 +0200 Subject: Lists with indent-based parsing - Unordered lists with indent-based parsing and basic layout using stacks - Headings are now also indent based - Removes syntax functions since they will be superseded by select & transform --- src/exec/context.rs | 20 +++++++++--- src/exec/mod.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++------- src/exec/state.rs | 2 +- 3 files changed, 95 insertions(+), 18 deletions(-) (limited to 'src/exec') diff --git a/src/exec/context.rs b/src/exec/context.rs index 016b092a..63008260 100644 --- a/src/exec/context.rs +++ b/src/exec/context.rs @@ -1,13 +1,13 @@ use std::mem; -use super::{Exec, FontFamily, State}; +use super::{Exec, ExecWithMap, FontFamily, State}; use crate::diag::{Diag, DiagSet, Pass}; -use crate::eval::TemplateValue; +use crate::eval::{ExprMap, TemplateValue}; use crate::geom::{Align, Dir, Gen, GenAxis, Length, Linear, Sides, Size}; use crate::layout::{ AnyNode, PadNode, PageRun, ParChild, ParNode, StackChild, StackNode, Tree, }; -use crate::syntax::Span; +use crate::syntax::{self, Span}; /// The context for execution. pub struct ExecContext { @@ -48,12 +48,22 @@ impl ExecContext { } /// Execute a template and return the result as a stack node. - pub fn exec_template(&mut self, template: &TemplateValue) -> StackNode { + pub fn exec_template_stack(&mut self, template: &TemplateValue) -> StackNode { + self.exec_stack(|ctx| template.exec(ctx)) + } + + /// Execute a tree with a map and return the result as a stack node. + pub fn exec_tree_stack(&mut self, tree: &syntax::Tree, map: &ExprMap) -> StackNode { + self.exec_stack(|ctx| tree.exec_with_map(ctx, map)) + } + + /// Execute something and return the result as a stack node. + pub fn exec_stack(&mut self, f: impl FnOnce(&mut Self)) -> StackNode { let snapshot = self.state.clone(); let page = self.page.take(); let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state)); - template.exec(self); + f(self); self.state = snapshot; self.page = page; diff --git a/src/exec/mod.rs b/src/exec/mod.rs index 35e6b55c..a13d8c5e 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -9,10 +9,11 @@ pub use state::*; use std::rc::Rc; use crate::diag::Pass; -use crate::eval::{NodeMap, TemplateFunc, TemplateNode, TemplateValue, Value}; -use crate::layout; +use crate::eval::{ExprMap, TemplateFunc, TemplateNode, TemplateValue, Value}; +use crate::geom::{Dir, Gen}; +use crate::layout::{self, FixedNode, StackChild, StackNode}; use crate::pretty::pretty; -use crate::syntax::*; +use crate::syntax; /// Execute a template to produce a layout tree. pub fn exec(template: &TemplateValue, state: State) -> Pass { @@ -33,30 +34,96 @@ pub trait Exec { fn exec(&self, ctx: &mut ExecContext); } -/// Execute a node with a node map that applies to it. +/// Execute a node with an expression map that applies to it. pub trait ExecWithMap { /// Execute the node. - fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap); + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap); } -impl ExecWithMap for Tree { - fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap) { +impl ExecWithMap for syntax::Tree { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { for node in self { node.exec_with_map(ctx, map); } } } -impl ExecWithMap for Node { - fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap) { +impl ExecWithMap for syntax::Node { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { match self { - Node::Text(text) => ctx.push_text(text), - Node::Space => ctx.push_word_space(), - _ => map[&(self as *const _)].exec(ctx), + Self::Text(text) => ctx.push_text(text), + Self::Space => ctx.push_word_space(), + Self::Linebreak(_) => ctx.linebreak(), + Self::Parbreak(_) => ctx.parbreak(), + Self::Strong(_) => ctx.state.font.strong ^= true, + Self::Emph(_) => ctx.state.font.emph ^= true, + Self::Raw(raw) => raw.exec(ctx), + Self::Heading(heading) => heading.exec_with_map(ctx, map), + Self::List(list) => list.exec_with_map(ctx, map), + Self::Expr(expr) => map[&(expr as *const _)].exec(ctx), } } } +impl Exec for syntax::RawNode { + fn exec(&self, ctx: &mut ExecContext) { + if self.block { + ctx.parbreak(); + } + + let snapshot = ctx.state.clone(); + ctx.set_monospace(); + ctx.push_text(&self.text); + ctx.state = snapshot; + + if self.block { + ctx.parbreak(); + } + } +} + +impl ExecWithMap for syntax::HeadingNode { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { + let snapshot = ctx.state.clone(); + + let upscale = 1.6 - 0.1 * self.level as f64; + ctx.state.font.scale *= upscale; + ctx.state.font.strong = true; + + self.body.exec_with_map(ctx, map); + + ctx.state = snapshot; + ctx.parbreak(); + } +} + +impl ExecWithMap for syntax::ListNode { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { + ctx.parbreak(); + + let bullet = ctx.exec_stack(|ctx| ctx.push_text("•")); + let body = ctx.exec_tree_stack(&self.body, map); + + let stack = StackNode { + dirs: Gen::new(Dir::TTB, ctx.state.lang.dir), + aspect: None, + children: vec![ + StackChild::Any(bullet.into(), Gen::default()), + StackChild::Spacing(ctx.state.font.resolve_size() / 2.0), + StackChild::Any(body.into(), Gen::default()), + ], + }; + + ctx.push(FixedNode { + width: None, + height: None, + child: stack.into(), + }); + + ctx.parbreak(); + } +} + impl Exec for Value { fn exec(&self, ctx: &mut ExecContext) { match self { diff --git a/src/exec/state.rs b/src/exec/state.rs index 9a8971cc..aeeeaed5 100644 --- a/src/exec/state.rs +++ b/src/exec/state.rs @@ -7,7 +7,7 @@ use crate::geom::*; use crate::layout::Fill; use crate::paper::{Paper, PaperClass, PAPER_A4}; -/// The evaluation state. +/// The execution state. #[derive(Debug, Clone, PartialEq)] pub struct State { /// The current language-related settings. -- cgit v1.2.3