From 0579fd4409375aaa9fd8e87a06fd59097b5fcd97 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sat, 26 Nov 2022 16:59:20 +0100 Subject: [PATCH] Reorganize library base --- library/src/base/calc.rs | 54 -------- library/src/base/color.rs | 64 ---------- library/src/base/create.rs | 149 ++++++++++++++++++++++ library/src/base/mod.rs | 13 +- library/src/{shared => base}/numbering.rs | 13 +- library/src/base/string.rs | 58 --------- library/src/lib.rs | 22 ++-- library/src/shared/mod.rs | 2 - library/src/structure/list.rs | 2 +- src/model/methods.rs | 14 +- tests/ref/base/numbering.png | Bin 10634 -> 7112 bytes tests/ref/base/string.png | Bin 10614 -> 0 bytes tests/typ/base/color.typ | 2 +- tests/typ/base/numbering.typ | 13 ++ tests/typ/base/string.typ | 21 --- tests/typ/structure/enum.typ | 4 +- 16 files changed, 202 insertions(+), 229 deletions(-) delete mode 100644 library/src/base/color.rs create mode 100644 library/src/base/create.rs rename library/src/{shared => base}/numbering.rs (92%) delete mode 100644 library/src/base/string.rs delete mode 100644 tests/ref/base/string.png create mode 100644 tests/typ/base/numbering.typ diff --git a/library/src/base/calc.rs b/library/src/base/calc.rs index db40df061..3541e08cd 100644 --- a/library/src/base/calc.rs +++ b/library/src/base/calc.rs @@ -2,35 +2,6 @@ use std::cmp::Ordering; use crate::prelude::*; -/// Convert a value to an integer. -pub fn int(_: &Vm, args: &mut Args) -> SourceResult { - let Spanned { v, span } = args.expect("value")?; - Ok(Value::Int(match v { - Value::Bool(v) => v as i64, - Value::Int(v) => v, - Value::Float(v) => v as i64, - Value::Str(v) => match v.parse() { - Ok(v) => v, - Err(_) => bail!(span, "invalid integer"), - }, - v => bail!(span, "cannot convert {} to integer", v.type_name()), - })) -} - -/// Convert a value to a float. -pub fn float(_: &Vm, args: &mut Args) -> SourceResult { - let Spanned { v, span } = args.expect("value")?; - Ok(Value::Float(match v { - Value::Int(v) => v as f64, - Value::Float(v) => v, - Value::Str(v) => match v.parse() { - Ok(v) => v, - Err(_) => bail!(span, "invalid float"), - }, - v => bail!(span, "cannot convert {} to float", v.type_name()), - })) -} - /// The absolute value of a numeric value. pub fn abs(_: &Vm, args: &mut Args) -> SourceResult { let Spanned { v, span } = args.expect("numeric value")?; @@ -115,28 +86,3 @@ pub fn mod_(_: &Vm, args: &mut Args) -> SourceResult { Ok(Value::Float(a % b)) } - -/// Create a sequence of numbers. -pub fn range(_: &Vm, args: &mut Args) -> SourceResult { - let first = args.expect::("end")?; - let (start, end) = match args.eat::()? { - Some(second) => (first, second), - None => (0, first), - }; - - let step: i64 = match args.named("step")? { - Some(Spanned { v: 0, span }) => bail!(span, "step must not be zero"), - Some(Spanned { v, .. }) => v, - None => 1, - }; - - let mut x = start; - let mut seq = vec![]; - - while x.cmp(&end) == 0.cmp(&step) { - seq.push(Value::Int(x)); - x += step; - } - - Ok(Value::Array(Array::from_vec(seq))) -} diff --git a/library/src/base/color.rs b/library/src/base/color.rs deleted file mode 100644 index 2db41ebfb..000000000 --- a/library/src/base/color.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::str::FromStr; - -use crate::prelude::*; - -/// Create a grayscale color. -pub fn luma(_: &Vm, args: &mut Args) -> SourceResult { - let Component(luma) = args.expect("gray component")?; - Ok(Value::Color(LumaColor::new(luma).into())) -} - -/// Create an RGB(A) color. -pub fn rgb(_: &Vm, args: &mut Args) -> SourceResult { - Ok(Value::Color(if let Some(string) = args.find::>()? { - match RgbaColor::from_str(&string.v) { - Ok(color) => color.into(), - Err(msg) => bail!(string.span, msg), - } - } else { - let Component(r) = args.expect("red component")?; - let Component(g) = args.expect("green component")?; - let Component(b) = args.expect("blue component")?; - let Component(a) = args.eat()?.unwrap_or(Component(255)); - RgbaColor::new(r, g, b, a).into() - })) -} - -/// Create a CMYK color. -pub fn cmyk(_: &Vm, args: &mut Args) -> SourceResult { - let RatioComponent(c) = args.expect("cyan component")?; - let RatioComponent(m) = args.expect("magenta component")?; - let RatioComponent(y) = args.expect("yellow component")?; - let RatioComponent(k) = args.expect("key component")?; - Ok(Value::Color(CmykColor::new(c, m, y, k).into())) -} - -/// An integer or ratio component. -struct Component(u8); - -castable! { - Component, - Expected: "integer or ratio", - Value::Int(v) => match v { - 0 ..= 255 => Self(v as u8), - _ => Err("must be between 0 and 255")?, - }, - Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) { - Self((v.get() * 255.0).round() as u8) - } else { - Err("must be between 0% and 100%")? - }, -} - -/// A component that must be a ratio. -struct RatioComponent(u8); - -castable! { - RatioComponent, - Expected: "ratio", - Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) { - Self((v.get() * 255.0).round() as u8) - } else { - Err("must be between 0% and 100%")? - }, -} diff --git a/library/src/base/create.rs b/library/src/base/create.rs new file mode 100644 index 000000000..be8e822fe --- /dev/null +++ b/library/src/base/create.rs @@ -0,0 +1,149 @@ +use std::str::FromStr; + +use typst::model::Regex; + +use crate::prelude::*; + +/// Convert a value to an integer. +pub fn int(_: &Vm, args: &mut Args) -> SourceResult { + let Spanned { v, span } = args.expect("value")?; + Ok(Value::Int(match v { + Value::Bool(v) => v as i64, + Value::Int(v) => v, + Value::Float(v) => v as i64, + Value::Str(v) => match v.parse() { + Ok(v) => v, + Err(_) => bail!(span, "invalid integer"), + }, + v => bail!(span, "cannot convert {} to integer", v.type_name()), + })) +} + +/// Convert a value to a float. +pub fn float(_: &Vm, args: &mut Args) -> SourceResult { + let Spanned { v, span } = args.expect("value")?; + Ok(Value::Float(match v { + Value::Int(v) => v as f64, + Value::Float(v) => v, + Value::Str(v) => match v.parse() { + Ok(v) => v, + Err(_) => bail!(span, "invalid float"), + }, + v => bail!(span, "cannot convert {} to float", v.type_name()), + })) +} + +/// Create a grayscale color. +pub fn luma(_: &Vm, args: &mut Args) -> SourceResult { + let Component(luma) = args.expect("gray component")?; + Ok(Value::Color(LumaColor::new(luma).into())) +} + +/// Create an RGB(A) color. +pub fn rgb(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Value::Color(if let Some(string) = args.find::>()? { + match RgbaColor::from_str(&string.v) { + Ok(color) => color.into(), + Err(msg) => bail!(string.span, msg), + } + } else { + let Component(r) = args.expect("red component")?; + let Component(g) = args.expect("green component")?; + let Component(b) = args.expect("blue component")?; + let Component(a) = args.eat()?.unwrap_or(Component(255)); + RgbaColor::new(r, g, b, a).into() + })) +} + +/// Create a CMYK color. +pub fn cmyk(_: &Vm, args: &mut Args) -> SourceResult { + let RatioComponent(c) = args.expect("cyan component")?; + let RatioComponent(m) = args.expect("magenta component")?; + let RatioComponent(y) = args.expect("yellow component")?; + let RatioComponent(k) = args.expect("key component")?; + Ok(Value::Color(CmykColor::new(c, m, y, k).into())) +} + +/// An integer or ratio component. +struct Component(u8); + +castable! { + Component, + Expected: "integer or ratio", + Value::Int(v) => match v { + 0 ..= 255 => Self(v as u8), + _ => Err("must be between 0 and 255")?, + }, + Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) { + Self((v.get() * 255.0).round() as u8) + } else { + Err("must be between 0% and 100%")? + }, +} + +/// A component that must be a ratio. +struct RatioComponent(u8); + +castable! { + RatioComponent, + Expected: "ratio", + Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) { + Self((v.get() * 255.0).round() as u8) + } else { + Err("must be between 0% and 100%")? + }, +} + +/// Convert a value to a string. +pub fn str(_: &Vm, args: &mut Args) -> SourceResult { + 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::Label(label) => label.0.into(), + Value::Str(v) => v, + v => bail!(span, "cannot convert {} to string", v.type_name()), + })) +} + +/// Create a blind text string. +pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult { + let words: usize = args.expect("number of words")?; + Ok(Value::Str(lipsum::lipsum(words).into())) +} + +/// Create a label from a string. +pub fn label(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Value::Label(Label(args.expect("string")?))) +} + +/// Create a regular expression from a string. +pub fn regex(_: &Vm, args: &mut Args) -> SourceResult { + let Spanned { v, span } = args.expect::>("regular expression")?; + Ok(Regex::new(&v).at(span)?.into()) +} + +/// Create an array consisting of a sequence of numbers. +pub fn range(_: &Vm, args: &mut Args) -> SourceResult { + let first = args.expect::("end")?; + let (start, end) = match args.eat::()? { + Some(second) => (first, second), + None => (0, first), + }; + + let step: i64 = match args.named("step")? { + Some(Spanned { v: 0, span }) => bail!(span, "step must not be zero"), + Some(Spanned { v, .. }) => v, + None => 1, + }; + + let mut x = start; + let mut seq = vec![]; + + while x.cmp(&end) == 0.cmp(&step) { + seq.push(Value::Int(x)); + x += step; + } + + Ok(Value::Array(Array::from_vec(seq))) +} diff --git a/library/src/base/mod.rs b/library/src/base/mod.rs index 86ebd6665..501edd712 100644 --- a/library/src/base/mod.rs +++ b/library/src/base/mod.rs @@ -1,14 +1,14 @@ //! Foundational functions. mod calc; -mod color; +mod create; mod data; -mod string; +mod numbering; pub use self::calc::*; -pub use self::color::*; +pub use self::create::*; pub use self::data::*; -pub use self::string::*; +pub use self::numbering::*; use comemo::Track; use typst::model::{self, Route, Vm}; @@ -21,6 +21,11 @@ pub fn type_(_: &Vm, args: &mut Args) -> SourceResult { Ok(args.expect::("value")?.type_name().into()) } +/// The string representation of a value. +pub fn repr(_: &Vm, args: &mut Args) -> SourceResult { + Ok(args.expect::("value")?.repr().into()) +} + /// Ensure that a condition is fulfilled. pub fn assert(_: &Vm, args: &mut Args) -> SourceResult { let Spanned { v, span } = args.expect::>("condition")?; diff --git a/library/src/shared/numbering.rs b/library/src/base/numbering.rs similarity index 92% rename from library/src/shared/numbering.rs rename to library/src/base/numbering.rs index 739edafe1..ea45fbc6d 100644 --- a/library/src/shared/numbering.rs +++ b/library/src/base/numbering.rs @@ -1,9 +1,16 @@ use std::str::FromStr; -use typst::model::{castable, Value}; -use typst::util::{format_eco, EcoString}; use unscanny::Scanner; +use crate::prelude::*; + +/// Apply a numbering pattern to a number. +pub fn numbering(_: &Vm, args: &mut Args) -> SourceResult { + let number = args.expect::("number")?; + let pattern = args.expect::("pattern")?; + Ok(Value::Str(pattern.apply(number).into())) +} + /// A numbering pattern for lists or headings. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct NumberingPattern { @@ -129,7 +136,7 @@ impl NumberingKind { return '-'.into(); } - const SYMBOLS: &[char] = &['*', '†', '‡', '§', '‖', '¶']; + const SYMBOLS: &[char] = &['*', '†', '‡', '§', '¶', '‖']; let symbol = SYMBOLS[(n - 1) % SYMBOLS.len()]; let amount = ((n - 1) / SYMBOLS.len()) + 1; std::iter::repeat(symbol).take(amount).collect() diff --git a/library/src/base/string.rs b/library/src/base/string.rs deleted file mode 100644 index 9c3b95625..000000000 --- a/library/src/base/string.rs +++ /dev/null @@ -1,58 +0,0 @@ -use typst::model::Regex; - -use crate::prelude::*; -use crate::shared::NumberingKind; - -/// The string representation of a value. -pub fn repr(_: &Vm, args: &mut Args) -> SourceResult { - Ok(args.expect::("value")?.repr().into()) -} - -/// Convert a value to a string. -pub fn str(_: &Vm, args: &mut Args) -> SourceResult { - 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::Label(label) => label.0.into(), - Value::Str(v) => v, - v => bail!(span, "cannot convert {} to string", v.type_name()), - })) -} - -/// Create a label from a string. -pub fn label(_: &Vm, args: &mut Args) -> SourceResult { - Ok(Value::Label(Label(args.expect("string")?))) -} - -/// Create blind text. -pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult { - let words: usize = args.expect("number of words")?; - Ok(Value::Str(lipsum::lipsum(words).into())) -} - -/// Create a regular expression. -pub fn regex(_: &Vm, args: &mut Args) -> SourceResult { - let Spanned { v, span } = args.expect::>("regular expression")?; - Ok(Regex::new(&v).at(span)?.into()) -} - -/// Converts an integer into one or multiple letters. -pub fn letter(_: &Vm, args: &mut Args) -> SourceResult { - numbered(NumberingKind::Letter, args) -} - -/// Converts an integer into a roman numeral. -pub fn roman(_: &Vm, args: &mut Args) -> SourceResult { - numbered(NumberingKind::Roman, args) -} - -/// Convert a number into a symbol. -pub fn symbol(_: &Vm, args: &mut Args) -> SourceResult { - numbered(NumberingKind::Symbol, args) -} - -fn numbered(numbering: NumberingKind, args: &mut Args) -> SourceResult { - let n = args.expect::("non-negative integer")?; - Ok(Value::Str(numbering.apply(n).into())) -} diff --git a/library/src/lib.rs b/library/src/lib.rs index 11baacc37..6107cf42d 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -88,28 +88,26 @@ fn scope() -> Scope { // Base. std.def_fn("type", base::type_); + std.def_fn("repr", base::repr); std.def_fn("assert", base::assert); std.def_fn("eval", base::eval); std.def_fn("int", base::int); std.def_fn("float", base::float); + std.def_fn("luma", base::luma); + std.def_fn("rgb", base::rgb); + std.def_fn("cmyk", base::cmyk); + std.def_fn("str", base::str); + std.def_fn("lorem", base::lorem); + std.def_fn("label", base::label); + std.def_fn("regex", base::regex); + std.def_fn("range", base::range); + std.def_fn("numbering", base::numbering); std.def_fn("abs", base::abs); std.def_fn("min", base::min); std.def_fn("max", base::max); std.def_fn("even", base::even); std.def_fn("odd", base::odd); std.def_fn("mod", base::mod_); - std.def_fn("range", base::range); - std.def_fn("luma", base::luma); - std.def_fn("rgb", base::rgb); - std.def_fn("cmyk", base::cmyk); - std.def_fn("repr", base::repr); - std.def_fn("str", base::str); - std.def_fn("label", base::label); - std.def_fn("regex", base::regex); - std.def_fn("letter", base::letter); - std.def_fn("roman", base::roman); - std.def_fn("symbol", base::symbol); - std.def_fn("lorem", base::lorem); std.def_fn("csv", base::csv); std.def_fn("json", base::json); std.def_fn("xml", base::xml); diff --git a/library/src/shared/mod.rs b/library/src/shared/mod.rs index 55522190f..f54241cfc 100644 --- a/library/src/shared/mod.rs +++ b/library/src/shared/mod.rs @@ -2,8 +2,6 @@ mod behave; mod ext; -mod numbering; pub use behave::*; pub use ext::*; -pub use numbering::*; diff --git a/library/src/structure/list.rs b/library/src/structure/list.rs index d1727087d..462e0c32e 100644 --- a/library/src/structure/list.rs +++ b/library/src/structure/list.rs @@ -1,6 +1,6 @@ +use crate::base::NumberingPattern; use crate::layout::{BlockNode, GridNode, HNode, Spacing, TrackSizing}; use crate::prelude::*; -use crate::shared::NumberingPattern; use crate::text::{ParNode, SpaceNode, TextNode}; /// An unordered (bulleted) or ordered (numbered) list. diff --git a/src/model/methods.rs b/src/model/methods.rs index c5c12ed24..fc33bea97 100644 --- a/src/model/methods.rs +++ b/src/model/methods.rs @@ -17,6 +17,13 @@ pub fn call( let missing = || Err(missing_method(name, method)).at(span); let output = match value { + Value::Color(color) => match method { + "lighten" => Value::Color(color.lighten(args.expect("amount")?)), + "darken" => Value::Color(color.darken(args.expect("amount")?)), + "negate" => Value::Color(color.negate()), + _ => return missing(), + }, + Value::Str(string) => match method { "len" => Value::Int(string.len() as i64), "slice" => { @@ -108,13 +115,6 @@ pub fn call( _ => return missing(), }, - Value::Color(color) => match method { - "lighten" => Value::Color(color.lighten(args.expect("amount")?)), - "darken" => Value::Color(color.darken(args.expect("amount")?)), - "negate" => Value::Color(color.negate()), - _ => return missing(), - }, - _ => return missing(), }; diff --git a/tests/ref/base/numbering.png b/tests/ref/base/numbering.png index d4d575d918560752b95abca87674135f7d2c791f..aa34de2960efc5bda4a2616e7a88c7c52770a8d5 100644 GIT binary patch literal 7112 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 literal 10634 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 diff --git a/tests/typ/base/color.typ b/tests/typ/base/color.typ index 96d760634..aecd86b88 100644 --- a/tests/typ/base/color.typ +++ b/tests/typ/base/color.typ @@ -1,4 +1,4 @@ -// Test color creation functions. +// Test color creation functions and modification methods. // Ref: false --- diff --git a/tests/typ/base/numbering.typ b/tests/typ/base/numbering.typ new file mode 100644 index 000000000..200850bcd --- /dev/null +++ b/tests/typ/base/numbering.typ @@ -0,0 +1,13 @@ +// Test integrated numbering patterns. + +--- +#for i in range(9) { + numbering(i, "* and ") + numbering(i, "I") + [ for #i] + parbreak() +} + +--- +// Error: 12-14 must be at least zero +#numbering(-1, "1") diff --git a/tests/typ/base/string.typ b/tests/typ/base/string.typ index 3104a3eac..e724f5632 100644 --- a/tests/typ/base/string.typ +++ b/tests/typ/base/string.typ @@ -135,27 +135,6 @@ #test(upper(memes), "ARE MEMES GREAT?") #test(upper("Ελλάδα"), "ΕΛΛΆΔΑ") ---- -// Test integrated lower, upper and symbols. -// Ref: true - -#upper("Abc 8") -#upper[def] - -#lower("SCREAMING MUST BE SILENCED in " + roman(1672) + " years") - -#for i in range(9) { - symbol(i) - [ and ] - roman(i) - [ for #i] - parbreak() -} - --- // Error: 8-9 expected string or content, found integer #upper(1) - ---- -// Error: 9-11 must be at least zero -#symbol(-1) diff --git a/tests/typ/structure/enum.typ b/tests/typ/structure/enum.typ index 40aad625e..d4c30385f 100644 --- a/tests/typ/structure/enum.typ +++ b/tests/typ/structure/enum.typ @@ -12,7 +12,7 @@ --- // Test automatic numbering in summed content. #for i in range(5) { - [+ #roman(1 + i)] + [+ #numbering(1 + i, "I")] } --- @@ -42,7 +42,7 @@ start: 4, spacing: 0.65em - 3pt, tight: false, - label: n => text(fill: (red, green, blue)(mod(n, 3)), [#upper(letter(n))]), + label: n => text(fill: (red, green, blue)(mod(n, 3)), numbering(n, "A")), [Red], [Green], [Blue], )