From 5e08028fb36aa766957cba64c5c665edf9b96fb7 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 21 Mar 2021 17:46:09 +0100 Subject: =?UTF-8?q?Syntax=20functions=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds overridable functions that markup desugars into. Specifically: - \ desugars into linebreak - Two newlines desugar into parbreak - * desugars into strong - _ desugars into emph - = .. desugars into heading - `..` desugars into raw --- src/exec/context.rs | 19 ++++++----- src/exec/mod.rs | 90 +++++++---------------------------------------------- 2 files changed, 22 insertions(+), 87 deletions(-) (limited to 'src/exec') diff --git a/src/exec/context.rs b/src/exec/context.rs index 761977fc..f19f6561 100644 --- a/src/exec/context.rs +++ b/src/exec/context.rs @@ -11,7 +11,7 @@ use crate::geom::{Dir, Gen, Linear, Sides, Size}; use crate::layout::{ Node, PadNode, PageRun, ParNode, SpacingNode, StackNode, TextNode, Tree, }; -use crate::parse::is_newline; +use crate::parse::{is_newline, Scanner}; use crate::syntax::{Span, Spanned}; /// The context for execution. @@ -99,16 +99,19 @@ impl<'a> ExecContext<'a> { /// /// The text is split into lines at newlines. pub fn push_text(&mut self, text: &str) { - let mut newline = false; - for line in text.split_terminator(is_newline) { - if newline { + let mut scanner = Scanner::new(text); + let mut line = String::new(); + + while let Some(c) = scanner.eat_merging_crlf() { + if is_newline(c) { + self.push(self.make_text_node(mem::take(&mut line))); self.push_linebreak(); + } else { + line.push(c); } - - let node = self.make_text_node(line.into()); - self.push(node); - newline = true; } + + self.push(self.make_text_node(line)); } /// Apply a forced line break. diff --git a/src/exec/mod.rs b/src/exec/mod.rs index 5a2ff698..6f3b9c83 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -10,24 +10,24 @@ use std::rc::Rc; use crate::diag::Pass; use crate::env::Env; -use crate::eval::{ExprMap, TemplateFunc, TemplateNode, TemplateValue, Value}; -use crate::layout::{self, FixedNode, SpacingNode, StackNode}; +use crate::eval::{NodeMap, TemplateFunc, TemplateNode, TemplateValue, Value}; +use crate::layout; use crate::pretty::pretty; use crate::syntax::*; /// Execute a syntax tree to produce a layout tree. /// -/// The `map` shall be an expression map computed for this tree with +/// The `map` shall be a node map computed for this tree with /// [`eval`](crate::eval::eval). Note that `tree` must be the _exact_ same tree -/// as used for evaluation (no cloned version), because the expression map -/// depends on the pointers being stable. +/// as used for evaluation (no cloned version), because the node map depends on +/// the pointers being stable. /// /// The `state` is the base state that may be updated over the course of /// execution. pub fn exec( env: &mut Env, tree: &Tree, - map: &ExprMap, + map: &NodeMap, state: State, ) -> Pass { let mut ctx = ExecContext::new(env, state); @@ -47,14 +47,14 @@ pub trait Exec { fn exec(&self, ctx: &mut ExecContext); } -/// Execute a node with an expression map that applies to it. +/// Execute a node with a node map that applies to it. pub trait ExecWithMap { /// Execute the node. - fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap); + fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap); } impl ExecWithMap for Tree { - fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap) { for node in self { node.exec_with_map(ctx, map); } @@ -62,83 +62,15 @@ impl ExecWithMap for Tree { } impl ExecWithMap for Node { - fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap) { match self { Node::Text(text) => ctx.push_text(text), Node::Space => ctx.push_space(), - Node::Linebreak => ctx.push_linebreak(), - Node::Parbreak => ctx.push_parbreak(), - Node::Strong => ctx.state.font.strong ^= true, - Node::Emph => ctx.state.font.emph ^= true, - Node::Heading(heading) => heading.exec_with_map(ctx, map), - Node::Raw(raw) => raw.exec(ctx), - Node::Expr(expr) => map[&(expr as *const _)].exec(ctx), + _ => map[&(self as *const _)].exec(ctx), } } } -impl ExecWithMap for HeadingNode { - fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { - let prev = ctx.state.clone(); - let upscale = 1.5 - 0.1 * self.level as f64; - ctx.state.font.scale *= upscale; - ctx.state.font.strong = true; - - self.contents.exec_with_map(ctx, map); - ctx.push_parbreak(); - - ctx.state = prev; - } -} - -impl Exec for RawNode { - fn exec(&self, ctx: &mut ExecContext) { - let prev = Rc::clone(&ctx.state.font.families); - ctx.set_monospace(); - - let em = ctx.state.font.font_size(); - let leading = ctx.state.par.leading.resolve(em); - - let mut children = vec![]; - let mut newline = false; - for line in &self.lines { - if newline { - children.push(layout::Node::Spacing(SpacingNode { - amount: leading, - softness: 2, - })); - } - - children.push(layout::Node::Text(ctx.make_text_node(line.clone()))); - newline = true; - } - - if self.block { - ctx.push_parbreak(); - } - - // This is wrapped in a fixed node to make sure the stack fits to its - // content instead of filling the available area. - ctx.push(FixedNode { - width: None, - height: None, - aspect: None, - child: StackNode { - dirs: ctx.state.dirs, - aligns: ctx.state.aligns, - children, - } - .into(), - }); - - if self.block { - ctx.push_parbreak(); - } - - ctx.state.font.families = prev; - } -} - impl Exec for Value { fn exec(&self, ctx: &mut ExecContext) { match self { -- cgit v1.2.3