mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Document parameters in comment
This commit is contained in:
parent
b6202b646a
commit
35b16e545b
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1221,6 +1221,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
"unscanny",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -7,7 +7,14 @@ use crate::text::{SpaceNode, TextNode, TextSize};
|
|||||||
|
|
||||||
/// A section heading.
|
/// A section heading.
|
||||||
///
|
///
|
||||||
/// Tags: basics.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The heading's contents.
|
||||||
|
/// - level: NonZeroUsize (named)
|
||||||
|
/// The logical nesting depth of the heading, starting from one.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - basics
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Prepare, Show, Finalize)]
|
#[capable(Prepare, Show, Finalize)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -5,7 +5,17 @@ use crate::text::{SpaceNode, TextNode};
|
|||||||
|
|
||||||
/// An unordered (bulleted) or ordered (numbered) list.
|
/// An unordered (bulleted) or ordered (numbered) list.
|
||||||
///
|
///
|
||||||
/// Tags: basics.
|
/// # Parameters
|
||||||
|
/// - items: Content (positional, variadic)
|
||||||
|
/// The contents of the list items.
|
||||||
|
/// - start: NonZeroUsize (named)
|
||||||
|
/// Which number to start the enumeration with.
|
||||||
|
/// - tight: bool (named)
|
||||||
|
/// Makes the list more compact, if enabled. This looks better if the items
|
||||||
|
/// fit into a single line each.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - basics
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -3,7 +3,22 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// A table of items.
|
/// A table of items.
|
||||||
///
|
///
|
||||||
/// Tags: basics.
|
/// # Parameters
|
||||||
|
/// - cells: Content (positional, variadic)
|
||||||
|
/// The contents of the table cells.
|
||||||
|
/// - rows: TrackSizings (named)
|
||||||
|
/// Defines the row sizes.
|
||||||
|
/// - columns: TrackSizings (named)
|
||||||
|
/// Defines the column sizes.
|
||||||
|
/// - gutter: TrackSizings (named)
|
||||||
|
/// Defines the gaps between rows & columns.
|
||||||
|
/// - column-gutter: TrackSizings (named)
|
||||||
|
/// Defines the gaps between columns. Takes precedence over `gutter`.
|
||||||
|
/// - row-gutter: TrackSizings (named)
|
||||||
|
/// Defines the gaps between rows. Takes precedence over `gutter`.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - basics
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -4,26 +4,37 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// The absolute value of a numeric value.
|
/// The absolute value of a numeric value.
|
||||||
///
|
///
|
||||||
/// Tags: calculate.
|
/// # Parameters
|
||||||
|
/// - value: ToAbs (positional, required)
|
||||||
|
/// The value whose absolute value to calculate.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - calculate
|
||||||
#[func]
|
#[func]
|
||||||
pub fn abs(args: &mut Args) -> SourceResult<Value> {
|
pub fn abs(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("numeric value")?;
|
Ok(args.expect::<ToAbs>("value")?.0)
|
||||||
Ok(match v {
|
}
|
||||||
Value::Int(v) => Value::Int(v.abs()),
|
|
||||||
Value::Float(v) => Value::Float(v.abs()),
|
/// A value of which the absolute value can be taken.
|
||||||
Value::Angle(v) => Value::Angle(v.abs()),
|
struct ToAbs(Value);
|
||||||
Value::Ratio(v) => Value::Ratio(v.abs()),
|
|
||||||
Value::Fraction(v) => Value::Fraction(v.abs()),
|
castable! {
|
||||||
Value::Length(_) | Value::Relative(_) => {
|
ToAbs,
|
||||||
bail!(span, "cannot take absolute value of a length")
|
v: i64 => Self(Value::Int(v.abs())),
|
||||||
}
|
v: f64 => Self(Value::Float(v.abs())),
|
||||||
v => bail!(span, "expected numeric value, found {}", v.type_name()),
|
v: Angle => Self(Value::Angle(v.abs())),
|
||||||
})
|
v: Ratio => Self(Value::Ratio(v.abs())),
|
||||||
|
v: Fr => Self(Value::Fraction(v.abs())),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The minimum of a sequence of values.
|
/// The minimum of a sequence of values.
|
||||||
///
|
///
|
||||||
/// Tags: calculate.
|
/// # Parameters
|
||||||
|
/// - values: Value (positional, variadic)
|
||||||
|
/// The sequence of values.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - calculate
|
||||||
#[func]
|
#[func]
|
||||||
pub fn min(args: &mut Args) -> SourceResult<Value> {
|
pub fn min(args: &mut Args) -> SourceResult<Value> {
|
||||||
minmax(args, Ordering::Less)
|
minmax(args, Ordering::Less)
|
||||||
@ -31,7 +42,12 @@ pub fn min(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// The maximum of a sequence of values.
|
/// The maximum of a sequence of values.
|
||||||
///
|
///
|
||||||
/// Tags: calculate.
|
/// # Parameters
|
||||||
|
/// - values: Value (positional, variadic)
|
||||||
|
/// The sequence of values.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - calculate
|
||||||
#[func]
|
#[func]
|
||||||
pub fn max(args: &mut Args) -> SourceResult<Value> {
|
pub fn max(args: &mut Args) -> SourceResult<Value> {
|
||||||
minmax(args, Ordering::Greater)
|
minmax(args, Ordering::Greater)
|
||||||
@ -60,27 +76,44 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// Whether an integer is even.
|
/// Whether an integer is even.
|
||||||
///
|
///
|
||||||
/// Tags: calculate.
|
/// # Parameters
|
||||||
|
/// - value: i64 (positional, required)
|
||||||
|
/// The number to check for evenness.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - calculate
|
||||||
#[func]
|
#[func]
|
||||||
pub fn even(args: &mut Args) -> SourceResult<Value> {
|
pub fn even(args: &mut Args) -> SourceResult<Value> {
|
||||||
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
|
Ok(Value::Bool(args.expect::<i64>("value")? % 2 == 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether an integer is odd.
|
/// Whether an integer is odd.
|
||||||
///
|
///
|
||||||
/// Tags: calculate.
|
/// # Parameters
|
||||||
|
/// - value: i64 (positional, required)
|
||||||
|
/// The number to check for oddness.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - calculate
|
||||||
#[func]
|
#[func]
|
||||||
pub fn odd(args: &mut Args) -> SourceResult<Value> {
|
pub fn odd(args: &mut Args) -> SourceResult<Value> {
|
||||||
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
|
Ok(Value::Bool(args.expect::<i64>("value")? % 2 != 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The modulo of two numbers.
|
/// The modulus of two numbers.
|
||||||
///
|
///
|
||||||
/// Tags: calculate.
|
/// # Parameters
|
||||||
|
/// - dividend: ToMod (positional, required)
|
||||||
|
/// The dividend of the modulus.
|
||||||
|
/// - divisor: ToMod (positional, required)
|
||||||
|
/// The divisor of the modulus.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - calculate
|
||||||
#[func]
|
#[func]
|
||||||
pub fn mod_(args: &mut Args) -> SourceResult<Value> {
|
pub fn mod_(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v: v1, span: span1 } = args.expect("integer or float")?;
|
let Spanned { v: v1, span: span1 } = args.expect("dividend")?;
|
||||||
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
|
let Spanned { v: v2, span: span2 } = args.expect("divisor")?;
|
||||||
|
|
||||||
let (a, b) = match (v1, v2) {
|
let (a, b) = match (v1, v2) {
|
||||||
(Value::Int(a), Value::Int(b)) => match a.checked_rem(b) {
|
(Value::Int(a), Value::Int(b)) => match a.checked_rem(b) {
|
||||||
@ -104,3 +137,12 @@ pub fn mod_(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
Ok(Value::Float(a % b))
|
Ok(Value::Float(a % b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A value which can be passed to the `mod` function.
|
||||||
|
struct ToMod;
|
||||||
|
|
||||||
|
castable! {
|
||||||
|
ToMod,
|
||||||
|
_: i64 => Self,
|
||||||
|
_: f64 => Self,
|
||||||
|
}
|
||||||
|
@ -6,42 +6,60 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Convert a value to an integer.
|
/// Convert a value to an integer.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - value: ToInt (positional, required)
|
||||||
|
/// The value that should be converted to an integer.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn int(args: &mut Args) -> SourceResult<Value> {
|
pub fn int(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("value")?;
|
Ok(Value::Int(args.expect::<ToInt>("value")?.0))
|
||||||
Ok(Value::Int(match v {
|
}
|
||||||
Value::Bool(v) => v as i64,
|
|
||||||
Value::Int(v) => v,
|
/// A value that can be cast to an integer.
|
||||||
Value::Float(v) => v as i64,
|
struct ToInt(i64);
|
||||||
Value::Str(v) => match v.parse() {
|
|
||||||
Ok(v) => v,
|
castable! {
|
||||||
Err(_) => bail!(span, "invalid integer"),
|
ToInt,
|
||||||
},
|
v: bool => Self(v as i64),
|
||||||
v => bail!(span, "cannot convert {} to integer", v.type_name()),
|
v: i64 => Self(v),
|
||||||
}))
|
v: f64 => Self(v as i64),
|
||||||
|
v: EcoString => Self(v.parse().map_err(|_| "not a valid integer")?),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a value to a float.
|
/// Convert a value to a float.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - value: ToFloat (positional, required)
|
||||||
|
/// The value that should be converted to a float.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn float(args: &mut Args) -> SourceResult<Value> {
|
pub fn float(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("value")?;
|
Ok(Value::Float(args.expect::<ToFloat>("value")?.0))
|
||||||
Ok(Value::Float(match v {
|
}
|
||||||
Value::Int(v) => v as f64,
|
|
||||||
Value::Float(v) => v,
|
/// A value that can be cast to a float.
|
||||||
Value::Str(v) => match v.parse() {
|
struct ToFloat(f64);
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => bail!(span, "invalid float"),
|
castable! {
|
||||||
},
|
ToFloat,
|
||||||
v => bail!(span, "cannot convert {} to float", v.type_name()),
|
v: bool => Self(v as i64 as f64),
|
||||||
}))
|
v: i64 => Self(v as f64),
|
||||||
|
v: f64 => Self(v),
|
||||||
|
v: EcoString => Self(v.parse().map_err(|_| "not a valid float")?),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a grayscale color.
|
/// Create a grayscale color.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - gray: Component (positional, required)
|
||||||
|
/// The gray component.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn luma(args: &mut Args) -> SourceResult<Value> {
|
pub fn luma(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Component(luma) = args.expect("gray component")?;
|
let Component(luma) = args.expect("gray component")?;
|
||||||
@ -50,7 +68,26 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// Create an RGB(A) color.
|
/// Create an RGB(A) color.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - hex: EcoString (positional)
|
||||||
|
/// The color in hexademical notation.
|
||||||
|
///
|
||||||
|
/// Accepts three, four, six or eight hexadecimal digits and optionally
|
||||||
|
/// a leading hashtag.
|
||||||
|
///
|
||||||
|
/// If this string is given, the individual components should not be given.
|
||||||
|
///
|
||||||
|
/// - red: Component (positional)
|
||||||
|
/// The red component.
|
||||||
|
/// - green: Component (positional)
|
||||||
|
/// The green component.
|
||||||
|
/// - blue: Component (positional)
|
||||||
|
/// The blue component.
|
||||||
|
/// - alpha: Component (positional)
|
||||||
|
/// The alpha component.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn rgb(args: &mut Args) -> SourceResult<Value> {
|
pub fn rgb(args: &mut Args) -> SourceResult<Value> {
|
||||||
Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||||
@ -67,18 +104,6 @@ pub fn rgb(args: &mut Args) -> SourceResult<Value> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a CMYK color.
|
|
||||||
///
|
|
||||||
/// Tags: create.
|
|
||||||
#[func]
|
|
||||||
pub fn cmyk(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.
|
/// An integer or ratio component.
|
||||||
struct Component(u8);
|
struct Component(u8);
|
||||||
|
|
||||||
@ -95,6 +120,29 @@ castable! {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a CMYK color.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - cyan: RatioComponent (positional, required)
|
||||||
|
/// The cyan component.
|
||||||
|
/// - magenta: RatioComponent (positional, required)
|
||||||
|
/// The magenta component.
|
||||||
|
/// - yellow: RatioComponent (positional, required)
|
||||||
|
/// The yellow component.
|
||||||
|
/// - key: RatioComponent (positional, required)
|
||||||
|
/// The key component.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
|
#[func]
|
||||||
|
pub fn cmyk(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()))
|
||||||
|
}
|
||||||
|
|
||||||
/// A component that must be a ratio.
|
/// A component that must be a ratio.
|
||||||
struct RatioComponent(u8);
|
struct RatioComponent(u8);
|
||||||
|
|
||||||
@ -109,22 +157,36 @@ castable! {
|
|||||||
|
|
||||||
/// Convert a value to a string.
|
/// Convert a value to a string.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - value: ToStr (positional, required)
|
||||||
|
/// The value that should be converted to a string.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn str(args: &mut Args) -> SourceResult<Value> {
|
pub fn str(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("value")?;
|
Ok(Value::Str(args.expect::<ToStr>("value")?.0))
|
||||||
Ok(Value::Str(match v {
|
}
|
||||||
Value::Int(v) => format_str!("{}", v),
|
|
||||||
Value::Float(v) => format_str!("{}", v),
|
/// A value that can be cast to a string.
|
||||||
Value::Label(label) => label.0.into(),
|
struct ToStr(Str);
|
||||||
Value::Str(v) => v,
|
|
||||||
v => bail!(span, "cannot convert {} to string", v.type_name()),
|
castable! {
|
||||||
}))
|
ToStr,
|
||||||
|
v: i64 => Self(format_str!("{}", v)),
|
||||||
|
v: f64 => Self(format_str!("{}", v)),
|
||||||
|
v: Label => Self(v.0.into()),
|
||||||
|
v: Str => Self(v),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a label from a string.
|
/// Create a label from a string.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - name: EcoString (positional, required)
|
||||||
|
/// The name of the label.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn label(args: &mut Args) -> SourceResult<Value> {
|
pub fn label(args: &mut Args) -> SourceResult<Value> {
|
||||||
Ok(Value::Label(Label(args.expect("string")?)))
|
Ok(Value::Label(Label(args.expect("string")?)))
|
||||||
@ -132,7 +194,12 @@ pub fn label(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// Create a regular expression from a string.
|
/// Create a regular expression from a string.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - regex: EcoString (positional, required)
|
||||||
|
/// The regular expression.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn regex(args: &mut Args) -> SourceResult<Value> {
|
pub fn regex(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?;
|
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?;
|
||||||
@ -141,7 +208,18 @@ pub fn regex(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// Create an array consisting of a sequence of numbers.
|
/// Create an array consisting of a sequence of numbers.
|
||||||
///
|
///
|
||||||
/// Tags: create.
|
/// # Parameters
|
||||||
|
/// - start: i64 (positional)
|
||||||
|
/// The start of the range (inclusive).
|
||||||
|
///
|
||||||
|
/// - end: i64 (positional, required)
|
||||||
|
/// The end of the range (exclusive).
|
||||||
|
///
|
||||||
|
/// - step: i64 (named)
|
||||||
|
/// The distance between the generated numbers.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - create
|
||||||
#[func]
|
#[func]
|
||||||
pub fn range(args: &mut Args) -> SourceResult<Value> {
|
pub fn range(args: &mut Args) -> SourceResult<Value> {
|
||||||
let first = args.expect::<i64>("end")?;
|
let first = args.expect::<i64>("end")?;
|
||||||
|
@ -6,7 +6,12 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Read structured data from a CSV file.
|
/// Read structured data from a CSV file.
|
||||||
///
|
///
|
||||||
/// Tags: data-loading.
|
/// # Parameters
|
||||||
|
/// - path: EcoString (positional, required)
|
||||||
|
/// Path to a CSV file.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - data-loading
|
||||||
#[func]
|
#[func]
|
||||||
pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v: path, span } =
|
let Spanned { v: path, span } =
|
||||||
@ -49,7 +54,12 @@ fn format_csv_error(error: csv::Error) -> String {
|
|||||||
|
|
||||||
/// Read structured data from a JSON file.
|
/// Read structured data from a JSON file.
|
||||||
///
|
///
|
||||||
/// Tags: data-loading.
|
/// # Parameters
|
||||||
|
/// - path: EcoString (positional, required)
|
||||||
|
/// Path to a JSON file.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - data-loading
|
||||||
#[func]
|
#[func]
|
||||||
pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v: path, span } =
|
let Spanned { v: path, span } =
|
||||||
@ -92,7 +102,12 @@ fn format_json_error(error: serde_json::Error) -> String {
|
|||||||
|
|
||||||
/// Read structured data from an XML file.
|
/// Read structured data from an XML file.
|
||||||
///
|
///
|
||||||
/// Tags: data-loading.
|
/// # Parameters
|
||||||
|
/// - path: EcoString (positional, required)
|
||||||
|
/// Path to an XML file.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - data-loading
|
||||||
#[func]
|
#[func]
|
||||||
pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v: path, span } =
|
let Spanned { v: path, span } =
|
||||||
|
@ -6,7 +6,12 @@ use typst::syntax::Source;
|
|||||||
|
|
||||||
/// The name of a value's type.
|
/// The name of a value's type.
|
||||||
///
|
///
|
||||||
/// Tags: foundations.
|
/// # Parameters
|
||||||
|
/// - value: Value (positional, required)
|
||||||
|
/// The value whose type's to determine.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - foundations
|
||||||
#[func]
|
#[func]
|
||||||
pub fn type_(args: &mut Args) -> SourceResult<Value> {
|
pub fn type_(args: &mut Args) -> SourceResult<Value> {
|
||||||
Ok(args.expect::<Value>("value")?.type_name().into())
|
Ok(args.expect::<Value>("value")?.type_name().into())
|
||||||
@ -14,7 +19,12 @@ pub fn type_(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// The string representation of a value.
|
/// The string representation of a value.
|
||||||
///
|
///
|
||||||
/// Tags: foundations.
|
/// # Parameters
|
||||||
|
/// - value: Value (positional, required)
|
||||||
|
/// The value whose string representation to produce.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - foundations
|
||||||
#[func]
|
#[func]
|
||||||
pub fn repr(args: &mut Args) -> SourceResult<Value> {
|
pub fn repr(args: &mut Args) -> SourceResult<Value> {
|
||||||
Ok(args.expect::<Value>("value")?.repr().into())
|
Ok(args.expect::<Value>("value")?.repr().into())
|
||||||
@ -22,7 +32,12 @@ pub fn repr(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// Ensure that a condition is fulfilled.
|
/// Ensure that a condition is fulfilled.
|
||||||
///
|
///
|
||||||
/// Tags: foundations.
|
/// # Parameters
|
||||||
|
/// - condition: bool (positional, required)
|
||||||
|
/// The condition that must be true for the assertion to pass.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - foundations
|
||||||
#[func]
|
#[func]
|
||||||
pub fn assert(args: &mut Args) -> SourceResult<Value> {
|
pub fn assert(args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
||||||
@ -34,7 +49,12 @@ pub fn assert(args: &mut Args) -> SourceResult<Value> {
|
|||||||
|
|
||||||
/// Evaluate a string as Typst markup.
|
/// Evaluate a string as Typst markup.
|
||||||
///
|
///
|
||||||
/// Tags: foundations.
|
/// # Parameters
|
||||||
|
/// - source: String (positional, required)
|
||||||
|
/// A string of Typst markup to evaluate.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - foundations
|
||||||
#[func]
|
#[func]
|
||||||
pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
|
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
|
||||||
|
@ -3,18 +3,30 @@ use std::str::FromStr;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::text::Case;
|
use crate::text::Case;
|
||||||
|
|
||||||
/// Create a blind text string.
|
/// Create blind text.
|
||||||
///
|
///
|
||||||
/// Tags: utility.
|
/// # Parameters
|
||||||
|
/// - words: usize (positional, required)
|
||||||
|
/// The length of the blind text in words.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - utility
|
||||||
#[func]
|
#[func]
|
||||||
pub fn lorem(args: &mut Args) -> SourceResult<Value> {
|
pub fn lorem(args: &mut Args) -> SourceResult<Value> {
|
||||||
let words: usize = args.expect("number of words")?;
|
let words: usize = args.expect("number of words")?;
|
||||||
Ok(Value::Str(lipsum::lipsum(words).into()))
|
Ok(Value::Str(lipsum::lipsum(words).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a numbering pattern to a number.
|
/// Apply a numbering pattern to a sequence of numbers.
|
||||||
///
|
///
|
||||||
/// Tags: utility.
|
/// # 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
|
||||||
#[func]
|
#[func]
|
||||||
pub fn numbering(args: &mut Args) -> SourceResult<Value> {
|
pub fn numbering(args: &mut Args) -> SourceResult<Value> {
|
||||||
let pattern = args.expect::<NumberingPattern>("pattern")?;
|
let pattern = args.expect::<NumberingPattern>("pattern")?;
|
||||||
|
@ -2,7 +2,14 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Align content horizontally and vertically.
|
/// Align content horizontally and vertically.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to align.
|
||||||
|
/// - alignment: Axes<Option<GenAlign>> (positional, settable)
|
||||||
|
/// The alignment along both axes.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable]
|
#[capable]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -3,13 +3,20 @@ use crate::text::TextNode;
|
|||||||
|
|
||||||
/// Separate a region into multiple equally sized columns.
|
/// Separate a region into multiple equally sized columns.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - count: usize (positional, required)
|
||||||
|
/// The number of columns.
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content that should be layouted into the columns.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct ColumnsNode {
|
pub struct ColumnsNode {
|
||||||
/// How many columns there should be.
|
/// How many columns there should be.
|
||||||
pub columns: NonZeroUsize,
|
pub count: NonZeroUsize,
|
||||||
/// The child to be layouted into the columns. Most likely, this should be a
|
/// The child to be layouted into the columns. Most likely, this should be a
|
||||||
/// flow or stack node.
|
/// flow or stack node.
|
||||||
pub body: Content,
|
pub body: Content,
|
||||||
@ -23,7 +30,7 @@ impl ColumnsNode {
|
|||||||
|
|
||||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
columns: args.expect("column count")?,
|
count: args.expect("column count")?,
|
||||||
body: args.expect("body")?,
|
body: args.expect("body")?,
|
||||||
}
|
}
|
||||||
.pack())
|
.pack())
|
||||||
@ -44,7 +51,7 @@ impl Layout for ColumnsNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the width of the gutter and each column.
|
// Determine the width of the gutter and each column.
|
||||||
let columns = self.columns.get();
|
let columns = self.count.get();
|
||||||
let gutter = styles.get(Self::GUTTER).relative_to(regions.base.x);
|
let gutter = styles.get(Self::GUTTER).relative_to(regions.base.x);
|
||||||
let width = (regions.first.x - gutter * (columns - 1) as f64) / columns as f64;
|
let width = (regions.first.x - gutter * (columns - 1) as f64) / columns as f64;
|
||||||
|
|
||||||
@ -106,7 +113,13 @@ impl Layout for ColumnsNode {
|
|||||||
|
|
||||||
/// A column break.
|
/// A column break.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - weak: bool (named)
|
||||||
|
/// If true, the column break is skipped if the current column is already
|
||||||
|
/// empty.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Behave)]
|
#[capable(Behave)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
use super::VNode;
|
use super::VNode;
|
||||||
|
use crate::layout::Spacing;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// An inline-level container that sizes content.
|
/// An inline-level container that sizes content.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional)
|
||||||
|
/// The contents of the box.
|
||||||
|
/// - width: Rel<Length> (named)
|
||||||
|
/// The width of the box.
|
||||||
|
/// - height: Rel<Length> (named)
|
||||||
|
/// The height of the box.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -65,7 +75,20 @@ impl Inline for BoxNode {}
|
|||||||
|
|
||||||
/// A block-level container that places content into a separate flow.
|
/// A block-level container that places content into a separate flow.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional)
|
||||||
|
/// The contents of the block.
|
||||||
|
/// - spacing: Spacing (named, settable)
|
||||||
|
/// The spacing around this block.
|
||||||
|
/// - above: Spacing (named, settable)
|
||||||
|
/// The spacing between the previous and this block. Takes precedence over
|
||||||
|
/// `spacing`.
|
||||||
|
/// - below: Spacing (named, settable)
|
||||||
|
/// The spacing between this block and the following one. Takes precedence
|
||||||
|
/// over `spacing`.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -74,10 +97,10 @@ pub struct BlockNode(pub Content);
|
|||||||
#[node]
|
#[node]
|
||||||
impl BlockNode {
|
impl BlockNode {
|
||||||
/// The spacing between the previous and this block.
|
/// The spacing between the previous and this block.
|
||||||
#[property(reflect, skip)]
|
#[property(skip)]
|
||||||
pub const ABOVE: VNode = VNode::block_spacing(Em::new(1.2).into());
|
pub const ABOVE: VNode = VNode::block_spacing(Em::new(1.2).into());
|
||||||
/// The spacing between this and the following block.
|
/// The spacing between this and the following block.
|
||||||
#[property(reflect, skip)]
|
#[property(skip)]
|
||||||
pub const BELOW: VNode = VNode::block_spacing(Em::new(1.2).into());
|
pub const BELOW: VNode = VNode::block_spacing(Em::new(1.2).into());
|
||||||
/// Whether this block must stick to the following one.
|
/// Whether this block must stick to the following one.
|
||||||
#[property(skip)]
|
#[property(skip)]
|
||||||
|
@ -4,7 +4,22 @@ use super::Spacing;
|
|||||||
|
|
||||||
/// Arrange content in a grid.
|
/// Arrange content in a grid.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - cells: Content (positional, variadic)
|
||||||
|
/// The contents of the table cells.
|
||||||
|
/// - rows: TrackSizings (named)
|
||||||
|
/// Defines the row sizes.
|
||||||
|
/// - columns: TrackSizings (named)
|
||||||
|
/// Defines the column sizes.
|
||||||
|
/// - gutter: TrackSizings (named)
|
||||||
|
/// Defines the gaps between rows & columns.
|
||||||
|
/// - column-gutter: TrackSizings (named)
|
||||||
|
/// Defines the gaps between columns. Takes precedence over `gutter`.
|
||||||
|
/// - row-gutter: TrackSizings (named)
|
||||||
|
/// Defines the gaps between rows. Takes precedence over `gutter`.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,7 +2,12 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Hide content without affecting layout.
|
/// Hide content without affecting layout.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to hide.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,7 +2,26 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Pad content at the sides.
|
/// Pad content at the sides.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to pad at the sides.
|
||||||
|
/// - left: Rel<Length> (named)
|
||||||
|
/// The padding at the left side.
|
||||||
|
/// - right: Rel<Length> (named)
|
||||||
|
/// The padding at the right side.
|
||||||
|
/// - top: Rel<Length> (named)
|
||||||
|
/// The padding at the top side.
|
||||||
|
/// - bottom: Rel<Length> (named)
|
||||||
|
/// The padding at the bottom side.
|
||||||
|
/// - x: Rel<Length> (named)
|
||||||
|
/// The horizontal padding. Both `left` and `right` take precedence over this.
|
||||||
|
/// - y: Rel<Length> (named)
|
||||||
|
/// The vertical padding. Both `top` and `bottom` take precedence over this.
|
||||||
|
/// - rest: Rel<Length> (named)
|
||||||
|
/// The padding for all sides. All other parameters take precedence over this.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -6,7 +6,14 @@ use crate::text::TextNode;
|
|||||||
|
|
||||||
/// Layouts its child onto one or multiple pages.
|
/// Layouts its child onto one or multiple pages.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The contents of the page(s).
|
||||||
|
/// - paper: Paper (positional, settable)
|
||||||
|
/// The paper size.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable]
|
#[capable]
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
@ -14,9 +21,6 @@ pub struct PageNode(pub Content);
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl PageNode {
|
impl PageNode {
|
||||||
/// The paper size.
|
|
||||||
#[property(reflect, skip, shorthand)]
|
|
||||||
pub const PAPER: Paper = Paper::A4;
|
|
||||||
/// The unflipped width of the page.
|
/// The unflipped width of the page.
|
||||||
#[property(resolve)]
|
#[property(resolve)]
|
||||||
pub const WIDTH: Smart<Length> = Smart::Custom(Paper::A4.width().into());
|
pub const WIDTH: Smart<Length> = Smart::Custom(Paper::A4.width().into());
|
||||||
@ -91,7 +95,7 @@ impl PageNode {
|
|||||||
// Realize columns.
|
// Realize columns.
|
||||||
let columns = styles.get(Self::COLUMNS);
|
let columns = styles.get(Self::COLUMNS);
|
||||||
if columns.get() > 1 {
|
if columns.get() > 1 {
|
||||||
child = ColumnsNode { columns, body: self.0.clone() }.pack();
|
child = ColumnsNode { count: columns, body: self.0.clone() }.pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Realize margins.
|
// Realize margins.
|
||||||
@ -151,7 +155,12 @@ impl Debug for PageNode {
|
|||||||
|
|
||||||
/// A page break.
|
/// A page break.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - weak: bool (named)
|
||||||
|
/// If true, the page break is skipped if the current page is already empty.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable]
|
#[capable]
|
||||||
#[derive(Debug, Copy, Clone, Hash)]
|
#[derive(Debug, Copy, Clone, Hash)]
|
||||||
@ -266,7 +275,10 @@ macro_rules! papers {
|
|||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
Paper,
|
Paper,
|
||||||
$($pat => Self::$var,)*
|
$(
|
||||||
|
/// Produces a paper of the respective size.
|
||||||
|
$pat => Self::$var,
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,12 @@ use crate::text::{
|
|||||||
|
|
||||||
/// Arrange text, spacing and inline-level nodes into a paragraph.
|
/// Arrange text, spacing and inline-level nodes into a paragraph.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The contents of the paragraph.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable]
|
#[capable]
|
||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
@ -144,7 +149,8 @@ castable! {
|
|||||||
|
|
||||||
/// A paragraph break.
|
/// A paragraph break.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Unlabellable)]
|
#[capable(Unlabellable)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,7 +2,18 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Place content at an absolute position.
|
/// Place content at an absolute position.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - alignment: Axes<Option<GenAlign>> (positional)
|
||||||
|
/// Relative to which position in the parent container to place the content.
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to place.
|
||||||
|
/// - dx: Rel<Length> (named)
|
||||||
|
/// The horizontal displacement of the placed content.
|
||||||
|
/// - dy: Rel<Length> (named)
|
||||||
|
/// The vertical displacement of the placed content.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Behave)]
|
#[capable(Layout, Behave)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,7 +2,12 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Repeats content to fill a line.
|
/// Repeats content to fill a line.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to repeat.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,9 +2,18 @@ use std::cmp::Ordering;
|
|||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// Horizontal spacing.
|
/// Horizontal spacing in a paragraph.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - amount: Spacing (positional, required)
|
||||||
|
/// How much spacing to insert.
|
||||||
|
/// - weak: bool (named)
|
||||||
|
/// If true, the spacing collapses at the start or end of a paragraph.
|
||||||
|
/// Moreover, from multiple adjacent weak spacings all but the largest one
|
||||||
|
/// collapse.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Behave)]
|
#[capable(Behave)]
|
||||||
#[derive(Debug, Copy, Clone, Hash)]
|
#[derive(Debug, Copy, Clone, Hash)]
|
||||||
@ -55,7 +64,16 @@ impl Behave for HNode {
|
|||||||
|
|
||||||
/// Vertical spacing.
|
/// Vertical spacing.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - amount: Spacing (positional, required)
|
||||||
|
/// How much spacing to insert.
|
||||||
|
/// - weak: bool (named)
|
||||||
|
/// If true, the spacing collapses at the start or end of a flow.
|
||||||
|
/// Moreover, from multiple adjacent weak spacings all but the largest one
|
||||||
|
/// collapse.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Behave)]
|
#[capable(Behave)]
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd)]
|
||||||
@ -123,11 +141,6 @@ impl Behave for VNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
castable! {
|
|
||||||
VNode,
|
|
||||||
spacing: Spacing => VNode::block_around(spacing),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Kinds of spacing.
|
/// Kinds of spacing.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Spacing {
|
pub enum Spacing {
|
||||||
|
@ -5,7 +5,16 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Arrange content and spacing along an axis.
|
/// Arrange content and spacing along an axis.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - items: StackChild (positional, variadic)
|
||||||
|
/// The items to stack along an axis.
|
||||||
|
/// - dir: Dir (named)
|
||||||
|
/// The direction along which the items are stacked.
|
||||||
|
/// - spacing: Spacing (named)
|
||||||
|
/// Spacing to insert between items where no explicit spacing was provided.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout)]
|
#[capable(Layout)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -4,7 +4,16 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Move content without affecting layout.
|
/// Move content without affecting layout.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to move.
|
||||||
|
/// - dx: Rel<Length> (named)
|
||||||
|
/// The horizontal displacement of the content.
|
||||||
|
/// - dy: Rel<Length> (named)
|
||||||
|
/// The vertical displacement of the content.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -49,7 +58,18 @@ impl Inline for MoveNode {}
|
|||||||
|
|
||||||
/// Transform content without affecting layout.
|
/// Transform content without affecting layout.
|
||||||
///
|
///
|
||||||
/// Tags: layout.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to transform.
|
||||||
|
/// - angle: Angle (named)
|
||||||
|
/// The amount of rotation.
|
||||||
|
/// - x: Ratio (named)
|
||||||
|
/// The horizontal scaling factor.
|
||||||
|
/// - y: Ratio (named)
|
||||||
|
/// The vertical scaling factor.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - layout
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -50,7 +50,6 @@ fn scope() -> Scope {
|
|||||||
|
|
||||||
// Math.
|
// Math.
|
||||||
std.def_func::<math::MathNode>("math");
|
std.def_func::<math::MathNode>("math");
|
||||||
std.def_func::<math::AtomNode>("atom");
|
|
||||||
std.def_func::<math::AccNode>("acc");
|
std.def_func::<math::AccNode>("acc");
|
||||||
std.def_func::<math::FracNode>("frac");
|
std.def_func::<math::FracNode>("frac");
|
||||||
std.def_func::<math::BinomNode>("binom");
|
std.def_func::<math::BinomNode>("binom");
|
||||||
@ -203,7 +202,7 @@ fn items() -> LangItems {
|
|||||||
desc_item: |term, body| {
|
desc_item: |term, body| {
|
||||||
basics::ListItem::Desc(Box::new(basics::DescItem { term, body })).pack()
|
basics::ListItem::Desc(Box::new(basics::DescItem { term, body })).pack()
|
||||||
},
|
},
|
||||||
math: |children, display| math::MathNode { children, display }.pack(),
|
math: |children, block| math::MathNode { children, block }.pack(),
|
||||||
math_atom: |atom| math::AtomNode(atom).pack(),
|
math_atom: |atom| math::AtomNode(atom).pack(),
|
||||||
math_script: |base, sub, sup| math::ScriptNode { base, sub, sup }.pack(),
|
math_script: |base, sub, sup| math::ScriptNode { base, sub, sup }.pack(),
|
||||||
math_frac: |num, denom| math::FracNode { num, denom }.pack(),
|
math_frac: |num, denom| math::FracNode { num, denom }.pack(),
|
||||||
|
@ -2,7 +2,12 @@ use super::*;
|
|||||||
|
|
||||||
/// A column vector.
|
/// A column vector.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - elements: Content (positional, variadic)
|
||||||
|
/// The elements of the vector.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -66,7 +71,12 @@ castable! {
|
|||||||
|
|
||||||
/// A case distinction.
|
/// A case distinction.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - branches: Content (positional, variadic)
|
||||||
|
/// The branches of the case distinction.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -16,22 +16,35 @@ use crate::text::{FontFamily, LinebreakNode, SpaceNode, SymbolNode, TextNode};
|
|||||||
|
|
||||||
/// A piece of a mathematical formula.
|
/// A piece of a mathematical formula.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - items: Content (positional, variadic)
|
||||||
|
/// The individual parts of the formula.
|
||||||
|
/// - block: bool (named)
|
||||||
|
/// Whether the formula is displayed as a separate block.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show, Layout, Inline, Texify)]
|
#[capable(Show, Layout, Inline, Texify)]
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct MathNode {
|
pub struct MathNode {
|
||||||
/// Whether the formula is display-level.
|
/// Whether the formula is displayed as a separate block.
|
||||||
pub display: bool,
|
pub block: bool,
|
||||||
/// The pieces of the formula.
|
/// The pieces of the formula.
|
||||||
pub children: Vec<Content>,
|
pub children: Vec<Content>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl MathNode {
|
impl MathNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
let block = args.named("block")?.unwrap_or(false);
|
||||||
|
let children = args.all()?;
|
||||||
|
Ok(Self { block, children }.pack())
|
||||||
|
}
|
||||||
|
|
||||||
fn field(&self, name: &str) -> Option<Value> {
|
fn field(&self, name: &str) -> Option<Value> {
|
||||||
match name {
|
match name {
|
||||||
"display" => Some(Value::Bool(self.display)),
|
"block" => Some(Value::Bool(self.block)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,7 +61,7 @@ impl Show for MathNode {
|
|||||||
.guarded(Guard::Base(NodeId::of::<Self>()))
|
.guarded(Guard::Base(NodeId::of::<Self>()))
|
||||||
.styled_with_map(map);
|
.styled_with_map(map);
|
||||||
|
|
||||||
if self.display {
|
if self.block {
|
||||||
realized = realized.aligned(Axes::with_x(Some(Align::Center.into())))
|
realized = realized.aligned(Axes::with_x(Some(Align::Center.into())))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +78,7 @@ impl Layout for MathNode {
|
|||||||
) -> SourceResult<Fragment> {
|
) -> SourceResult<Fragment> {
|
||||||
let mut t = Texifier::new(styles);
|
let mut t = Texifier::new(styles);
|
||||||
self.texify(&mut t)?;
|
self.texify(&mut t)?;
|
||||||
Ok(layout_tex(vt, &t.finish(), self.display, styles)
|
Ok(layout_tex(vt, &t.finish(), self.block, styles)
|
||||||
.unwrap_or(Fragment::frame(Frame::new(Size::zero()))))
|
.unwrap_or(Fragment::frame(Frame::new(Size::zero()))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +260,12 @@ impl Texify for Content {
|
|||||||
|
|
||||||
/// An atom in a math formula: `x`, `+`, `12`.
|
/// An atom in a math formula: `x`, `+`, `12`.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - text: EcoString (positional, required)
|
||||||
|
/// The atom's text.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -288,7 +306,14 @@ impl Texify for AtomNode {
|
|||||||
|
|
||||||
/// An accented node.
|
/// An accented node.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - base: Content (positional, required)
|
||||||
|
/// The base to which the accent is applied.
|
||||||
|
/// - accent: Content (positional, required)
|
||||||
|
/// The accent to apply to the base.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -365,7 +390,14 @@ impl Texify for AccNode {
|
|||||||
|
|
||||||
/// A fraction.
|
/// A fraction.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - num: Content (positional, required)
|
||||||
|
/// The fraction's numerator.
|
||||||
|
/// - denom: Content (positional, required)
|
||||||
|
/// The fraction's denominator.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -398,7 +430,14 @@ impl Texify for FracNode {
|
|||||||
|
|
||||||
/// A binomial.
|
/// A binomial.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - upper: Content (positional, required)
|
||||||
|
/// The binomial's upper index.
|
||||||
|
/// - lower: Content (positional, required)
|
||||||
|
/// The binomial's lower index.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -431,7 +470,16 @@ impl Texify for BinomNode {
|
|||||||
|
|
||||||
/// A sub- and/or superscript.
|
/// A sub- and/or superscript.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - base: Content (positional, required)
|
||||||
|
/// The base to which the applies the sub- and/or superscript.
|
||||||
|
/// - sub: Content (named)
|
||||||
|
/// The subscript.
|
||||||
|
/// - sup: Content (named)
|
||||||
|
/// The superscript.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -445,7 +493,14 @@ pub struct ScriptNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl ScriptNode {}
|
impl ScriptNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
let base = args.expect("base")?;
|
||||||
|
let sub = args.named("sub")?;
|
||||||
|
let sup = args.named("sup")?;
|
||||||
|
Ok(Self { base, sub, sup }.pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Texify for ScriptNode {
|
impl Texify for ScriptNode {
|
||||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||||
@ -469,14 +524,23 @@ impl Texify for ScriptNode {
|
|||||||
|
|
||||||
/// A math alignment point: `&`, `&&`.
|
/// A math alignment point: `&`, `&&`.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - index: usize (positional, required)
|
||||||
|
/// The alignment point's index.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct AlignPointNode(pub usize);
|
pub struct AlignPointNode(pub NonZeroUsize);
|
||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl AlignPointNode {}
|
impl AlignPointNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
Ok(Self(args.expect("index")?).pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Texify for AlignPointNode {
|
impl Texify for AlignPointNode {
|
||||||
fn texify(&self, _: &mut Texifier) -> SourceResult<()> {
|
fn texify(&self, _: &mut Texifier) -> SourceResult<()> {
|
||||||
@ -486,7 +550,12 @@ impl Texify for AlignPointNode {
|
|||||||
|
|
||||||
/// A square root.
|
/// A square root.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The expression to take the square root of.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -510,7 +579,12 @@ impl Texify for SqrtNode {
|
|||||||
|
|
||||||
/// A floored expression.
|
/// A floored expression.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The expression to floor.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -534,7 +608,12 @@ impl Texify for FloorNode {
|
|||||||
|
|
||||||
/// A ceiled expression.
|
/// A ceiled expression.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The expression to ceil.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,7 +2,12 @@ use super::*;
|
|||||||
|
|
||||||
/// Serif (roman) font style.
|
/// Serif (roman) font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -26,7 +31,12 @@ impl Texify for SerifNode {
|
|||||||
|
|
||||||
/// Sans-serif font style.
|
/// Sans-serif font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -50,7 +60,12 @@ impl Texify for SansNode {
|
|||||||
|
|
||||||
/// Bold font style.
|
/// Bold font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -74,7 +89,12 @@ impl Texify for BoldNode {
|
|||||||
|
|
||||||
/// Italic font style.
|
/// Italic font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -98,7 +118,12 @@ impl Texify for ItalNode {
|
|||||||
|
|
||||||
/// Calligraphic font style.
|
/// Calligraphic font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -122,7 +147,12 @@ impl Texify for CalNode {
|
|||||||
|
|
||||||
/// Fraktur font style.
|
/// Fraktur font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -146,7 +176,12 @@ impl Texify for FrakNode {
|
|||||||
|
|
||||||
/// Monospace font style.
|
/// Monospace font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -170,7 +205,12 @@ impl Texify for MonoNode {
|
|||||||
|
|
||||||
/// Blackboard bold (double-struck) font style.
|
/// Blackboard bold (double-struck) font style.
|
||||||
///
|
///
|
||||||
/// Tags: math.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The piece of formula to style.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(Texify)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -3,7 +3,8 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// The root node that represents a full document.
|
/// The root node that represents a full document.
|
||||||
///
|
///
|
||||||
/// Tags: meta.
|
/// # Tags
|
||||||
|
/// - meta
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(LayoutRoot)]
|
#[capable(LayoutRoot)]
|
||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
|
@ -3,7 +3,14 @@ use crate::text::TextNode;
|
|||||||
|
|
||||||
/// Link text and other elements to a destination.
|
/// Link text and other elements to a destination.
|
||||||
///
|
///
|
||||||
/// Tags: meta.
|
/// # Parameters
|
||||||
|
/// - dest: Destination (positional, required)
|
||||||
|
/// The destination the link points to.
|
||||||
|
/// - body: Content (positional)
|
||||||
|
/// How the link is represented. Defaults to the destination if it is a link.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - meta
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show, Finalize)]
|
#[capable(Show, Finalize)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -5,7 +5,8 @@ use crate::text::{LinebreakNode, SpaceNode, TextNode};
|
|||||||
|
|
||||||
/// A section outline (table of contents).
|
/// A section outline (table of contents).
|
||||||
///
|
///
|
||||||
/// Tags: meta.
|
/// # Tags
|
||||||
|
/// - meta
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Prepare, Show)]
|
#[capable(Prepare, Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -3,7 +3,12 @@ use crate::text::TextNode;
|
|||||||
|
|
||||||
/// A reference to a label.
|
/// A reference to a label.
|
||||||
///
|
///
|
||||||
/// Tags: meta.
|
/// # Parameters
|
||||||
|
/// - target: Label (positional, required)
|
||||||
|
/// The label that should be referenced.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - meta
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -6,7 +6,12 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Typeset underline, stricken-through or overlined text.
|
/// Typeset underline, stricken-through or overlined text.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to decorate.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -3,7 +3,8 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// A text space.
|
/// A text space.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Unlabellable, Behave)]
|
#[capable(Unlabellable, Behave)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -26,7 +27,12 @@ impl Behave for SpaceNode {
|
|||||||
|
|
||||||
/// A line break.
|
/// A line break.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - justify: bool (named)
|
||||||
|
/// Whether to justify the line before the break.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Behave)]
|
#[capable(Behave)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -50,7 +56,12 @@ impl Behave for LinebreakNode {
|
|||||||
|
|
||||||
/// Strongly emphasizes content by increasing the font weight.
|
/// Strongly emphasizes content by increasing the font weight.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to strongly emphasize.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -98,7 +109,12 @@ impl Fold for Delta {
|
|||||||
|
|
||||||
/// Emphasizes content by flipping the italicness.
|
/// Emphasizes content by flipping the italicness.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content to emphasize.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -136,17 +152,27 @@ impl Fold for Toggle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a string or content to lowercase.
|
/// Convert text or content to lowercase.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - text: ToCase (positional, required)
|
||||||
|
/// The text to convert to lowercase.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
pub fn lower(args: &mut Args) -> SourceResult<Value> {
|
pub fn lower(args: &mut Args) -> SourceResult<Value> {
|
||||||
case(Case::Lower, args)
|
case(Case::Lower, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a string or content to uppercase.
|
/// Convert text or content to uppercase.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - text: ToCase (positional, required)
|
||||||
|
/// The text to convert to uppercase.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
pub fn upper(args: &mut Args) -> SourceResult<Value> {
|
pub fn upper(args: &mut Args) -> SourceResult<Value> {
|
||||||
case(Case::Upper, args)
|
case(Case::Upper, args)
|
||||||
@ -162,6 +188,15 @@ fn case(case: Case, args: &mut Args) -> SourceResult<Value> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A value whose case can be changed.
|
||||||
|
struct ToCase;
|
||||||
|
|
||||||
|
castable! {
|
||||||
|
ToCase,
|
||||||
|
_: Str => Self,
|
||||||
|
_: Content => Self,
|
||||||
|
}
|
||||||
|
|
||||||
/// A case transformation on text.
|
/// A case transformation on text.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Case {
|
pub enum Case {
|
||||||
@ -183,7 +218,12 @@ impl Case {
|
|||||||
|
|
||||||
/// Display text in small capitals.
|
/// Display text in small capitals.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - text: Content (positional, required)
|
||||||
|
/// The text to display to small capitals.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
pub fn smallcaps(args: &mut Args) -> SourceResult<Value> {
|
pub fn smallcaps(args: &mut Args) -> SourceResult<Value> {
|
||||||
let body: Content = args.expect("content")?;
|
let body: Content = args.expect("content")?;
|
||||||
|
@ -25,9 +25,16 @@ use typst::util::EcoString;
|
|||||||
use crate::layout::ParNode;
|
use crate::layout::ParNode;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// A single run of text with the same style.
|
/// Stylable text.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - family: EcoString (positional, variadic, settable)
|
||||||
|
/// A prioritized sequence of font families.
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// Content in which all text is styled according to the other arguments.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable]
|
#[capable]
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
|
@ -4,7 +4,12 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// A smart quote.
|
/// A smart quote.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - double: bool (named)
|
||||||
|
/// Whether to produce a smart double quote.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable]
|
#[capable]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -8,14 +8,21 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Raw text with optional syntax highlighting.
|
/// Raw text with optional syntax highlighting.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - text: EcoString (positional, required)
|
||||||
|
/// The raw text.
|
||||||
|
/// - block: bool (named)
|
||||||
|
/// Whether the raw text is displayed as a separate block.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct RawNode {
|
pub struct RawNode {
|
||||||
/// The raw text.
|
/// The raw text.
|
||||||
pub text: EcoString,
|
pub text: EcoString,
|
||||||
/// Whether the node is block-level.
|
/// Whether the raw text is displayed as a separate block.
|
||||||
pub block: bool,
|
pub block: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,14 +4,19 @@ use typst::util::EcoString;
|
|||||||
use super::{variant, SpaceNode, TextNode, TextSize};
|
use super::{variant, SpaceNode, TextNode, TextSize};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// Sub or superscript text.
|
/// Sub- or superscript text.
|
||||||
///
|
///
|
||||||
/// The text is rendered smaller and its baseline is raised. To provide the best
|
/// The text is rendered smaller and its baseline is raised/lowered. To provide
|
||||||
/// typography possible, we first try to transform the text to superscript
|
/// the best typography possible, we first try to transform the text to
|
||||||
/// codepoints. If that fails, we fall back to rendering shrunk normal letters
|
/// superscript codepoints. If that fails, we fall back to rendering shrunk
|
||||||
/// in a raised way.
|
/// normal letters in a raised way.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The text to display in sub- or superscript.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -3,7 +3,12 @@ use crate::text::TextNode;
|
|||||||
|
|
||||||
/// A symbol identified by symmie notation.
|
/// A symbol identified by symmie notation.
|
||||||
///
|
///
|
||||||
/// Tags: text.
|
/// # Parameters
|
||||||
|
/// - notation: EcoString (positional, required)
|
||||||
|
/// The symbols symmie notation.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - text
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Show)]
|
#[capable(Show)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -6,7 +6,14 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Show a raster or vector graphic.
|
/// Show a raster or vector graphic.
|
||||||
///
|
///
|
||||||
/// Tags: visualize.
|
/// Supported formats are PNG, JPEG, GIF and SVG.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - path: EcoString (positional, required)
|
||||||
|
/// Path to an image file.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - visualize
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -2,7 +2,20 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Display a line without affecting the layout.
|
/// Display a line without affecting the layout.
|
||||||
///
|
///
|
||||||
/// Tags: visualize.
|
/// You should only provide either an endpoint or an angle and a length.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - origin: Axes<Rel<Length>> (named)
|
||||||
|
/// The start point of the line.
|
||||||
|
/// - to: Axes<Rel<Length>> (named)
|
||||||
|
/// The end point of the line.
|
||||||
|
/// - length: Rel<Length> (named)
|
||||||
|
/// The line's length.
|
||||||
|
/// - angle: Angle (named)
|
||||||
|
/// The angle at which the line points away from the origin.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - visualize
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
@ -4,7 +4,22 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// A sizable and fillable shape with optional content.
|
/// A sizable and fillable shape with optional content.
|
||||||
///
|
///
|
||||||
/// Tags: visualize.
|
/// # Parameters
|
||||||
|
/// - body: Content (positional)
|
||||||
|
/// The content to place into the shape.
|
||||||
|
/// - width: Rel<Length> (named)
|
||||||
|
/// The shape's width.
|
||||||
|
/// - height: Rel<Length> (named)
|
||||||
|
/// The shape's height.
|
||||||
|
/// - size: Length (named)
|
||||||
|
/// The square's side length.
|
||||||
|
/// - radius: Length (named)
|
||||||
|
/// The circle's radius.
|
||||||
|
/// - stroke: Smart<Sides<Option<PartialStroke>>> (named)
|
||||||
|
/// How to stroke the shape.
|
||||||
|
///
|
||||||
|
/// # Tags
|
||||||
|
/// - visualize
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Layout, Inline)]
|
#[capable(Layout, Inline)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
@ -27,7 +42,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
|
|||||||
/// How to fill the shape.
|
/// How to fill the shape.
|
||||||
pub const FILL: Option<Paint> = None;
|
pub const FILL: Option<Paint> = None;
|
||||||
/// How to stroke the shape.
|
/// How to stroke the shape.
|
||||||
#[property(reflect, skip, resolve, fold)]
|
#[property(skip, resolve, fold)]
|
||||||
pub const STROKE: Smart<Sides<Option<PartialStroke>>> = Smart::Auto;
|
pub const STROKE: Smart<Sides<Option<PartialStroke>>> = Smart::Auto;
|
||||||
|
|
||||||
/// How much to pad the shape's content.
|
/// How much to pad the shape's content.
|
||||||
@ -38,7 +53,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
|
|||||||
pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
|
pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
|
||||||
|
|
||||||
/// How much to round the shape's corners.
|
/// How much to round the shape's corners.
|
||||||
#[property(reflect, skip, resolve, fold)]
|
#[property(skip, resolve, fold)]
|
||||||
pub const RADIUS: Corners<Option<Rel<Length>>> = Corners::splat(Rel::zero());
|
pub const RADIUS: Corners<Option<Rel<Length>>> = Corners::splat(Rel::zero());
|
||||||
|
|
||||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
@ -14,3 +14,4 @@ bench = false
|
|||||||
proc-macro2 = "1"
|
proc-macro2 = "1"
|
||||||
quote = "1"
|
quote = "1"
|
||||||
syn = { version = "1", features = ["full"] }
|
syn = { version = "1", features = ["full"] }
|
||||||
|
unscanny = "0.1"
|
||||||
|
@ -150,7 +150,7 @@ fn create_describe_func(castable: &Castable) -> TokenStream {
|
|||||||
let mut infos = vec![];
|
let mut infos = vec![];
|
||||||
|
|
||||||
for cast in &castable.casts {
|
for cast in &castable.casts {
|
||||||
let docs = doc_comment(&cast.attrs);
|
let docs = documentation(&cast.attrs);
|
||||||
infos.push(match &cast.pattern {
|
infos.push(match &cast.pattern {
|
||||||
Pattern::Str(lit) => {
|
Pattern::Str(lit) => {
|
||||||
quote! { ::typst::model::CastInfo::Value(#lit.into(), #docs) }
|
quote! { ::typst::model::CastInfo::Value(#lit.into(), #docs) }
|
||||||
|
@ -1,36 +1,26 @@
|
|||||||
|
use proc_macro2::Span;
|
||||||
|
use unscanny::Scanner;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Expand the `#[func]` macro.
|
/// Expand the `#[func]` macro.
|
||||||
pub fn func(item: syn::Item) -> Result<TokenStream> {
|
pub fn func(item: syn::Item) -> Result<TokenStream> {
|
||||||
let doc_comment = match &item {
|
let mut docs = match &item {
|
||||||
syn::Item::Struct(item) => doc_comment(&item.attrs),
|
syn::Item::Struct(item) => documentation(&item.attrs),
|
||||||
syn::Item::Enum(item) => doc_comment(&item.attrs),
|
syn::Item::Enum(item) => documentation(&item.attrs),
|
||||||
syn::Item::Fn(item) => doc_comment(&item.attrs),
|
syn::Item::Fn(item) => documentation(&item.attrs),
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tags = vec![];
|
let tags = tags(&mut docs);
|
||||||
let mut kept = vec![];
|
let params = params(&mut docs)?;
|
||||||
for line in doc_comment.lines() {
|
let docs = docs.trim();
|
||||||
let line = line.trim();
|
|
||||||
if let Some(suffix) = line.trim_end_matches(".").strip_prefix("Tags: ") {
|
|
||||||
tags.extend(suffix.split(", "));
|
|
||||||
} else {
|
|
||||||
kept.push(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while kept.last().map_or(false, |line| line.is_empty()) {
|
|
||||||
kept.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
let docs = kept.join("\n");
|
|
||||||
let info = quote! {
|
let info = quote! {
|
||||||
::typst::model::FuncInfo {
|
::typst::model::FuncInfo {
|
||||||
name,
|
name,
|
||||||
docs: #docs,
|
docs: #docs,
|
||||||
tags: &[#(#tags),*],
|
tags: &[#(#tags),*],
|
||||||
params: ::std::vec![],
|
params: ::std::vec![#(#params),*],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,3 +73,93 @@ pub fn func(item: syn::Item) -> Result<TokenStream> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract a section.
|
||||||
|
pub fn section(docs: &mut String, title: &str) -> Option<String> {
|
||||||
|
let needle = format!("# {title}\n");
|
||||||
|
let start = docs.find(&needle)?;
|
||||||
|
let rest = &docs[start..];
|
||||||
|
let len = rest[1..].find('#').map(|x| 1 + x).unwrap_or(rest.len());
|
||||||
|
let end = start + len;
|
||||||
|
let section = docs[start + needle.len()..].to_owned();
|
||||||
|
docs.replace_range(start..end, "");
|
||||||
|
Some(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the tag section.
|
||||||
|
pub fn tags(docs: &mut String) -> Vec<String> {
|
||||||
|
section(docs, "Tags")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.lines()
|
||||||
|
.filter_map(|line| line.strip_prefix('-'))
|
||||||
|
.map(|s| s.trim().into())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the parameter section.
|
||||||
|
pub fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
|
||||||
|
let Some(section) = section(docs, "Parameters") else { return Ok(vec![]) };
|
||||||
|
let mut s = Scanner::new(§ion);
|
||||||
|
let mut infos = vec![];
|
||||||
|
|
||||||
|
while s.eat_if('-') {
|
||||||
|
s.eat_whitespace();
|
||||||
|
let name = s.eat_until(':');
|
||||||
|
s.expect(": ");
|
||||||
|
let ty: syn::Type = syn::parse_str(s.eat_until(char::is_whitespace))?;
|
||||||
|
s.eat_whitespace();
|
||||||
|
let mut named = false;
|
||||||
|
let mut positional = false;
|
||||||
|
let mut required = false;
|
||||||
|
let mut variadic = false;
|
||||||
|
let mut settable = false;
|
||||||
|
s.expect('(');
|
||||||
|
for part in s.eat_until(')').split(',').map(str::trim).filter(|s| !s.is_empty()) {
|
||||||
|
match part {
|
||||||
|
"named" => named = true,
|
||||||
|
"positional" => positional = true,
|
||||||
|
"required" => required = true,
|
||||||
|
"variadic" => variadic = true,
|
||||||
|
"settable" => settable = true,
|
||||||
|
_ => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
format!("unknown parameter flag {:?}", part),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!named && !positional)
|
||||||
|
|| (variadic && !positional)
|
||||||
|
|| (named && variadic)
|
||||||
|
|| (required && variadic)
|
||||||
|
{
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"invalid combination of parameter flags",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
s.expect(')');
|
||||||
|
let docs = dedent(s.eat_until("\n-").trim());
|
||||||
|
infos.push(quote! {
|
||||||
|
::typst::model::ParamInfo {
|
||||||
|
name: #name,
|
||||||
|
docs: #docs,
|
||||||
|
cast: <#ty as ::typst::model::Cast<
|
||||||
|
::typst::syntax::Spanned<::typst::model::Value>
|
||||||
|
>>::describe(),
|
||||||
|
named: #named,
|
||||||
|
positional: #positional,
|
||||||
|
required: #required,
|
||||||
|
variadic: #variadic,
|
||||||
|
settable: #settable,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
s.eat_whitespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(infos)
|
||||||
|
}
|
||||||
|
@ -64,7 +64,7 @@ pub fn castable(stream: BoundaryStream) -> BoundaryStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extract documentation comments from an attribute list.
|
/// Extract documentation comments from an attribute list.
|
||||||
fn doc_comment(attrs: &[syn::Attribute]) -> String {
|
fn documentation(attrs: &[syn::Attribute]) -> String {
|
||||||
let mut doc = String::new();
|
let mut doc = String::new();
|
||||||
|
|
||||||
// Parse doc comments.
|
// Parse doc comments.
|
||||||
@ -72,7 +72,9 @@ fn doc_comment(attrs: &[syn::Attribute]) -> String {
|
|||||||
if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() {
|
if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() {
|
||||||
if meta.path.is_ident("doc") {
|
if meta.path.is_ident("doc") {
|
||||||
if let syn::Lit::Str(string) = &meta.lit {
|
if let syn::Lit::Str(string) = &meta.lit {
|
||||||
doc.push_str(&string.value());
|
let full = string.value();
|
||||||
|
let line = full.strip_prefix(' ').unwrap_or(&full);
|
||||||
|
doc.push_str(line);
|
||||||
doc.push('\n');
|
doc.push('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,3 +83,8 @@ fn doc_comment(attrs: &[syn::Attribute]) -> String {
|
|||||||
|
|
||||||
doc.trim().into()
|
doc.trim().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dedent documentation text.
|
||||||
|
fn dedent(text: &str) -> String {
|
||||||
|
text.lines().map(str::trim).collect::<Vec<_>>().join("\n")
|
||||||
|
}
|
||||||
|
@ -36,7 +36,6 @@ struct Property {
|
|||||||
shorthand: Option<Shorthand>,
|
shorthand: Option<Shorthand>,
|
||||||
resolve: bool,
|
resolve: bool,
|
||||||
fold: bool,
|
fold: bool,
|
||||||
reflect: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shorthand form of a style property.
|
/// The shorthand form of a style property.
|
||||||
@ -118,7 +117,6 @@ fn prepare_property(item: &syn::ImplItemConst) -> Result<Property> {
|
|||||||
let mut referenced = false;
|
let mut referenced = false;
|
||||||
let mut resolve = false;
|
let mut resolve = false;
|
||||||
let mut fold = false;
|
let mut fold = false;
|
||||||
let mut reflect = false;
|
|
||||||
|
|
||||||
// Parse the `#[property(..)]` attribute.
|
// Parse the `#[property(..)]` attribute.
|
||||||
let mut stream = tokens.into_iter().peekable();
|
let mut stream = tokens.into_iter().peekable();
|
||||||
@ -152,7 +150,6 @@ fn prepare_property(item: &syn::ImplItemConst) -> Result<Property> {
|
|||||||
"referenced" => referenced = true,
|
"referenced" => referenced = true,
|
||||||
"resolve" => resolve = true,
|
"resolve" => resolve = true,
|
||||||
"fold" => fold = true,
|
"fold" => fold = true,
|
||||||
"reflect" => reflect = true,
|
|
||||||
_ => bail!(ident, "invalid attribute"),
|
_ => bail!(ident, "invalid attribute"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +189,6 @@ fn prepare_property(item: &syn::ImplItemConst) -> Result<Property> {
|
|||||||
referenced,
|
referenced,
|
||||||
resolve,
|
resolve,
|
||||||
fold,
|
fold,
|
||||||
reflect,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,9 +271,9 @@ fn create_node_construct_func(node: &Node) -> syn::ImplItemMethod {
|
|||||||
parse_quote! {
|
parse_quote! {
|
||||||
fn construct(
|
fn construct(
|
||||||
_: &::typst::model::Vm,
|
_: &::typst::model::Vm,
|
||||||
_: &mut ::typst::model::Args,
|
args: &mut ::typst::model::Args,
|
||||||
) -> ::typst::diag::SourceResult<::typst::model::Content> {
|
) -> ::typst::diag::SourceResult<::typst::model::Content> {
|
||||||
unimplemented!()
|
::typst::diag::bail!(args.span, "cannot be constructed manually");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -335,27 +331,26 @@ fn create_node_set_func(node: &Node) -> syn::ImplItemMethod {
|
|||||||
|
|
||||||
/// Create the node's `properties` function.
|
/// Create the node's `properties` function.
|
||||||
fn create_node_properties_func(node: &Node) -> syn::ImplItemMethod {
|
fn create_node_properties_func(node: &Node) -> syn::ImplItemMethod {
|
||||||
let infos = node
|
let infos = node.properties.iter().filter(|p| !p.skip).map(|property| {
|
||||||
.properties
|
let name = property.name.to_string().replace('_', "-").to_lowercase();
|
||||||
.iter()
|
let docs = documentation(&property.attrs);
|
||||||
.filter(|p| !p.skip || p.reflect)
|
let value_ty = &property.value_ty;
|
||||||
.map(|property| {
|
let shorthand = matches!(property.shorthand, Some(Shorthand::Positional));
|
||||||
let name = property.name.to_string().replace('_', "-").to_lowercase();
|
quote! {
|
||||||
let docs = doc_comment(&property.attrs);
|
::typst::model::ParamInfo {
|
||||||
let value_ty = &property.value_ty;
|
name: #name,
|
||||||
let shorthand = matches!(property.shorthand, Some(Shorthand::Positional));
|
docs: #docs,
|
||||||
quote! {
|
cast: <#value_ty as ::typst::model::Cast<
|
||||||
::typst::model::ParamInfo {
|
::typst::syntax::Spanned<::typst::model::Value>
|
||||||
name: #name,
|
>>::describe(),
|
||||||
docs: #docs,
|
named: true,
|
||||||
settable: true,
|
positional: #shorthand,
|
||||||
shorthand: #shorthand,
|
required: false,
|
||||||
cast: <#value_ty as ::typst::model::Cast<
|
variadic: false,
|
||||||
::typst::syntax::Spanned<::typst::model::Value>
|
settable: true,
|
||||||
>>::describe(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
parse_quote! {
|
parse_quote! {
|
||||||
fn properties() -> ::std::vec::Vec<::typst::model::ParamInfo>
|
fn properties() -> ::std::vec::Vec<::typst::model::ParamInfo>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
|
|
||||||
use super::summarize_font_family;
|
use super::summarize_font_family;
|
||||||
@ -141,7 +143,7 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
|
|||||||
SyntaxKind::Colon | SyntaxKind::Space { .. } => ctx.cursor,
|
SyntaxKind::Colon | SyntaxKind::Space { .. } => ctx.cursor,
|
||||||
_ => ctx.leaf.offset(),
|
_ => ctx.leaf.offset(),
|
||||||
};
|
};
|
||||||
ctx.param_value_completions(&callee, ¶m);
|
ctx.named_param_value_completions(&callee, ¶m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,6 +362,7 @@ struct CompletionContext<'a> {
|
|||||||
explicit: bool,
|
explicit: bool,
|
||||||
from: usize,
|
from: usize,
|
||||||
completions: Vec<Completion>,
|
completions: Vec<Completion>,
|
||||||
|
seen_casts: HashSet<u128>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CompletionContext<'a> {
|
impl<'a> CompletionContext<'a> {
|
||||||
@ -382,6 +385,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
explicit,
|
explicit,
|
||||||
from: cursor,
|
from: cursor,
|
||||||
completions: vec![],
|
completions: vec![],
|
||||||
|
seen_casts: HashSet::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,14 +444,16 @@ impl<'a> CompletionContext<'a> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.completions.push(Completion {
|
if param.named {
|
||||||
kind: CompletionKind::Param,
|
self.completions.push(Completion {
|
||||||
label: param.name.into(),
|
kind: CompletionKind::Param,
|
||||||
apply: Some(format_eco!("{}: ${{}}", param.name)),
|
label: param.name.into(),
|
||||||
detail: Some(param.docs.into()),
|
apply: Some(format_eco!("{}: ${{}}", param.name)),
|
||||||
});
|
detail: Some(param.docs.into()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if param.shorthand {
|
if param.positional {
|
||||||
self.cast_completions(¶m.cast);
|
self.cast_completions(¶m.cast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,11 +464,12 @@ impl<'a> CompletionContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add completions for the values of a function parameter.
|
/// Add completions for the values of a function parameter.
|
||||||
fn param_value_completions(&mut self, callee: &ast::Ident, name: &str) {
|
fn named_param_value_completions(&mut self, callee: &ast::Ident, name: &str) {
|
||||||
let param = if_chain! {
|
let param = if_chain! {
|
||||||
if let Some(Value::Func(func)) = self.scope.get(callee);
|
if let Some(Value::Func(func)) = self.scope.get(callee);
|
||||||
if let Some(info) = func.info();
|
if let Some(info) = func.info();
|
||||||
if let Some(param) = info.param(name);
|
if let Some(param) = info.param(name);
|
||||||
|
if param.named;
|
||||||
then { param }
|
then { param }
|
||||||
else { return; }
|
else { return; }
|
||||||
};
|
};
|
||||||
@ -475,7 +482,12 @@ impl<'a> CompletionContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add completions for a castable.
|
/// Add completions for a castable.
|
||||||
fn cast_completions(&mut self, cast: &CastInfo) {
|
fn cast_completions(&mut self, cast: &'a CastInfo) {
|
||||||
|
// Prevent duplicate completions from appearing.
|
||||||
|
if !self.seen_casts.insert(crate::util::hash128(cast)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match cast {
|
match cast {
|
||||||
CastInfo::Any => {}
|
CastInfo::Any => {}
|
||||||
CastInfo::Value(value, docs) => {
|
CastInfo::Value(value, docs) => {
|
||||||
@ -485,7 +497,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
self.snippet_completion("none", "none", "Nonexistent.")
|
self.snippet_completion("none", "none", "Nonexistent.")
|
||||||
}
|
}
|
||||||
CastInfo::Type("auto") => {
|
CastInfo::Type("auto") => {
|
||||||
self.snippet_completion("auto", "auto", "A smart default");
|
self.snippet_completion("auto", "auto", "A smart default.");
|
||||||
}
|
}
|
||||||
CastInfo::Type("boolean") => {
|
CastInfo::Type("boolean") => {
|
||||||
self.snippet_completion("false", "false", "Yes / Enabled.");
|
self.snippet_completion("false", "false", "Yes / Enabled.");
|
||||||
|
@ -33,7 +33,7 @@ pub trait Cast<V = Value>: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a possible value for a cast.
|
/// Describes a possible value for a cast.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum CastInfo {
|
pub enum CastInfo {
|
||||||
/// Any value is okay.
|
/// Any value is okay.
|
||||||
Any,
|
Any,
|
||||||
|
@ -411,7 +411,7 @@ impl Eval for ast::Math {
|
|||||||
self.children()
|
self.children()
|
||||||
.map(|node| node.eval(vm))
|
.map(|node| node.eval(vm))
|
||||||
.collect::<SourceResult<_>>()?,
|
.collect::<SourceResult<_>>()?,
|
||||||
self.display(),
|
self.block(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,12 +232,21 @@ pub struct ParamInfo {
|
|||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
/// Documentation for the parameter.
|
/// Documentation for the parameter.
|
||||||
pub docs: &'static str,
|
pub docs: &'static str,
|
||||||
/// Is the parameter settable with a set rule?
|
|
||||||
pub settable: bool,
|
|
||||||
/// Can the name be omitted?
|
|
||||||
pub shorthand: bool,
|
|
||||||
/// Valid values for the parameter.
|
/// Valid values for the parameter.
|
||||||
pub cast: CastInfo,
|
pub cast: CastInfo,
|
||||||
|
/// Is the parameter positional?
|
||||||
|
pub positional: bool,
|
||||||
|
/// Is the parameter named?
|
||||||
|
///
|
||||||
|
/// Can be true even if `positional` is true if the parameter can be given
|
||||||
|
/// in both variants.
|
||||||
|
pub named: bool,
|
||||||
|
/// Is the parameter required?
|
||||||
|
pub required: bool,
|
||||||
|
/// Can the parameter be given any number of times?
|
||||||
|
pub variadic: bool,
|
||||||
|
/// Is the parameter settable with a set rule?
|
||||||
|
pub settable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A user-defined closure.
|
/// A user-defined closure.
|
||||||
|
@ -66,7 +66,7 @@ pub struct LangItems {
|
|||||||
/// An item in a description list: `/ Term: Details`.
|
/// An item in a description list: `/ Term: Details`.
|
||||||
pub desc_item: fn(term: Content, body: Content) -> Content,
|
pub desc_item: fn(term: Content, body: Content) -> Content,
|
||||||
/// A mathematical formula: `$x$`, `$ x^2 $`.
|
/// A mathematical formula: `$x$`, `$ x^2 $`.
|
||||||
pub math: fn(children: Vec<Content>, display: bool) -> Content,
|
pub math: fn(children: Vec<Content>, block: bool) -> Content,
|
||||||
/// An atom in a formula: `x`, `+`, `12`.
|
/// An atom in a formula: `x`, `+`, `12`.
|
||||||
pub math_atom: fn(atom: EcoString) -> Content,
|
pub math_atom: fn(atom: EcoString) -> Content,
|
||||||
/// A base with optional sub- and superscripts in a formula: `a_1^2`.
|
/// A base with optional sub- and superscripts in a formula: `a_1^2`.
|
||||||
@ -75,7 +75,7 @@ pub struct LangItems {
|
|||||||
/// A fraction in a formula: `x/2`.
|
/// A fraction in a formula: `x/2`.
|
||||||
pub math_frac: fn(num: Content, denom: Content) -> Content,
|
pub math_frac: fn(num: Content, denom: Content) -> Content,
|
||||||
/// An alignment point in a formula: `&`, `&&`.
|
/// An alignment point in a formula: `&`, `&&`.
|
||||||
pub math_align_point: fn(count: usize) -> Content,
|
pub math_align_point: fn(count: NonZeroUsize) -> Content,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for LangItems {
|
impl Debug for LangItems {
|
||||||
|
@ -295,7 +295,7 @@ impl Raw {
|
|||||||
self.get().lang.as_ref()
|
self.get().lang.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the raw block is block-level.
|
/// Whether the raw text should be displayed in a separate block.
|
||||||
pub fn block(&self) -> bool {
|
pub fn block(&self) -> bool {
|
||||||
self.get().block
|
self.get().block
|
||||||
}
|
}
|
||||||
@ -425,8 +425,8 @@ impl Math {
|
|||||||
self.0.children().filter_map(SyntaxNode::cast)
|
self.0.children().filter_map(SyntaxNode::cast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this is a display-level math formula.
|
/// Whether the formula should be displayed as a separate block.
|
||||||
pub fn display(&self) -> bool {
|
pub fn block(&self) -> bool {
|
||||||
matches!(self.children().next(), Some(MathNode::Space(_)))
|
matches!(self.children().next(), Some(MathNode::Space(_)))
|
||||||
&& matches!(self.children().last(), Some(MathNode::Space(_)))
|
&& matches!(self.children().last(), Some(MathNode::Space(_)))
|
||||||
}
|
}
|
||||||
@ -564,8 +564,13 @@ node! {
|
|||||||
|
|
||||||
impl AlignPoint {
|
impl AlignPoint {
|
||||||
/// The number of ampersands.
|
/// The number of ampersands.
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> NonZeroUsize {
|
||||||
self.0.children().filter(|n| n.kind() == &SyntaxKind::Amp).count()
|
self.0
|
||||||
|
.children()
|
||||||
|
.filter(|n| n.kind() == &SyntaxKind::Amp)
|
||||||
|
.count()
|
||||||
|
.try_into()
|
||||||
|
.expect("alignment point is missing ampersand sign")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,19 +13,19 @@
|
|||||||
#test(type(float(10)), "float")
|
#test(type(float(10)), "float")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 6-10 cannot convert length to integer
|
// Error: 6-10 expected boolean, integer, float, or string, found length
|
||||||
#int(10pt)
|
#int(10pt)
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 8-13 cannot convert function to float
|
// Error: 8-13 expected boolean, integer, float, or string, found function
|
||||||
#float(float)
|
#float(float)
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 6-12 invalid integer
|
// Error: 6-12 not a valid integer
|
||||||
#int("nope")
|
#int("nope")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 8-15 invalid float
|
// Error: 8-15 not a valid float
|
||||||
#float("1.2.3")
|
#float("1.2.3")
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -39,17 +39,9 @@
|
|||||||
#test(abs(-25%), 25%)
|
#test(abs(-25%), 25%)
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 6-17 expected numeric value, found string
|
// Error: 6-17 expected integer, float, angle, ratio, or fraction, found string
|
||||||
#abs("no number")
|
#abs("no number")
|
||||||
|
|
||||||
---
|
|
||||||
// Error: 6-11 cannot take absolute value of a length
|
|
||||||
#abs(-12pt)
|
|
||||||
|
|
||||||
---
|
|
||||||
// Error: 6-16 cannot take absolute value of a length
|
|
||||||
#abs(50% - 12pt)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test the `even` and `odd` functions.
|
// Test the `even` and `odd` functions.
|
||||||
#test(even(2), true)
|
#test(even(2), true)
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
#test(str(10 / 3).len() > 10, true)
|
#test(str(10 / 3).len() > 10, true)
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 6-8 cannot convert content to string
|
// Error: 6-8 expected integer, float, label, or string, found content
|
||||||
#str([])
|
#str([])
|
||||||
|
|
||||||
---
|
---
|
||||||
|
Loading…
x
Reference in New Issue
Block a user