diff options
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/deco.rs | 4 | ||||
| -rw-r--r-- | src/library/grid.rs | 11 | ||||
| -rw-r--r-- | src/library/image.rs | 2 | ||||
| -rw-r--r-- | src/library/mod.rs | 6 | ||||
| -rw-r--r-- | src/library/pad.rs | 2 | ||||
| -rw-r--r-- | src/library/page.rs | 3 | ||||
| -rw-r--r-- | src/library/par.rs | 2 | ||||
| -rw-r--r-- | src/library/spacing.rs | 3 | ||||
| -rw-r--r-- | src/library/stack.rs | 3 | ||||
| -rw-r--r-- | src/library/text.rs | 152 | ||||
| -rw-r--r-- | src/library/utility.rs | 14 |
11 files changed, 90 insertions, 112 deletions
diff --git a/src/library/deco.rs b/src/library/deco.rs index 18ca2bb1..6ef5a97b 100644 --- a/src/library/deco.rs +++ b/src/library/deco.rs @@ -36,14 +36,14 @@ fn line_impl(args: &mut Args, kind: LineKind) -> TypResult<Value> { /// `link`: Typeset text as a link. pub fn link(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let url = args.expect::<Str>("url")?; + let url = args.expect::<EcoString>("url")?; let body = args.find().unwrap_or_else(|| { let mut template = Template::new(); template.text(url.trim_start_matches("mailto:").trim_start_matches("tel:")); template }); - Ok(Value::Template(body.decorate(Decoration::Link(url.into())))) + Ok(Value::Template(body.decorate(Decoration::Link(url)))) } /// A decoration for a frame. diff --git a/src/library/grid.rs b/src/library/grid.rs index af486496..c7e6b8e9 100644 --- a/src/library/grid.rs +++ b/src/library/grid.rs @@ -3,7 +3,8 @@ use super::prelude::*; /// `grid`: Arrange children into a grid. pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { castable! { - Vec<TrackSizing>: "integer or (auto, linear, fractional, or array thereof)", + Vec<TrackSizing>, + Expected: "integer or (auto, linear, fractional, or array thereof)", Value::Auto => vec![TrackSizing::Auto], Value::Length(v) => vec![TrackSizing::Linear(v.into())], Value::Relative(v) => vec![TrackSizing::Linear(v.into())], @@ -17,7 +18,8 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - TrackSizing: "auto, linear, or fractional", + TrackSizing, + Expected: "auto, linear, or fractional", Value::Auto => Self::Auto, Value::Length(v) => Self::Linear(v.into()), Value::Relative(v) => Self::Linear(v.into()), @@ -43,10 +45,7 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { GridNode { tracks: tracks.clone(), gutter: gutter.clone(), - children: children - .iter() - .map(|child| child.to_stack(&style).pack()) - .collect(), + children: children.iter().map(|child| child.to_stack(style).pack()).collect(), } }))) } diff --git a/src/library/image.rs b/src/library/image.rs index c2273502..b51e4e70 100644 --- a/src/library/image.rs +++ b/src/library/image.rs @@ -6,7 +6,7 @@ use crate::image::ImageId; /// `image`: An image. pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let path = args.expect::<Spanned<Str>>("path to image file")?; + let path = args.expect::<Spanned<EcoString>>("path to image file")?; let width = args.named("width")?; let height = args.named("height")?; diff --git a/src/library/mod.rs b/src/library/mod.rs index b0a42e83..e6cb0d9d 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -23,12 +23,12 @@ mod prelude { pub use std::rc::Rc; pub use crate::diag::{At, TypResult}; - pub use crate::eval::{Args, EvalContext, Str, Template, Value}; + pub use crate::eval::{Args, EvalContext, Template, Value}; pub use crate::frame::*; pub use crate::geom::*; pub use crate::layout::*; pub use crate::syntax::{Span, Spanned}; - pub use crate::util::OptionExt; + pub use crate::util::{EcoString, OptionExt}; } pub use self::image::*; @@ -47,8 +47,8 @@ pub use transform::*; pub use utility::*; use crate::eval::{Scope, Value}; -use crate::font::FontFamily; use crate::geom::*; +use crate::style::FontFamily; /// Construct a scope containing all standard library definitions. pub fn new() -> Scope { diff --git a/src/library/pad.rs b/src/library/pad.rs index 6457f603..8c3c0f53 100644 --- a/src/library/pad.rs +++ b/src/library/pad.rs @@ -19,7 +19,7 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { Ok(Value::Template(Template::from_block(move |style| { PadNode { padding, - child: body.to_stack(&style).pack(), + child: body.to_stack(style).pack(), } }))) } diff --git a/src/library/page.rs b/src/library/page.rs index b31a32a3..16e6283d 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -4,7 +4,8 @@ use crate::style::{Paper, PaperClass}; /// `page`: Configure pages. pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { castable! { - Paper: "string", + Paper, + Expected: "string", Value::Str(string) => Paper::from_name(&string).ok_or("unknown paper")?, } diff --git a/src/library/par.rs b/src/library/par.rs index 3330eedf..eeb46dd8 100644 --- a/src/library/par.rs +++ b/src/library/par.rs @@ -34,7 +34,7 @@ pub fn par(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// `lang`: Configure the language. pub fn lang(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let iso = args.find::<Str>(); + let iso = args.find::<EcoString>(); let dir = if let Some(dir) = args.named::<Spanned<Dir>>("dir")? { if dir.v.axis() == SpecAxis::Horizontal { Some(dir.v) diff --git a/src/library/spacing.rs b/src/library/spacing.rs index 23328c86..26f1bee1 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -24,7 +24,8 @@ pub enum Spacing { } castable! { - Spacing: "linear or fractional", + Spacing, + Expected: "linear or fractional", Value::Length(v) => Self::Linear(v.into()), Value::Relative(v) => Self::Linear(v.into()), Value::Linear(v) => Self::Linear(v), diff --git a/src/library/stack.rs b/src/library/stack.rs index 80ed507b..ffd9b44f 100644 --- a/src/library/stack.rs +++ b/src/library/stack.rs @@ -11,7 +11,8 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - Child: "linear, fractional or template", + Child, + Expected: "linear, fractional or template", Value::Length(v) => Self::Spacing(Spacing::Linear(v.into())), Value::Relative(v) => Self::Spacing(Spacing::Linear(v.into())), Value::Linear(v) => Self::Spacing(Spacing::Linear(v)), diff --git a/src/library/text.rs b/src/library/text.rs index 4cf94bde..914122a1 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -7,48 +7,42 @@ use ttf_parser::Tag; use super::prelude::*; use crate::font::{ - Face, FaceId, FontFamily, FontStore, FontStretch, FontStyle, FontVariant, FontWeight, + Face, FaceId, FontStore, FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric, }; use crate::geom::{Dir, Em, Length, Point, Size}; use crate::style::{ - FontFeatures, NumberPosition, NumberType, NumberWidth, Style, TextStyle, + FontFamily, FontFeatures, NumberPosition, NumberType, NumberWidth, Style, + StylisticSet, TextStyle, }; -use crate::util::SliceExt; +use crate::util::{EcoString, SliceExt}; /// `font`: Configure the font. pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - struct FontDef(Rc<Vec<FontFamily>>); - struct FamilyDef(Rc<Vec<String>>); - struct FeatureList(Vec<(Tag, u32)>); - struct StylisticSet(Option<u8>); - castable! { - FontDef: "font family or array of font families", - 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()])), + Vec<FontFamily>, + Expected: "string, generic family or array thereof", + Value::Str(string) => vec![FontFamily::Named(string.to_lowercase())], + Value::Array(values) => { + values.into_iter().filter_map(|v| v.cast().ok()).collect() + }, + @family: FontFamily => vec![family.clone()], } castable! { - FamilyDef: "string or array of strings", - 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: Str| string.to_lowercase()) - .collect() - )), + Vec<EcoString>, + Expected: "string or array of strings", + Value::Str(string) => vec![string.to_lowercase()], + Value::Array(values) => values + .into_iter() + .filter_map(|v| v.cast().ok()) + .map(|string: EcoString| string.to_lowercase()) + .collect(), } castable! { - FontStyle: "string", + FontStyle, + Expected: "string", Value::Str(string) => match string.as_str() { "normal" => Self::Normal, "italic" => Self::Italic, @@ -58,7 +52,8 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - FontWeight: "integer or string", + FontWeight, + Expected: "integer or string", Value::Int(v) => v.try_into().map_or(Self::BLACK, Self::from_number), Value::Str(string) => match string.as_str() { "thin" => Self::THIN, @@ -75,12 +70,14 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - FontStretch: "relative", + FontStretch, + Expected: "relative", Value::Relative(v) => Self::from_ratio(v.get() as f32), } castable! { - VerticalFontMetric: "linear or string", + VerticalFontMetric, + Expected: "linear or string", Value::Length(v) => Self::Linear(v.into()), Value::Relative(v) => Self::Linear(v.into()), Value::Linear(v) => Self::Linear(v), @@ -95,7 +92,8 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - StylisticSet: "none or integer", + StylisticSet, + Expected: "none or integer", Value::None => Self(None), Value::Int(v) => match v { 1 ..= 20 => Self(Some(v as u8)), @@ -104,7 +102,8 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - NumberType: "auto or string", + NumberType, + Expected: "auto or string", Value::Auto => Self::Auto, Value::Str(string) => match string.as_str() { "lining" => Self::Lining, @@ -114,7 +113,8 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - NumberWidth: "auto or string", + NumberWidth, + Expected: "auto or string", Value::Auto => Self::Auto, Value::Str(string) => match string.as_str() { "proportional" => Self::Proportional, @@ -124,7 +124,8 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - NumberPosition: "string", + NumberPosition, + Expected: "string", Value::Str(string) => match string.as_str() { "normal" => Self::Normal, "subscript" => Self::Subscript, @@ -134,44 +135,39 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } castable! { - FeatureList: "array of strings or dictionary mapping tags to integers", - Value::Array(values) => Self( - values - .into_iter() - .filter_map(|v| v.cast().ok()) - .map(|string: Str| (Tag::from_bytes_lossy(string.as_bytes()), 1)) - .collect() - ), - Value::Dict(values) => Self( - values - .into_iter() - .filter_map(|(k, v)| { - let tag = Tag::from_bytes_lossy(k.as_bytes()); - let num = v.cast::<i64>().ok()?.try_into().ok()?; - Some((tag, num)) - }) - .collect() - ), + Vec<(Tag, u32)>, + Expected: "array of strings or dictionary mapping tags to integers", + Value::Array(values) => values + .into_iter() + .filter_map(|v| v.cast().ok()) + .map(|string: EcoString| (Tag::from_bytes_lossy(string.as_bytes()), 1)) + .collect(), + Value::Dict(values) => values + .into_iter() + .filter_map(|(k, v)| { + let tag = Tag::from_bytes_lossy(k.as_bytes()); + let num = v.cast::<i64>().ok()?.try_into().ok()?; + Some((tag, num)) + }) + .collect(), } let list = args.named("family")?.or_else(|| { let families: Vec<_> = args.all().collect(); - (!families.is_empty()).then(|| FontDef(Rc::new(families))) + (!families.is_empty()).then(|| families) }); let serif = args.named("serif")?; let sans_serif = args.named("sans-serif")?; let monospace = args.named("monospace")?; let fallback = args.named("fallback")?; - - let size = args.named::<Linear>("size")?.or_else(|| args.find()); let style = args.named("style")?; let weight = args.named("weight")?; let stretch = args.named("stretch")?; - let fill = args.named("fill")?.or_else(|| args.find()); + let size = args.named::<Linear>("size")?.or_else(|| args.find()); let top_edge = args.named("top-edge")?; let bottom_edge = args.named("bottom-edge")?; - + let fill = args.named("fill")?.or_else(|| args.find()); let kerning = args.named("kerning")?; let smallcaps = args.named("smallcaps")?; let alternates = args.named("alternates")?; @@ -199,22 +195,6 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let f = move |style_: &mut Style| { let text = style_.text_mut(); - if let Some(FontDef(list)) = &list { - text.families_mut().list = list.clone(); - } - - if let Some(FamilyDef(serif)) = &serif { - text.families_mut().serif = serif.clone(); - } - - if let Some(FamilyDef(sans_serif)) = &sans_serif { - text.families_mut().sans_serif = sans_serif.clone(); - } - - if let Some(FamilyDef(monospace)) = &monospace { - text.families_mut().monospace = monospace.clone(); - } - if let Some(size) = size { text.size = size.resolve(text.size); } @@ -223,16 +203,21 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { text.fill = Paint::Color(fill); } - set!(text.fallback => fallback); set!(text.variant.style => style); set!(text.variant.weight => weight); set!(text.variant.stretch => stretch); set!(text.top_edge => top_edge); set!(text.bottom_edge => bottom_edge); + set!(text.fallback => fallback); + set!(text.families_mut().list => list.clone()); + set!(text.families_mut().serif => serif.clone()); + set!(text.families_mut().sans_serif => sans_serif.clone()); + set!(text.families_mut().monospace => monospace.clone()); set!(text.features_mut().kerning => kerning); set!(text.features_mut().smallcaps => smallcaps); set!(text.features_mut().alternates => alternates); + set!(text.features_mut().stylistic_set => stylistic_set); set!(text.features_mut().ligatures.standard => ligatures); set!(text.features_mut().ligatures.discretionary => discretionary_ligatures); set!(text.features_mut().ligatures.historical => historical_ligatures); @@ -241,14 +226,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { set!(text.features_mut().numbers.position => number_position); set!(text.features_mut().numbers.slashed_zero => slashed_zero); set!(text.features_mut().numbers.fractions => fractions); - - if let Some(StylisticSet(stylistic_set)) = stylistic_set { - text.features_mut().stylistic_set = stylistic_set; - } - - if let Some(FeatureList(features)) = &features { - text.features_mut().raw = features.clone(); - } + set!(text.features_mut().raw => features.clone()); }; Ok(if let Some(body) = body { @@ -638,12 +616,10 @@ fn tags(features: &FontFeatures) -> Vec<Feature> { feat(b"salt", 1); } - let set_tag; - if let Some(set) = features.stylistic_set { - if matches!(set, 1 ..= 20) { - set_tag = [b's', b's', b'0' + set / 10, b'0' + set % 10]; - feat(&set_tag, 1); - } + let storage; + if let StylisticSet(Some(set @ 1 ..= 20)) = features.stylistic_set { + storage = [b's', b's', b'0' + set / 10, b'0' + set % 10]; + feat(&storage, 1); } if !features.ligatures.standard { diff --git a/src/library/utility.rs b/src/library/utility.rs index 69ae235d..6d15a823 100644 --- a/src/library/utility.rs +++ b/src/library/utility.rs @@ -77,8 +77,8 @@ pub fn float(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Str(match v { - Value::Int(v) => format_str!("{}", v), - Value::Float(v) => format_str!("{}", v), + Value::Int(v) => format_eco!("{}", v), + Value::Float(v) => format_eco!("{}", v), Value::Str(v) => v, v => bail!(span, "cannot convert {} to string", v.type_name()), })) @@ -87,7 +87,7 @@ pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// `rgb`: Create an RGB(A) color. pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { Ok(Value::Color(Color::Rgba( - if let Some(string) = args.find::<Spanned<Str>>() { + if let Some(string) = args.find::<Spanned<EcoString>>() { match RgbaColor::from_str(&string.v) { Ok(color) => color, Err(_) => bail!(string.span, "invalid hex string"), @@ -98,7 +98,7 @@ pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let b = args.expect("blue component")?; let a = args.eat()?.unwrap_or(Spanned::new(1.0, Span::detached())); let f = |Spanned { v, span }: Spanned<f64>| { - if 0.0 <= v && v <= 1.0 { + if (0.0 ..= 1.0).contains(&v) { Ok((v * 255.0).round() as u8) } else { bail!(span, "value must be between 0.0 and 1.0"); @@ -182,19 +182,19 @@ pub fn range(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// `lower`: Convert a string to lowercase. pub fn lower(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - Ok(args.expect::<Str>("string")?.to_lowercase().into()) + Ok(args.expect::<EcoString>("string")?.to_lowercase().into()) } /// `upper`: Convert a string to uppercase. pub fn upper(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - Ok(args.expect::<Str>("string")?.to_uppercase().into()) + Ok(args.expect::<EcoString>("string")?.to_uppercase().into()) } /// `len`: The length of a string, an array or a dictionary. pub fn len(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let Spanned { v, span } = args.expect("collection")?; Ok(Value::Int(match v { - Value::Str(v) => v.len(), + Value::Str(v) => v.len() as i64, Value::Array(v) => v.len(), Value::Dict(v) => v.len(), v => bail!( |
