summaryrefslogtreecommitdiff
path: root/library/src/compute
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/compute')
-rw-r--r--library/src/compute/calc.rs90
-rw-r--r--library/src/compute/create.rs196
-rw-r--r--library/src/compute/data.rs33
-rw-r--r--library/src/compute/foundations.rs28
-rw-r--r--library/src/compute/utility.rs14
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")?;