diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-01-26 15:51:13 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-01-26 15:51:13 +0100 |
| commit | 20fb4e7c379b79b84d9884d5f2c89d781c5793e2 (patch) | |
| tree | a1eef90680afa2b43cb1ce0a687c837fd78810e7 /src/layout/model.rs | |
| parent | 0a087cd28bbee5fcdffbb9d49b0ba9f413ad7f92 (diff) | |
Document everything 📜
Diffstat (limited to 'src/layout/model.rs')
| -rw-r--r-- | src/layout/model.rs | 75 |
1 files changed, 56 insertions, 19 deletions
diff --git a/src/layout/model.rs b/src/layout/model.rs index 2e61b453..1d635f5c 100644 --- a/src/layout/model.rs +++ b/src/layout/model.rs @@ -1,3 +1,7 @@ +//! The model layouter layouts models (i.e. +//! [syntax models](crate::syntax::SyntaxModel) and [functions](crate::func)) +//! by executing commands issued by the models. + use std::future::Future; use std::pin::Pin; use smallvec::smallvec; @@ -13,7 +17,7 @@ use super::text::{layout_text, TextContext}; use super::*; -#[derive(Debug, Clone)] +/// Performs the model layouting. pub struct ModelLayouter<'a, 'p> { ctx: LayoutContext<'a, 'p>, layouter: LineLayouter, @@ -21,7 +25,7 @@ pub struct ModelLayouter<'a, 'p> { errors: Errors, } -/// The general context for layouting. +/// The context for layouting. #[derive(Debug, Clone)] pub struct LayoutContext<'a, 'p> { /// The font loader to retrieve fonts from when typesetting text @@ -46,53 +50,74 @@ pub struct LayoutContext<'a, 'p> { pub debug: bool, } +/// The result of layouting: Some layouted things and a list of errors. pub struct Layouted<T> { + /// The result of the layouting process. pub output: T, + /// Errors that arose in the process of layouting. pub errors: Errors, } -impl<T> Layouted<T> { - pub fn map<F, U>(self, f: F) -> Layouted<U> where F: FnOnce(T) -> U { - Layouted { - output: f(self.output), - errors: self.errors, - } - } -} - /// A sequence of layouting commands. pub type Commands<'a> = Vec<Command<'a>>; -/// Layouting commands from functions to the typesetting engine. +/// Commands issued to the layouting engine by models. #[derive(Debug)] pub enum Command<'a> { + /// Layout the given model in the current context (i.e. not nested). The + /// content of the model is not laid out into a separate box and then added, + /// but simply laid out flat in the active layouting process. + /// + /// 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 integrated in the current paragraph. LayoutSyntaxModel(&'a SyntaxModel), + /// Add a already computed layout. Add(Layout), + /// Add multiple layouts, one after another. This is equivalent to multiple + /// [Add](Command::Add) commands. AddMultiple(MultiLayout), + + /// Add spacing of given [kind](super::SpacingKind) along the primary or + /// secondary axis. The spacing kind defines how the spacing interacts with + /// surrounding spacing. AddSpacing(Size, SpacingKind, GenericAxis), - FinishLine, - FinishSpace, + /// Start a new line. + BreakLine, + /// Start a new paragraph. BreakParagraph, + /// Start a new page, which will exist in the finished layout even if it + /// stays empty (since the page break is a _hard_ space break). BreakPage, + /// Update the text style. SetTextStyle(TextStyle), + /// Update the page style. SetPageStyle(PageStyle), + + /// Update the alignment for future boxes added to this layouting process. SetAlignment(LayoutAlignment), + /// Update the layouting axes along which future boxes will be laid out. + /// This finishes the current line. SetAxes(LayoutAxes), } +/// Layout a syntax model into a list of boxes. pub async fn layout(model: &SyntaxModel, ctx: LayoutContext<'_, '_>) -> Layouted<MultiLayout> { let mut layouter = ModelLayouter::new(ctx); layouter.layout_syntax_model(model).await; layouter.finish() } +/// A dynamic future type which allows recursive invocation of async functions +/// when used as the return type. This is also how the async trait functions +/// work internally. pub type DynFuture<'a, T> = Pin<Box<dyn Future<Output=T> + 'a>>; impl<'a, 'p> ModelLayouter<'a, 'p> { - /// Create a new syntax tree layouter. + /// Create a new model layouter. pub fn new(ctx: LayoutContext<'a, 'p>) -> ModelLayouter<'a, 'p> { ModelLayouter { layouter: LineLayouter::new(LineContext { @@ -109,10 +134,12 @@ impl<'a, 'p> ModelLayouter<'a, 'p> { } } + /// Flatly layout a model into this layouting process. pub fn layout<'r>( &'r mut self, model: Spanned<&'r dyn Model> ) -> DynFuture<'r, ()> { Box::pin(async move { + // Execute the model's layout function which generates the commands. let layouted = model.v.layout(LayoutContext { style: &self.style, spaces: self.layouter.remaining(), @@ -121,14 +148,16 @@ impl<'a, 'p> ModelLayouter<'a, 'p> { .. self.ctx }).await; - let commands = layouted.output; + // Add the errors generated by the model to the error list. self.errors.extend(offset_spans(layouted.errors, model.span.start)); - for command in commands { + for command in layouted.output { self.execute_command(command, model.span).await; } }) } + /// Layout a syntax model by directly processing the nodes instead of using + /// the command based architecture. pub fn layout_syntax_model<'r>( &'r mut self, model: &'r SyntaxModel @@ -162,6 +191,7 @@ impl<'a, 'p> ModelLayouter<'a, 'p> { } }) } + /// Compute the finished list of boxes. pub fn finish(self) -> Layouted<MultiLayout> { Layouted { output: self.layouter.finish(), @@ -169,6 +199,8 @@ impl<'a, 'p> ModelLayouter<'a, 'p> { } } + /// Execute a command issued by a model. When the command is errorful, the + /// given span is stored with the error. fn execute_command<'r>( &'r mut self, command: Command<'r>, @@ -186,8 +218,7 @@ impl<'a, 'p> ModelLayouter<'a, 'p> { Secondary => self.layouter.add_secondary_spacing(space, kind), } - FinishLine => self.layouter.finish_line(), - FinishSpace => self.layouter.finish_space(true), + BreakLine => self.layouter.finish_line(), BreakParagraph => self.layout_paragraph(), BreakPage => { if self.ctx.nested { @@ -209,6 +240,9 @@ impl<'a, 'p> ModelLayouter<'a, 'p> { } else { self.style.page = style; + // The line layouter has no idea of page styles and thus we + // need to recompute the layouting space resulting of the + // new page style and update it within the layouter. let margins = style.margins(); self.ctx.base = style.dimensions.unpadded(margins); self.layouter.set_spaces(smallvec