From cff325b520727ac0eec46a3757831afaa0916cc1 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 22 Oct 2019 21:40:37 +0200 Subject: [PATCH] =?UTF-8?q?Add=20spacing=20functions=20=F0=9F=94=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/func.rs | 1 + src/layout/mod.rs | 9 +++++ src/layout/tree.rs | 2 + src/library/mod.rs | 12 +++++- src/library/spacing.rs | 76 ++++++++++++++++++++++++++++++++++++ src/parsing/mod.rs | 4 +- tests/layouts/align.typ | 4 +- tests/layouts/coma.typ | 6 +-- tests/layouts/pagebreaks.typ | 6 +-- 9 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 src/library/spacing.rs diff --git a/src/func.rs b/src/func.rs index 7925af2de..05bbe83df 100644 --- a/src/func.rs +++ b/src/func.rs @@ -116,6 +116,7 @@ pub enum Command<'a> { Layout(&'a SyntaxTree), Add(Layout), AddMany(MultiLayout), + AddFlex(Layout), SetAlignment(Alignment), SetStyle(TextStyle), FinishLayout, diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 470ac3ba3..34c9b35a3 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -40,6 +40,15 @@ pub struct Layout { } impl Layout { + /// Create an empty layout with the specified dimensions. + pub fn empty(width: Size, height: Size) -> Layout { + Layout { + dimensions: Size2D::new(width, height), + actions: vec![], + debug_render: true, + } + } + /// Serialize this layout into an output buffer. pub fn serialize(&self, f: &mut W) -> io::Result<()> { writeln!( diff --git a/src/layout/tree.rs b/src/layout/tree.rs index 3a58115f7..a0cb14349 100644 --- a/src/layout/tree.rs +++ b/src/layout/tree.rs @@ -124,6 +124,8 @@ impl<'a, 'p> TreeLayouter<'a, 'p> { self.start_new_flex(); } + Command::AddFlex(layout) => self.flex.add(layout), + Command::SetAlignment(alignment) => { self.finish_flex()?; self.alignment = alignment; diff --git a/src/library/mod.rs b/src/library/mod.rs index d0c987a44..784ef2041 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -5,6 +5,7 @@ use crate::func::Scope; mod align; mod boxed; mod breaks; +mod spacing; mod styles; /// Useful imports for creating your own functions. @@ -20,6 +21,7 @@ pub mod prelude { pub use align::AlignFunc; pub use boxed::BoxFunc; pub use breaks::{LinebreakFunc, PagebreakFunc}; +pub use spacing::{HorizontalSpaceFunc, VerticalSpaceFunc}; pub use styles::{BoldFunc, ItalicFunc, MonospaceFunc}; /// Create a scope with all standard functions. @@ -27,15 +29,21 @@ pub fn std() -> Scope { let mut std = Scope::new(); std.add::("align"); std.add::("box"); - std.add::("linebreak"); + + std.add::("line.break"); std.add::("n"); - std.add::("pagebreak"); + std.add::("page.break"); + + std.add::("h"); + std.add::("v"); + std.add::("bold"); std.add::("italic"); std.add::("mono"); std } +/// Helpers for writing custom functions. pub mod helpers { use super::prelude::*; diff --git a/src/library/spacing.rs b/src/library/spacing.rs new file mode 100644 index 000000000..91288edcb --- /dev/null +++ b/src/library/spacing.rs @@ -0,0 +1,76 @@ +use std::marker::PhantomData; +use super::prelude::*; +use crate::size::Size; + +/// Adds vertical space. +pub type VerticalSpaceFunc = SpaceFunc; + +/// Adds horizontal space. +pub type HorizontalSpaceFunc = SpaceFunc; + +/// Adds generic space. +#[derive(Debug, PartialEq)] +pub struct SpaceFunc { + spacing: Spacing, + _phantom: PhantomData, +} + +/// Absolute or font-relative spacing. +#[derive(Debug, PartialEq)] +enum Spacing { + Absolute(Size), + Relative(f32), +} + +impl Function for SpaceFunc { + fn parse(header: &FuncHeader, body: Option<&str>, _: ParseContext) -> ParseResult + where Self: Sized { + if header.args.len() != 1 || !header.kwargs.is_empty() { + return err("align: expected exactly one positional argument"); + } + + let spacing = match header.args[0] { + Expression::Size(s) => Spacing::Absolute(s), + Expression::Number(f) => Spacing::Relative(f as f32), + _ => return err("space: expected size or number"), + }; + + if body.is_some() { + return err("space: expected no body"); + } + + Ok(SpaceFunc { + spacing, + _phantom: PhantomData, + }) + } + + fn layout(&self, ctx: LayoutContext) -> LayoutResult { + let space = match self.spacing { + Spacing::Absolute(s) => s, + Spacing::Relative(f) => Size::pt(f * ctx.style.font_size), + }; + + Ok(commands![F::cmd(space)]) + } +} + +pub trait SpaceFlow: std::fmt::Debug + PartialEq + 'static { + fn cmd(space: Size) -> Command<'static>; +} + +#[derive(Debug, PartialEq)] +pub struct SpaceVertical; +impl SpaceFlow for SpaceVertical { + fn cmd(space: Size) -> Command<'static> { + Command::Add(Layout::empty(Size::zero(), space)) + } +} + +#[derive(Debug, PartialEq)] +pub struct SpaceHorizontal; +impl SpaceFlow for SpaceHorizontal { + fn cmd(space: Size) -> Command<'static> { + Command::AddFlex(Layout::empty(space, Size::zero())) + } +} diff --git a/src/parsing/mod.rs b/src/parsing/mod.rs index cd886fb46..369205957 100644 --- a/src/parsing/mod.rs +++ b/src/parsing/mod.rs @@ -404,13 +404,13 @@ fn is_identifier(string: &str) -> bool { let mut chars = string.chars(); match chars.next() { - Some(c) if !UnicodeXID::is_xid_start(c) => return false, + Some(c) if c != '.' && !UnicodeXID::is_xid_start(c) => return false, None => return false, _ => (), } while let Some(c) = chars.next() { - if !UnicodeXID::is_xid_continue(c) { + if c != '.' && !UnicodeXID::is_xid_continue(c) { return false; } } diff --git a/tests/layouts/align.typ b/tests/layouts/align.typ index 68e5fab59..c971cb41b 100644 --- a/tests/layouts/align.typ +++ b/tests/layouts/align.typ @@ -11,7 +11,7 @@ // Over multiple pages after the pervious 3-page run. [align: left][Left: {lorem:80}] -[pagebreak] +[page.break] // ---------------------------------- // // Context-modifying align. @@ -26,7 +26,7 @@ Right Again: {lorem:10} // Reset context-modifier. [align: left] -[pagebreak] +[page.break] // ---------------------------------- // // All in one line. diff --git a/tests/layouts/coma.typ b/tests/layouts/coma.typ index 7b3266a92..b56299eca 100644 --- a/tests/layouts/coma.typ +++ b/tests/layouts/coma.typ @@ -9,9 +9,7 @@ [align: right][*WiSe 2019/2020* [n] Week 1] ] - -// hack for more whitespace -[box][] +[v: 3mm] [align: center][ *3. Ubungsblatt Computerorientierte Mathematik II* [n] @@ -27,5 +25,3 @@ Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten ≤ 2 Kinder hat. Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel zu _v_, und die Höhe von _v_ ist die Länge eines längsten (absteigenden) Weges von _v_ zu einem Blatt. Die Höhe des Baumes ist die Höhe der Wurzel. - - diff --git a/tests/layouts/pagebreaks.typ b/tests/layouts/pagebreaks.typ index 8de361ab7..3644f6629 100644 --- a/tests/layouts/pagebreaks.typ +++ b/tests/layouts/pagebreaks.typ @@ -1,10 +1,10 @@ {size:150pt*200pt} {lorem:100} -[pagebreak] -[pagebreak] +[page.break] +[page.break] {lorem:20} -[pagebreak] +[page.break] {lorem:150}