summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-07-29 13:21:25 +0200
committerLaurenz <laurmaedje@gmail.com>2021-07-29 13:28:19 +0200
commit2c6127dea611944abb09a0d38375ad7cf9baced0 (patch)
tree6572d169d4ce26edc38a880860ebae2f49639fb8 /src/library
parent7d15dc634b3be1b6e284bb6b2450e3736d3e6e8d (diff)
Refactor state
Diffstat (limited to 'src/library')
-rw-r--r--src/library/layout.rs84
-rw-r--r--src/library/text.rs96
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);
})
}