summaryrefslogtreecommitdiff
path: root/src/exec
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-03-21 17:46:09 +0100
committerLaurenz <laurmaedje@gmail.com>2021-03-21 17:50:56 +0100
commit5e08028fb36aa766957cba64c5c665edf9b96fb7 (patch)
tree912799dad3c1e25b7032f3e3bee009537c6f555b /src/exec
parent898728f260923a91444eb23b522d0abf01a4299b (diff)
Syntax functions 🚀
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
Diffstat (limited to 'src/exec')
-rw-r--r--src/exec/context.rs19
-rw-r--r--src/exec/mod.rs90
2 files changed, 22 insertions, 87 deletions
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<layout::Tree> {
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 {