diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-12-17 00:20:27 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-12-17 00:20:27 +0100 |
| commit | 81e80ecfba80f5bffab45719c1f2aba4f9b91b4f (patch) | |
| tree | 03452a7ef0361f24159a60c93fb543263afb91e3 /src | |
| parent | 2336aeb4c32864f53a4d4e0f72e54a174df47a60 (diff) | |
Test [page] function 📕
- Make page break behaviour more consistent
- Allow skipping reference image testing for single tests with `// compare-ref: false` (useful for tests which only check error messages)
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/mod.rs | 39 | ||||
| -rw-r--r-- | src/layout/spacing.rs | 26 | ||||
| -rw-r--r-- | src/library/layout.rs | 28 |
3 files changed, 53 insertions, 40 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 6d8f66ca..bab93a05 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -25,7 +25,7 @@ use crate::diag::{Deco, Feedback, Pass}; use crate::env::SharedEnv; use crate::geom::{BoxAlign, Dir, Flow, Gen, Length, Linear, Relative, Sides, Size}; use crate::layout::{ - Document, Expansion, LayoutNode, Pad, Pages, Par, Softness, Spacing, Stack, Text, + Document, Expansion, LayoutNode, Pad, Pages, Par, Spacing, Stack, Text, }; use crate::syntax::*; @@ -35,9 +35,9 @@ use crate::syntax::*; /// evaluation. pub fn eval(tree: &SynTree, env: SharedEnv, state: State) -> Pass<Document> { let mut ctx = EvalContext::new(env, state); - ctx.start_page_group(false); + ctx.start_page_group(Softness::Hard); tree.eval(&mut ctx); - ctx.end_page_group(true); + ctx.end_page_group(|s| s == Softness::Hard); ctx.finish() } @@ -117,28 +117,35 @@ impl EvalContext { /// Start a page group based on the active page state. /// - /// If both this `hard` and the one in the matching call to `end_page_group` - /// are false, empty page runs will be omitted from the output. + /// The `softness` is a hint on whether empty pages should be kept in the + /// output. /// /// This also starts an inner paragraph. - pub fn start_page_group(&mut self, hard: bool) { + pub fn start_page_group(&mut self, softness: Softness) { self.start_group(PageGroup { size: self.state.page.size, padding: self.state.page.margins(), flow: self.state.flow, align: self.state.align, - hard, + softness, }); self.start_par_group(); } - /// End a page group and push it to the finished page runs. + /// End a page group, returning its [`Softness`]. + /// + /// Whether the page is kept when it's empty is decided by `keep_empty` + /// based on its softness. If kept, the page is pushed to the finished page + /// runs. /// /// This also ends an inner paragraph. - pub fn end_page_group(&mut self, hard: bool) { + pub fn end_page_group( + &mut self, + keep_empty: impl FnOnce(Softness) -> bool, + ) -> Softness { self.end_par_group(); let (group, children) = self.end_group::<PageGroup>(); - if hard || group.hard || !children.is_empty() { + if !children.is_empty() || keep_empty(group.softness) { self.runs.push(Pages { size: group.size, child: LayoutNode::dynamic(Pad { @@ -152,6 +159,7 @@ impl EvalContext { }), }) } + group.softness } /// Start a content group. @@ -273,7 +281,7 @@ struct PageGroup { padding: Sides<Linear>, flow: Flow, align: BoxAlign, - hard: bool, + softness: Softness, } /// A group for generic content. @@ -286,6 +294,15 @@ struct ParGroup { line_spacing: Length, } +/// Defines how items interact with surrounding items. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum Softness { + /// Soft items can be skipped in some circumstances. + Soft, + /// Hard items are always retained. + Hard, +} + /// Evaluate an item. /// /// _Note_: Evaluation is not necessarily pure, it may change the active state. diff --git a/src/layout/spacing.rs b/src/layout/spacing.rs index 1ba3b54a..c9a9c233 100644 --- a/src/layout/spacing.rs +++ b/src/layout/spacing.rs @@ -1,14 +1,21 @@ use std::fmt::{self, Debug, Formatter}; use super::*; +use crate::eval::Softness; /// A spacing node. #[derive(Copy, Clone, PartialEq)] pub struct Spacing { /// The amount of spacing to insert. pub amount: Length, - /// Spacing interaction, see [`Softness`]'s documentation for more - /// information. + /// Defines how spacing interacts with surrounding spacing. + /// + /// Hard spacing assures that a fixed amount of spacing will always be + /// inserted. Soft spacing will be consumed by previous soft spacing or + /// neighbouring hard spacing and can be used to insert overridable spacing, + /// e.g. between words or paragraphs. + /// + /// This field is only used in evaluation, not in layouting. pub softness: Softness, } @@ -32,18 +39,3 @@ impl From<Spacing> for LayoutNode { Self::Spacing(spacing) } } - -/// Defines how spacing interacts with surrounding spacing. -/// -/// Hard spacing assures that a fixed amount of spacing will always be inserted. -/// Soft spacing will be consumed by previous soft spacing or neighbouring hard -/// spacing and can be used to insert overridable spacing, e.g. between words or -/// paragraphs. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub enum Softness { - /// Soft spacing is not laid out if it directly follows other soft spacing - /// or if it touches hard spacing. - Soft, - /// Hard spacing is always laid out and consumes surrounding soft spacing. - Hard, -} diff --git a/src/library/layout.rs b/src/library/layout.rs index 4a787f1e..36a20821 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -1,7 +1,8 @@ use std::fmt::{self, Display, Formatter}; +use crate::eval::Softness; use crate::geom::{Length, Linear}; -use crate::layout::{Expansion, Fixed, Softness, Spacing, Stack}; +use crate::layout::{Expansion, Fixed, Spacing, Stack}; use crate::paper::{Paper, PaperClass}; use crate::prelude::*; @@ -184,8 +185,8 @@ pub fn boxed(mut args: Args, ctx: &mut EvalContext) -> Value { let body = args.find::<SynTree>().unwrap_or_default(); let width = args.get::<_, Linear>(ctx, "width"); let height = args.get::<_, Linear>(ctx, "height"); - let main = args.get::<_, Spanned<Dir>>(ctx, "main"); - let cross = args.get::<_, Spanned<Dir>>(ctx, "cross"); + let main = args.get::<_, Spanned<Dir>>(ctx, "main-dir"); + let cross = args.get::<_, Spanned<Dir>>(ctx, "cross-dir"); ctx.set_flow(Gen::new(main, cross)); args.done(ctx); @@ -269,7 +270,7 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value { let snapshot = ctx.state.clone(); let body = args.find::<SynTree>(); - if let Some(paper) = args.find::<Paper>() { + if let Some(paper) = args.get::<_, Paper>(ctx, 0) { ctx.state.page.class = paper.class; ctx.state.page.size = paper.size(); } @@ -309,21 +310,24 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value { std::mem::swap(&mut size.width, &mut size.height); } - let main = args.get::<_, Spanned<Dir>>(ctx, "main"); - let cross = args.get::<_, Spanned<Dir>>(ctx, "cross"); + let main = args.get::<_, Spanned<Dir>>(ctx, "main-dir"); + let cross = args.get::<_, Spanned<Dir>>(ctx, "cross-dir"); ctx.set_flow(Gen::new(main, cross)); args.done(ctx); + let mut softness = ctx.end_page_group(|_| false); + if let Some(body) = body { - ctx.end_page_group(false); - ctx.start_page_group(true); + // TODO: Restrict body to a single page? + ctx.start_page_group(Softness::Hard); body.eval(ctx); + ctx.end_page_group(|s| s == Softness::Hard); ctx.state = snapshot; + softness = Softness::Soft; } - ctx.end_page_group(false); - ctx.start_page_group(false); + ctx.start_page_group(softness); Value::None } @@ -331,7 +335,7 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value { /// `pagebreak`: Start a new page. pub fn pagebreak(args: Args, ctx: &mut EvalContext) -> Value { args.done(ctx); - ctx.end_page_group(false); - ctx.start_page_group(true); + ctx.end_page_group(|_| true); + ctx.start_page_group(Softness::Hard); Value::None } |
