diff options
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/layout.rs | 84 | ||||
| -rw-r--r-- | src/library/text.rs | 96 |
2 files changed, 102 insertions, 78 deletions
diff --git a/src/library/layout.rs b/src/library/layout.rs index eea4afb5..f3f3f81e 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -24,45 +24,45 @@ pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { Value::template(move |ctx| { let snapshot = ctx.state.clone(); + let state = ctx.state.page_mut(); if let Some(paper) = paper { - ctx.state.page.class = paper.class; - ctx.state.page.size = paper.size(); + state.class = paper.class; + state.size = paper.size(); } if let Some(width) = width { - ctx.state.page.class = PaperClass::Custom; - ctx.state.page.size.width = width; + state.class = PaperClass::Custom; + state.size.width = width; } if let Some(height) = height { - ctx.state.page.class = PaperClass::Custom; - ctx.state.page.size.height = height; + state.class = PaperClass::Custom; + state.size.height = height; } if let Some(margins) = margins { - ctx.state.page.margins = Sides::splat(Some(margins)); + state.margins = Sides::splat(Some(margins)); } if let Some(left) = left { - ctx.state.page.margins.left = Some(left); + state.margins.left = Some(left); } if let Some(top) = top { - ctx.state.page.margins.top = Some(top); + state.margins.top = Some(top); } if let Some(right) = right { - ctx.state.page.margins.right = Some(right); + state.margins.right = Some(right); } if let Some(bottom) = bottom { - ctx.state.page.margins.bottom = Some(bottom); + state.margins.bottom = Some(bottom); } if flip.unwrap_or(false) { - let page = &mut ctx.state.page; - std::mem::swap(&mut page.size.width, &mut page.size.height); + std::mem::swap(&mut state.size.width, &mut state.size.height); } ctx.pagebreak(false, true, span); @@ -96,7 +96,7 @@ fn spacing_impl(ctx: &mut EvalContext, args: &mut FuncArgs, axis: GenAxis) -> Va Value::template(move |ctx| { if let Some(linear) = spacing { // TODO: Should this really always be font-size relative? - let amount = linear.resolve(ctx.state.text.size); + let amount = linear.resolve(ctx.state.font.size); ctx.push_spacing(axis, amount); } }) @@ -180,7 +180,7 @@ pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `stack`: Stack children along an axis. pub fn stack(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let dir = args.named(ctx, "dir").unwrap_or(Dir::TTB); + let dir = args.named(ctx, "dir"); let children: Vec<_> = args.all().collect(); Value::template(move |ctx| { @@ -192,22 +192,26 @@ pub fn stack(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { }) .collect(); - ctx.push_into_stack(StackNode { - dirs: Gen::new(ctx.state.dir, dir), - aspect: None, - children, - }); + let mut dirs = Gen::new(None, dir).unwrap_or(ctx.state.dirs); + + // If the directions become aligned, fix up the cross direction since + // that's the one that is not user-defined. + if dirs.main.axis() == dirs.cross.axis() { + dirs.cross = ctx.state.dirs.main; + } + + ctx.push_into_stack(StackNode { dirs, aspect: None, children }); }) } /// `grid`: Arrange children into a grid. pub fn grid(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let columns = args.named::<Tracks>(ctx, "columns").unwrap_or_default(); - let rows = args.named::<Tracks>(ctx, "rows").unwrap_or_default(); + let columns = args.named(ctx, "columns").unwrap_or_default(); + let rows = args.named(ctx, "rows").unwrap_or_default(); let gutter_columns = args.named(ctx, "gutter-columns"); let gutter_rows = args.named(ctx, "gutter-rows"); - let gutter = args + let default = args .named(ctx, "gutter") .map(|v| vec![TrackSizing::Linear(v)]) .unwrap_or_default(); @@ -217,22 +221,40 @@ pub fn grid(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let children: Vec<_> = args.all().collect(); + let tracks = Gen::new(columns, rows); + let gutter = Gen::new( + gutter_columns.unwrap_or_else(|| default.clone()), + gutter_rows.unwrap_or(default), + ); + Value::template(move |ctx| { let children = children .iter() .map(|child| ctx.exec_template_stack(child).into()) .collect(); - let cross_dir = column_dir.unwrap_or(ctx.state.dir); - let main_dir = row_dir.unwrap_or(cross_dir.axis().other().dir(true)); + let mut dirs = Gen::new(column_dir, row_dir).unwrap_or(ctx.state.dirs); + + // If the directions become aligned, try to fix up the direction which + // is not user-defined. + if dirs.main.axis() == dirs.cross.axis() { + let target = if column_dir.is_some() { + &mut dirs.main + } else { + &mut dirs.cross + }; + + *target = if target.axis() == ctx.state.dirs.cross.axis() { + ctx.state.dirs.main + } else { + ctx.state.dirs.cross + }; + } ctx.push_into_stack(GridNode { - dirs: Gen::new(cross_dir, main_dir), - tracks: Gen::new(columns.clone(), rows.clone()), - gutter: Gen::new( - gutter_columns.as_ref().unwrap_or(&gutter).clone(), - gutter_rows.as_ref().unwrap_or(&gutter).clone(), - ), + dirs, + tracks: tracks.clone(), + gutter: gutter.clone(), children, }) }) diff --git a/src/library/text.rs b/src/library/text.rs index b56cbcd3..54e9794a 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -1,17 +1,10 @@ -use crate::exec::{LineState, TextState}; +use crate::exec::{FontState, LineState}; use crate::layout::Paint; use super::*; /// `font`: Configure the font. pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let families: Vec<_> = args.all().collect(); - let list = if families.is_empty() { - args.named(ctx, "family") - } else { - Some(FontDef(families)) - }; - let size = args.eat::<Linear>().or_else(|| args.named(ctx, "size")); let style = args.named(ctx, "style"); let weight = args.named(ctx, "weight"); @@ -19,20 +12,25 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let top_edge = args.named(ctx, "top-edge"); let bottom_edge = args.named(ctx, "bottom-edge"); let fill = args.named(ctx, "fill"); + + let families: Vec<_> = args.all().collect(); + let list = if families.is_empty() { + args.named(ctx, "family") + } else { + Some(FontDef(Rc::new(families))) + }; + let serif = args.named(ctx, "serif"); let sans_serif = args.named(ctx, "sans-serif"); let monospace = args.named(ctx, "monospace"); + let body = args.expect::<Template>(ctx, "body").unwrap_or_default(); Value::template(move |ctx| { - let state = ctx.state.text_mut(); + let state = ctx.state.font_mut(); - if let Some(linear) = size { - state.size = linear.resolve(state.size); - } - - if let Some(FontDef(list)) = &list { - state.families_mut().list = list.clone(); + if let Some(size) = size { + state.size = size.resolve(state.size); } if let Some(style) = style { @@ -59,6 +57,10 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { state.fill = Paint::Color(fill); } + if let Some(FontDef(list)) = &list { + state.families_mut().list = list.clone(); + } + if let Some(FamilyDef(serif)) = &serif { state.families_mut().serif = serif.clone(); } @@ -75,41 +77,42 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { }) } -struct FontDef(Vec<FontFamily>); +struct FontDef(Rc<Vec<FontFamily>>); castable! { FontDef: "font family or array of font families", - Value::Str(string) => Self(vec![FontFamily::Named(string.to_lowercase())]), - Value::Array(values) => Self(values - .into_iter() - .filter_map(|v| v.cast().ok()) - .collect() - ), - @family: FontFamily => Self(vec![family.clone()]), + Value::Str(string) => Self(Rc::new(vec![FontFamily::Named(string.to_lowercase())])), + Value::Array(values) => Self(Rc::new( + values + .into_iter() + .filter_map(|v| v.cast().ok()) + .collect() + )), + @family: FontFamily => Self(Rc::new(vec![family.clone()])), } -struct FamilyDef(Vec<String>); +struct FamilyDef(Rc<Vec<String>>); castable! { FamilyDef: "string or array of strings", - Value::Str(string) => Self(vec![string.to_lowercase()]), - Value::Array(values) => Self(values - .into_iter() - .filter_map(|v| v.cast().ok()) - .map(|string: EcoString| string.to_lowercase()) - .collect() - ), + Value::Str(string) => Self(Rc::new(vec![string.to_lowercase()])), + Value::Array(values) => Self(Rc::new( + values + .into_iter() + .filter_map(|v| v.cast().ok()) + .map(|string: EcoString| string.to_lowercase()) + .collect() + )), } /// `par`: Configure paragraphs. pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let par_spacing = args.named(ctx, "spacing"); let line_spacing = args.named(ctx, "leading"); - let word_spacing = args.named(ctx, "word-spacing"); let body = args.expect::<Template>(ctx, "body").unwrap_or_default(); Value::template(move |ctx| { - let state = ctx.state.text_mut(); + let state = ctx.state.par_mut(); if let Some(par_spacing) = par_spacing { state.par_spacing = par_spacing; @@ -119,10 +122,6 @@ pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { state.line_spacing = line_spacing; } - if let Some(word_spacing) = word_spacing { - state.word_spacing = word_spacing; - } - ctx.parbreak(); body.exec(ctx); }) @@ -130,20 +129,23 @@ pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `lang`: Configure the language. pub fn lang(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let iso = args.eat::<EcoString>().map(|s| lang_dir(&s)); - let dir = match args.named::<Spanned<Dir>>(ctx, "dir") { - Some(dir) if dir.v.axis() == SpecAxis::Horizontal => Some(dir.v), - Some(dir) => { + let iso = args.eat::<EcoString>(); + let dir = if let Some(dir) = args.named::<Spanned<Dir>>(ctx, "dir") { + if dir.v.axis() == SpecAxis::Horizontal { + Some(dir.v) + } else { ctx.diag(error!(dir.span, "must be horizontal")); None } - None => None, + } else { + iso.as_deref().map(lang_dir) }; + let body = args.expect::<Template>(ctx, "body").unwrap_or_default(); Value::template(move |ctx| { - if let Some(dir) = dir.or(iso) { - ctx.state.dir = dir; + if let Some(dir) = dir { + ctx.state.dirs.cross = dir; } ctx.parbreak(); @@ -151,7 +153,7 @@ pub fn lang(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { }) } -/// The default direction for the language identified by `iso`. +/// The default direction for the language identified by the given `iso` code. fn lang_dir(iso: &str) -> Dir { match iso.to_ascii_lowercase().as_str() { "ar" | "he" | "fa" | "ur" | "ps" | "yi" => Dir::RTL, @@ -178,7 +180,7 @@ pub fn overline(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { fn line_impl( ctx: &mut EvalContext, args: &mut FuncArgs, - substate: fn(&mut TextState) -> &mut Option<Rc<LineState>>, + substate: fn(&mut FontState) -> &mut Option<Rc<LineState>>, ) -> Value { let stroke = args.eat().or_else(|| args.named(ctx, "stroke")); let thickness = args.eat::<Linear>().or_else(|| args.named(ctx, "thickness")); @@ -197,7 +199,7 @@ fn line_impl( }); Value::template(move |ctx| { - *substate(ctx.state.text_mut()) = state.clone(); + *substate(ctx.state.font_mut()) = state.clone(); body.exec(ctx); }) } |
