diff options
| author | Laurenz <laurmaedje@gmail.com> | 2024-10-27 19:04:55 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-27 18:04:55 +0000 |
| commit | be7cfc85d08c545abfac08098b7b33b4bd71f37e (patch) | |
| tree | f4137fa2aaa57babae1f7603a9b2ed7e688f43d8 /crates/typst-library/src/math/lr.rs | |
| parent | b8034a343831e8609aec2ec81eb7eeda57aa5d81 (diff) | |
Split out four new crates (#5302)
Diffstat (limited to 'crates/typst-library/src/math/lr.rs')
| -rw-r--r-- | crates/typst-library/src/math/lr.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/crates/typst-library/src/math/lr.rs b/crates/typst-library/src/math/lr.rs new file mode 100644 index 00000000..07ab0dd4 --- /dev/null +++ b/crates/typst-library/src/math/lr.rs @@ -0,0 +1,135 @@ +use crate::foundations::{elem, func, Content, NativeElement, Smart}; +use crate::layout::{Length, Rel}; +use crate::math::Mathy; +use crate::text::TextElem; + +/// Scales delimiters. +/// +/// While matched delimiters scale by default, this can be used to scale +/// unmatched delimiters and to control the delimiter scaling more precisely. +#[elem(title = "Left/Right", Mathy)] +pub struct LrElem { + /// The size of the brackets, relative to the height of the wrapped content. + pub size: Smart<Rel<Length>>, + + /// The delimited content, including the delimiters. + #[required] + #[parse( + let mut arguments = args.all::<Content>()?.into_iter(); + let mut body = arguments.next().unwrap_or_default(); + arguments.for_each(|arg| body += TextElem::packed(',') + arg); + body + )] + pub body: Content, +} + +/// Scales delimiters vertically to the nearest surrounding `{lr()}` group. +/// +/// ```example +/// $ { x mid(|) sum_(i=1)^n w_i|f_i (x)| < 1 } $ +/// ``` +#[elem(Mathy)] +pub struct MidElem { + /// The content to be scaled. + #[required] + pub body: Content, +} + +/// Floors an expression. +/// +/// ```example +/// $ floor(x/2) $ +/// ``` +#[func] +pub fn floor( + /// The size of the brackets, relative to the height of the wrapped content. + #[named] + size: Option<Smart<Rel<Length>>>, + /// The expression to floor. + body: Content, +) -> Content { + delimited(body, '⌊', '⌋', size) +} + +/// Ceils an expression. +/// +/// ```example +/// $ ceil(x/2) $ +/// ``` +#[func] +pub fn ceil( + /// The size of the brackets, relative to the height of the wrapped content. + #[named] + size: Option<Smart<Rel<Length>>>, + /// The expression to ceil. + body: Content, +) -> Content { + delimited(body, '⌈', '⌉', size) +} + +/// Rounds an expression. +/// +/// ```example +/// $ round(x/2) $ +/// ``` +#[func] +pub fn round( + /// The size of the brackets, relative to the height of the wrapped content. + #[named] + size: Option<Smart<Rel<Length>>>, + /// The expression to round. + body: Content, +) -> Content { + delimited(body, '⌊', '⌉', size) +} + +/// Takes the absolute value of an expression. +/// +/// ```example +/// $ abs(x/2) $ +/// ``` +#[func] +pub fn abs( + /// The size of the brackets, relative to the height of the wrapped content. + #[named] + size: Option<Smart<Rel<Length>>>, + /// The expression to take the absolute value of. + body: Content, +) -> Content { + delimited(body, '|', '|', size) +} + +/// Takes the norm of an expression. +/// +/// ```example +/// $ norm(x/2) $ +/// ``` +#[func] +pub fn norm( + /// The size of the brackets, relative to the height of the wrapped content. + #[named] + size: Option<Smart<Rel<Length>>>, + /// The expression to take the norm of. + body: Content, +) -> Content { + delimited(body, '‖', '‖', size) +} + +fn delimited( + body: Content, + left: char, + right: char, + size: Option<Smart<Rel<Length>>>, +) -> Content { + let span = body.span(); + let mut elem = LrElem::new(Content::sequence([ + TextElem::packed(left), + body, + TextElem::packed(right), + ])); + // Push size only if size is provided + if let Some(size) = size { + elem.push_size(size); + } + elem.pack().spanned(span) +} |
