summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
Diffstat (limited to 'src/library')
-rw-r--r--src/library/deco.rs4
-rw-r--r--src/library/grid.rs11
-rw-r--r--src/library/image.rs2
-rw-r--r--src/library/mod.rs6
-rw-r--r--src/library/pad.rs2
-rw-r--r--src/library/page.rs3
-rw-r--r--src/library/par.rs2
-rw-r--r--src/library/spacing.rs3
-rw-r--r--src/library/stack.rs3
-rw-r--r--src/library/text.rs152
-rw-r--r--src/library/utility.rs14
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!(