diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/mod.rs | 27 | ||||
| -rw-r--r-- | src/layout/tree.rs | 105 |
2 files changed, 66 insertions, 66 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 5f5a4859..837c19ec 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -10,9 +10,7 @@ mod tree; /// Basic types used across the layouting engine. pub mod prelude { pub use super::primitive::*; - pub use super::{ - BoxLayout, layout, Layout, LayoutContext, LayoutSpace, MultiLayout, - }; + pub use super::{BoxLayout, layout, LayoutContext, LayoutSpace, MultiLayout}; pub use Dir::*; pub use GenAlign::*; pub use GenAxis::*; @@ -23,13 +21,11 @@ pub mod prelude { pub use primitive::*; pub use tree::layout_tree as layout; -use async_trait::async_trait; - +use crate::compute::scope::Scope; use crate::font::SharedFontLoader; use crate::geom::{Margins, Size}; use crate::style::{LayoutStyle, PageStyle, TextStyle}; use crate::syntax::tree::SyntaxTree; -use crate::Pass; use elements::LayoutElements; use prelude::*; @@ -48,18 +44,13 @@ pub struct BoxLayout { pub elements: LayoutElements, } -/// Command-based layouting. -#[async_trait(?Send)] -pub trait Layout { - /// Create a sequence of layouting commands to execute. - async fn layout<'a>(&'a self, ctx: LayoutContext<'_>) -> Pass<Commands<'a>>; -} - /// The context for layouting. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct LayoutContext<'a> { /// The font loader to query fonts from when typesetting text. pub loader: &'a SharedFontLoader, + /// The function scope. + pub scope: &'a Scope, /// The style for pages and text. pub style: &'a LayoutStyle, /// The unpadded size of this container (the base 100% for relative sizes). @@ -118,11 +109,11 @@ impl LayoutSpace { } /// A sequence of layouting commands. -pub type Commands<'a> = Vec<Command<'a>>; +pub type Commands = Vec<Command>; /// Commands executable by the layouting engine. -#[derive(Debug, Clone)] -pub enum Command<'a> { +#[derive(Debug, Clone, PartialEq)] +pub enum Command { /// Layout the given tree in the current context (i.e. not nested). The /// content of the tree is not laid out into a separate box and then added, /// but simply laid out flatly in the active layouting process. @@ -130,7 +121,7 @@ pub enum Command<'a> { /// This has the effect that the content fits nicely into the active line /// layouting, enabling functions to e.g. change the style of some piece of /// text while keeping it part of the current paragraph. - LayoutSyntaxTree(&'a SyntaxTree), + LayoutSyntaxTree(SyntaxTree), /// Add a finished layout. Add(BoxLayout), diff --git a/src/layout/tree.rs b/src/layout/tree.rs index 3abdc934..39e111bd 100644 --- a/src/layout/tree.rs +++ b/src/layout/tree.rs @@ -1,9 +1,10 @@ //! Layouting of syntax trees. +use crate::compute::value::Value; use crate::style::LayoutStyle; use crate::syntax::decoration::Decoration; -use crate::syntax::span::{Span, Spanned}; -use crate::syntax::tree::{DynamicNode, SyntaxNode, SyntaxTree}; +use crate::syntax::span::{Offset, Span, Spanned}; +use crate::syntax::tree::{CallExpr, SyntaxNode, SyntaxTree}; use crate::{DynFuture, Feedback, Pass}; use super::line::{LineContext, LineLayouter}; use super::text::{layout_text, TextContext}; @@ -66,60 +67,28 @@ impl<'a> TreeLayouter<'a> { self.style.text.word_spacing(), SpacingKind::WORD, ); - }, - + } SyntaxNode::Linebreak => self.layouter.finish_line(), SyntaxNode::ToggleItalic => { self.style.text.italic = !self.style.text.italic; decorate(self, Decoration::Italic); } - SyntaxNode::ToggleBolder => { self.style.text.bolder = !self.style.text.bolder; decorate(self, Decoration::Bold); } SyntaxNode::Text(text) => { - if self.style.text.italic { - decorate(self, Decoration::Italic); - } - - if self.style.text.bolder { - decorate(self, Decoration::Bold); - } - + if self.style.text.italic { decorate(self, Decoration::Italic); } + if self.style.text.bolder { decorate(self, Decoration::Bold); } self.layout_text(text).await; } - SyntaxNode::Raw(lines) => { - // TODO: Make this more efficient. - let fallback = self.style.text.fallback.clone(); - self.style.text.fallback - .list_mut() - .insert(0, "monospace".to_string()); - - self.style.text.fallback.flatten(); - - // Layout the first line. - let mut iter = lines.iter(); - if let Some(line) = iter.next() { - self.layout_text(line).await; - } - - // Put a newline before each following line. - for line in iter { - self.layouter.finish_line(); - self.layout_text(line).await; - } - - self.style.text.fallback = fallback; - } - + SyntaxNode::Raw(lines) => self.layout_raw(lines).await, SyntaxNode::Par(par) => self.layout_par(par).await, - - SyntaxNode::Dyn(dynamic) => { - self.layout_dyn(Spanned::new(dynamic.as_ref(), node.span)).await; + SyntaxNode::Call(call) => { + self.layout_call(Spanned::new(call, node.span)).await; } } } @@ -133,19 +102,35 @@ impl<'a> TreeLayouter<'a> { self.layout_tree(par).await; } - async fn layout_dyn(&mut self, dynamic: Spanned<&dyn DynamicNode>) { - // Execute the dynamic node's command-generating layout function. - let layouted = dynamic.v.layout(LayoutContext { + async fn layout_call(&mut self, call: Spanned<&CallExpr>) { + let name = call.v.name.v.as_str(); + let span = call.v.name.span.offset(call.span.start); + + let (func, deco) = if let Some(func) = self.ctx.scope.func(name) { + (func, Decoration::Resolved) + } else { + error!(@self.feedback, span, "unknown function"); + (self.ctx.scope.fallback(), Decoration::Unresolved) + }; + + self.feedback.decorations.push(Spanned::new(deco, span)); + + let args = call.v.args.eval(); + let pass = func(args, LayoutContext { style: &self.style, spaces: self.layouter.remaining(), root: true, ..self.ctx }).await; - self.feedback.extend_offset(layouted.feedback, dynamic.span.start); + self.feedback.extend_offset(pass.feedback, call.span.start); - for command in layouted.output { - self.execute_command(command, dynamic.span).await; + if let Value::Commands(commands) = pass.output { + for command in commands { + self.execute_command(command, call.span).await; + } + } else { + self.layout_raw(&[format!("{:?}", pass.output)]).await; } } @@ -163,11 +148,35 @@ impl<'a> TreeLayouter<'a> { ); } - async fn execute_command(&mut self, command: Command<'_>, span: Span) { + async fn layout_raw(&mut self, lines: &[String]) { + // TODO: Make this more efficient. + let fallback = self.style.text.fallback.clone(); + self.style.text.fallback + .list_mut() + .insert(0, "monospace".to_string()); + + self.style.text.fallback.flatten(); + + // Layout the first line. + let mut iter = lines.iter(); + if let Some(line) = iter.next() { + self.layout_text(line).await; + } + + // Put a newline before each following line. + for line in iter { + self.layouter.finish_line(); + self.layout_text(line).await; + } + + self.style.text.fallback = fallback; + } + + async fn execute_command(&mut self, command: Command, span: Span) { use Command::*; match command { - LayoutSyntaxTree(tree) => self.layout_tree(tree).await, + LayoutSyntaxTree(tree) => self.layout_tree(&tree).await, Add(layout) => self.layouter.add(layout), AddMultiple(layouts) => self.layouter.add_multiple(layouts), |
