Reorganize library base
This commit is contained in:
parent
9db6e533cd
commit
0579fd4409
@ -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<Value> {
|
||||
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<Value> {
|
||||
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<Value> {
|
||||
let Spanned { v, span } = args.expect("numeric value")?;
|
||||
@ -115,28 +86,3 @@ pub fn mod_(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
|
||||
Ok(Value::Float(a % b))
|
||||
}
|
||||
|
||||
/// Create a sequence of numbers.
|
||||
pub fn range(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let first = args.expect::<i64>("end")?;
|
||||
let (start, end) = match args.eat::<i64>()? {
|
||||
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)))
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Create a grayscale color.
|
||||
pub fn luma(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
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<Value> {
|
||||
Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||
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<Value> {
|
||||
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%")?
|
||||
},
|
||||
}
|
149
library/src/base/create.rs
Normal file
149
library/src/base/create.rs
Normal file
@ -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<Value> {
|
||||
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<Value> {
|
||||
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<Value> {
|
||||
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<Value> {
|
||||
Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||
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<Value> {
|
||||
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<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::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<Value> {
|
||||
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<Value> {
|
||||
Ok(Value::Label(Label(args.expect("string")?)))
|
||||
}
|
||||
|
||||
/// Create a regular expression from a string.
|
||||
pub fn regex(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("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<Value> {
|
||||
let first = args.expect::<i64>("end")?;
|
||||
let (start, end) = match args.eat::<i64>()? {
|
||||
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)))
|
||||
}
|
@ -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<Value> {
|
||||
Ok(args.expect::<Value>("value")?.type_name().into())
|
||||
}
|
||||
|
||||
/// The string representation of a value.
|
||||
pub fn repr(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(args.expect::<Value>("value")?.repr().into())
|
||||
}
|
||||
|
||||
/// Ensure that a condition is fulfilled.
|
||||
pub fn assert(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
||||
|
@ -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<Value> {
|
||||
let number = args.expect::<usize>("number")?;
|
||||
let pattern = args.expect::<NumberingPattern>("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()
|
@ -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<Value> {
|
||||
Ok(args.expect::<Value>("value")?.repr().into())
|
||||
}
|
||||
|
||||
/// Convert a value to a string.
|
||||
pub fn str(_: &Vm, args: &mut Args) -> SourceResult<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::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<Value> {
|
||||
Ok(Value::Label(Label(args.expect("string")?)))
|
||||
}
|
||||
|
||||
/// Create blind text.
|
||||
pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
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<Value> {
|
||||
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("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<Value> {
|
||||
numbered(NumberingKind::Letter, args)
|
||||
}
|
||||
|
||||
/// Converts an integer into a roman numeral.
|
||||
pub fn roman(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
numbered(NumberingKind::Roman, args)
|
||||
}
|
||||
|
||||
/// Convert a number into a symbol.
|
||||
pub fn symbol(_: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
numbered(NumberingKind::Symbol, args)
|
||||
}
|
||||
|
||||
fn numbered(numbering: NumberingKind, args: &mut Args) -> SourceResult<Value> {
|
||||
let n = args.expect::<usize>("non-negative integer")?;
|
||||
Ok(Value::Str(numbering.apply(n).into()))
|
||||
}
|
@ -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);
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
mod behave;
|
||||
mod ext;
|
||||
mod numbering;
|
||||
|
||||
pub use behave::*;
|
||||
pub use ext::*;
|
||||
pub use numbering::*;
|
||||
|
@ -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.
|
||||
|
@ -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(),
|
||||
};
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
@ -1,4 +1,4 @@
|
||||
// Test color creation functions.
|
||||
// Test color creation functions and modification methods.
|
||||
// Ref: false
|
||||
|
||||
---
|
||||
|
13
tests/typ/base/numbering.typ
Normal file
13
tests/typ/base/numbering.typ
Normal file
@ -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")
|
@ -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)
|
||||
|
@ -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],
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user