diff options
Diffstat (limited to 'library/src/compute')
| -rw-r--r-- | library/src/compute/calc.rs | 90 | ||||
| -rw-r--r-- | library/src/compute/create.rs | 196 | ||||
| -rw-r--r-- | library/src/compute/data.rs | 33 | ||||
| -rw-r--r-- | library/src/compute/foundations.rs | 28 | ||||
| -rw-r--r-- | library/src/compute/utility.rs | 14 |
5 files changed, 276 insertions, 85 deletions
diff --git a/library/src/compute/calc.rs b/library/src/compute/calc.rs index 1984d5ef..873eff15 100644 --- a/library/src/compute/calc.rs +++ b/library/src/compute/calc.rs @@ -2,14 +2,22 @@ use std::cmp::Ordering; use crate::prelude::*; +/// # Absolute /// The absolute value of a numeric value. /// -/// # Parameters +/// ## Example +/// ``` +/// #abs(-5) \ +/// #abs(5pt - 2cm) \ +/// #abs(2fr) +/// ``` +/// +/// ## Parameters /// - value: ToAbs (positional, required) /// The value whose absolute value to calculate. /// -/// # Tags -/// - calculate +/// ## Category +/// calculate #[func] pub fn abs(args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<ToAbs>("value")?.0) @@ -22,32 +30,50 @@ castable! { ToAbs, v: i64 => Self(Value::Int(v.abs())), v: f64 => Self(Value::Float(v.abs())), + v: Length => Self(Value::Length(v.try_abs() + .ok_or_else(|| "cannot take absolute value of this length")?)), v: Angle => Self(Value::Angle(v.abs())), v: Ratio => Self(Value::Ratio(v.abs())), v: Fr => Self(Value::Fraction(v.abs())), } +/// # Minimum /// The minimum of a sequence of values. /// -/// # Parameters +/// ## Example +/// ``` +/// #min(1, -3, -5, 20, 3, 6) \ +/// #min("Typst", "in", "beta") +/// ``` +/// +/// ## Parameters /// - values: Value (positional, variadic) -/// The sequence of values. +/// The sequence of values from which to extract the minimum. +/// Must not be empty. /// -/// # Tags -/// - calculate +/// ## Category +/// calculate #[func] pub fn min(args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Less) } +/// # Maximum /// The maximum of a sequence of values. /// -/// # Parameters +/// ## Example +/// ``` +/// #max(1, -3, -5, 20, 3, 6) \ +/// #max("Typst", "in", "beta") +/// ``` +/// +/// ## Parameters /// - values: Value (positional, variadic) -/// The sequence of values. +/// The sequence of values from which to extract the maximum. +/// Must not be empty. /// -/// # Tags -/// - calculate +/// ## Category +/// calculate #[func] pub fn max(args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Greater) @@ -74,43 +100,67 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { Ok(extremum) } +/// # Even /// Whether an integer is even. /// -/// # Parameters +/// ## Example +/// ``` +/// #even(4) \ +/// #even(5) \ +/// { range(10).filter(even) } +/// ``` +/// +/// ## Parameters /// - value: i64 (positional, required) /// The number to check for evenness. /// -/// # Tags -/// - calculate +/// ## Category +/// calculate #[func] pub fn even(args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("value")? % 2 == 0)) } +/// # Odd /// Whether an integer is odd. /// -/// # Parameters +/// ## Example +/// ``` +/// #odd(4) \ +/// #odd(5) \ +/// { range(10).filter(odd) } +/// ``` +/// +/// +/// ## Parameters /// - value: i64 (positional, required) /// The number to check for oddness. /// -/// # Tags -/// - calculate +/// ## Category +/// calculate #[func] pub fn odd(args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("value")? % 2 != 0)) } +/// # Modulus /// The modulus of two numbers. /// -/// # Parameters +/// ## Example +/// ``` +/// #mod(20, 6) \ +/// #mod(1.75, 0.5) +/// ``` +/// +/// ## Parameters /// - dividend: ToMod (positional, required) /// The dividend of the modulus. /// /// - divisor: ToMod (positional, required) /// The divisor of the modulus. /// -/// # Tags -/// - calculate +/// ## Category +/// calculate #[func] pub fn mod_(args: &mut Args) -> SourceResult<Value> { let Spanned { v: v1, span: span1 } = args.expect("dividend")?; diff --git a/library/src/compute/create.rs b/library/src/compute/create.rs index cb693a1c..a34c0ba6 100644 --- a/library/src/compute/create.rs +++ b/library/src/compute/create.rs @@ -4,14 +4,27 @@ use typst::model::Regex; use crate::prelude::*; +/// # Integer /// Convert a value to an integer. /// -/// # Parameters +/// - Booleans are converted to `0` or `1`. +/// - Floats are floored to the next 64-bit integer. +/// - Strings are parsed in base 10. +/// +/// ## Example +/// ``` +/// #int(false) \ +/// #int(true) \ +/// #int(2.7) \ +/// { int("27") + int("4") } +/// ``` +/// +/// ## Parameters /// - value: ToInt (positional, required) /// The value that should be converted to an integer. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn int(args: &mut Args) -> SourceResult<Value> { Ok(Value::Int(args.expect::<ToInt>("value")?.0)) @@ -28,14 +41,29 @@ castable! { v: EcoString => Self(v.parse().map_err(|_| "not a valid integer")?), } +/// # Float /// Convert a value to a float. /// -/// # Parameters +/// - Booleans are converted to `0.0` or `1.0`. +/// - Integers are converted to the closest 64-bit float. +/// - Strings are parsed in base 10 to the closest 64-bit float. +/// Exponential notation is supported. +/// +/// ## Example +/// ``` +/// #float(false) \ +/// #float(true) \ +/// #float(4) \ +/// #float("2.7") \ +/// #float("1e5") +/// ``` +/// +/// ## Parameters /// - value: ToFloat (positional, required) /// The value that should be converted to a float. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn float(args: &mut Args) -> SourceResult<Value> { Ok(Value::Float(args.expect::<ToFloat>("value")?.0)) @@ -52,23 +80,45 @@ castable! { v: EcoString => Self(v.parse().map_err(|_| "not a valid float")?), } +/// # Luma /// Create a grayscale color. /// -/// # Parameters +/// ## Example +/// ``` +/// #for x in range(250, step: 50) { +/// square(fill: luma(x)) +/// } +/// ``` +/// +/// ## Parameters /// - gray: Component (positional, required) /// The gray component. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn luma(args: &mut Args) -> SourceResult<Value> { let Component(luma) = args.expect("gray component")?; Ok(Value::Color(LumaColor::new(luma).into())) } +/// # RGBA /// Create an RGB(A) color. /// -/// # Parameters +/// The color is specified in the sRGB color space. +/// +/// _Note:_ While you can specify transparent colors and Typst's preview will +/// render them correctly, the PDF export does not handle them properly at the +/// moment. This will be fixed in the future. +/// +/// ## Example +/// ``` +/// #square(fill: rgb("#b1f2eb")) +/// #square(fill: rgb(87, 127, 230)) +/// #square(fill: rgb(25%, 13%, 65%)) +/// ``` +/// +/// ## Parameters /// - hex: EcoString (positional) /// The color in hexademical notation. /// @@ -77,10 +127,11 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> { /// /// If this string is given, the individual components should not be given. /// -/// # Example +/// ### Example /// ``` -/// #let color = rgb("#239dad") -/// #text(16pt, color)[*Typst*] +/// #text(16pt, rgb("#239dad"))[ +/// *Typst* +/// ] /// ``` /// /// - red: Component (positional) @@ -95,8 +146,8 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> { /// - alpha: Component (positional) /// The alpha component. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn rgb(args: &mut Args) -> SourceResult<Value> { Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? { @@ -129,9 +180,21 @@ castable! { }, } +/// # CMYK /// Create a CMYK color. /// -/// # Parameters +/// This is useful if you want to target a specific printer. The conversion +/// to RGB for display preview might differ from how your printer reproduces +/// the color. +/// +/// ## Example +/// ``` +/// #square( +/// fill: cmyk(27%, 0%, 3%, 5%) +/// ) +/// ```` +/// +/// ## Parameters /// - cyan: RatioComponent (positional, required) /// The cyan component. /// @@ -144,8 +207,8 @@ castable! { /// - key: RatioComponent (positional, required) /// The key component. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn cmyk(args: &mut Args) -> SourceResult<Value> { let RatioComponent(c) = args.expect("cyan component")?; @@ -167,14 +230,27 @@ castable! { }, } +/// # String /// Convert a value to a string. /// -/// # Parameters +/// - Integers are formatted in base 10. +/// - Floats are formatted in base 10 and never in exponential notation. +/// - From labels the name is extracted. +/// +/// ## Example +/// ``` +/// #str(10) \ +/// #str(2.7) \ +/// #str(1e8) \ +/// #str(<intro>) +/// ``` +/// +/// ## Parameters /// - value: ToStr (positional, required) /// The value that should be converted to a string. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn str(args: &mut Args) -> SourceResult<Value> { Ok(Value::Str(args.expect::<ToStr>("value")?.0)) @@ -191,36 +267,94 @@ castable! { v: Str => Self(v), } +/// # Label /// Create a label from a string. /// -/// # Parameters +/// Inserting a label into content attaches it to the closest previous element +/// that is not a space. Then, the element can be [referenced](@ref) and styled +/// through the label. +/// +/// ## Example +/// ``` +/// #show <a>: set text(blue) +/// #show label("b"): set text(red) +/// +/// = Heading <a> +/// *Strong* #label("b") +/// ``` +/// +/// ## Syntax +/// This function also has dedicated syntax: You can create a label by enclosing +/// its name in angle brackets. This works both in markup and code. +/// +/// ## Parameters /// - name: EcoString (positional, required) /// The name of the label. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn label(args: &mut Args) -> SourceResult<Value> { Ok(Value::Label(Label(args.expect("string")?))) } +/// # Regex /// Create a regular expression from a string. /// -/// # Parameters +/// The result can be used as a show rule +/// [selector](/docs/reference/concepts/#selector) and with +/// [string methods](/docs/reference/concepts/#methods) like `find`, `split`, +/// and `replace`. +/// +/// [See here](https://docs.rs/regex/latest/regex/#syntax) for a specification +/// of the supported syntax. +/// +/// ## Example +/// ``` +/// // Works with show rules. +/// #show regex("\d+"): set text(red) +/// +/// The numbers 1 to 10. +/// +/// // Works with string methods. +/// { "a,b;c" +/// .split(regex("[,;]")) } +/// ``` +/// +/// ## Parameters /// - regex: EcoString (positional, required) -/// The regular expression. +/// The regular expression as a string. /// -/// # Tags -/// - create +/// Most regex escape sequences just work because they are not valid Typst +/// escape sequences. To produce regex escape sequences that are also valid in +/// Typst (e.g. `[\\]`), you need to escape twice. Thus, to match a verbatim +/// backslash, you would need to write `{regex("\\\\")}`. +/// +/// ## Category +/// create #[func] pub fn regex(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?; Ok(Regex::new(&v).at(span)?.into()) } +/// # Range /// Create an array consisting of a sequence of numbers. /// -/// # Parameters +/// If you pass just one positional parameter, it is interpreted as the `end` of +/// the range. If you pass two, they describe the `start` and `end` of the +/// range. +/// +/// ## Example +/// ``` +/// #range(5) \ +/// #range(2, 5) \ +/// #range(20, step: 4) \ +/// #range(21, step: 4) \ +/// #range(5, 2, step: -1) +/// ``` +/// +/// ## Parameters /// - start: i64 (positional) /// The start of the range (inclusive). /// @@ -230,8 +364,8 @@ pub fn regex(args: &mut Args) -> SourceResult<Value> { /// - step: i64 (named) /// The distance between the generated numbers. /// -/// # Tags -/// - create +/// ## Category +/// create #[func] pub fn range(args: &mut Args) -> SourceResult<Value> { let first = args.expect::<i64>("end")?; diff --git a/library/src/compute/data.rs b/library/src/compute/data.rs index ed87f78d..e947d617 100644 --- a/library/src/compute/data.rs +++ b/library/src/compute/data.rs @@ -4,6 +4,7 @@ use typst::diag::{format_xml_like_error, FileError}; use crate::prelude::*; +/// # CSV /// Read structured data from a CSV file. /// /// The CSV file will be read and parsed into a 2-dimensional array of strings: @@ -11,7 +12,7 @@ use crate::prelude::*; /// rows will be collected into a single array. Header rows will not be /// stripped. /// -/// # Example +/// ## Example /// ``` /// #let results = csv("/data.csv") /// @@ -21,7 +22,8 @@ use crate::prelude::*; /// ..results.flatten(), /// ) /// ``` -/// # Parameters +/// +/// ## Parameters /// - path: EcoString (positional, required) /// Path to a CSV file. /// - delimiter: Delimiter (named) @@ -29,8 +31,8 @@ use crate::prelude::*; /// Must be a single ASCII character. /// Defaults to a comma. /// -/// # Tags -/// - data-loading +/// ## Category +/// data-loading #[func] pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = @@ -95,6 +97,7 @@ fn format_csv_error(error: csv::Error) -> String { } } +/// # JSON /// Read structured data from a JSON file. /// /// The file must contain a valid JSON object or array. JSON objects will be @@ -108,7 +111,7 @@ fn format_csv_error(error: csv::Error) -> String { /// The JSON files in the example contain a object with the keys `temperature`, /// `unit`, and `weather`. /// -/// # Example +/// ## Example /// ``` /// #let forecast(day) = block[ /// #square( @@ -134,12 +137,12 @@ fn format_csv_error(error: csv::Error) -> String { /// #forecast(json("/tuesday.json")) /// ``` /// -/// # Parameters +/// ## Parameters /// - path: EcoString (positional, required) /// Path to a JSON file. /// -/// # Tags -/// - data-loading +/// ## Category +/// data-loading #[func] pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = @@ -177,12 +180,10 @@ fn convert_json(value: serde_json::Value) -> Value { /// Format the user-facing JSON error message. fn format_json_error(error: serde_json::Error) -> String { assert!(error.is_syntax() || error.is_eof()); - format!( - "failed to parse json file: syntax error in line {}", - error.line() - ) + format!("failed to parse json file: syntax error in line {}", error.line()) } +/// # XML /// Read structured data from an XML file. /// /// The XML file is parsed into an array of dictionaries and strings. XML nodes @@ -198,7 +199,7 @@ fn format_json_error(error: serde_json::Error) -> String { /// `content` tag contains one or more paragraphs, which are represented as `p` /// tags. /// -/// # Example +/// ## Example /// ``` /// #let findChild(elem, tag) = { /// elem.children @@ -232,12 +233,12 @@ fn format_json_error(error: serde_json::Error) -> String { /// } /// ``` /// -/// # Parameters +/// ## Parameters /// - path: EcoString (positional, required) /// Path to an XML file. /// -/// # Tags -/// - data-loading +/// ## Category +/// data-loading #[func] pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = diff --git a/library/src/compute/foundations.rs b/library/src/compute/foundations.rs index cb952d81..0ee0a628 100644 --- a/library/src/compute/foundations.rs +++ b/library/src/compute/foundations.rs @@ -4,40 +4,43 @@ use comemo::Track; use typst::model; use typst::syntax::Source; +/// # Type /// The name of a value's type. /// -/// # Parameters +/// ## Parameters /// - value: Value (positional, required) /// The value whose type's to determine. /// -/// # Tags -/// - foundations +/// ## Category +/// foundations #[func] pub fn type_(args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.type_name().into()) } +/// # Representation /// The string representation of a value. /// -/// # Parameters +/// ## Parameters /// - value: Value (positional, required) /// The value whose string representation to produce. /// -/// # Tags -/// - foundations +/// ## Category +/// foundations #[func] pub fn repr(args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.repr().into()) } +/// # Assert /// Ensure that a condition is fulfilled. /// -/// # Parameters +/// ## Parameters /// - condition: bool (positional, required) /// The condition that must be true for the assertion to pass. /// -/// # Tags -/// - foundations +/// ## Category +/// foundations #[func] pub fn assert(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?; @@ -47,14 +50,15 @@ pub fn assert(args: &mut Args) -> SourceResult<Value> { Ok(Value::None) } +/// # Evaluate /// Evaluate a string as Typst markup. /// -/// # Parameters +/// ## Parameters /// - source: String (positional, required) /// A string of Typst markup to evaluate. /// -/// # Tags -/// - foundations +/// ## Category +/// foundations #[func] pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?; diff --git a/library/src/compute/utility.rs b/library/src/compute/utility.rs index ffad740e..1a3511d0 100644 --- a/library/src/compute/utility.rs +++ b/library/src/compute/utility.rs @@ -3,31 +3,33 @@ use std::str::FromStr; use crate::prelude::*; use crate::text::Case; +/// # Blind Text /// Create blind text. /// -/// # Parameters +/// ## Parameters /// - words: usize (positional, required) /// The length of the blind text in words. /// -/// # Tags -/// - utility +/// ## Category +/// utility #[func] pub fn lorem(args: &mut Args) -> SourceResult<Value> { let words: usize = args.expect("number of words")?; Ok(Value::Str(lipsum::lipsum(words).into())) } +/// # Numbering /// Apply a numbering pattern to a sequence of numbers. /// -/// # Parameters +/// ## Parameters /// - pattern: NumberingPattern (positional, required) /// A string that defines how the numbering works. /// /// - numbers: NonZeroUsize (positional, variadic) /// The numbers to apply the pattern to. /// -/// # Tags -/// - utility +/// ## Category +/// utility #[func] pub fn numbering(args: &mut Args) -> SourceResult<Value> { let pattern = args.expect::<NumberingPattern>("pattern")?; |
