typst_library/math/lr.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use crate::foundations::{elem, func, Content, NativeElement, SymbolElem};
use crate::layout::{Length, Rel};
use crate::math::Mathy;
/// 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.
#[resolve]
#[default(Rel::one())]
pub size: 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 += SymbolElem::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<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<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<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<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<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<Rel<Length>>,
) -> Content {
let span = body.span();
let mut elem = LrElem::new(Content::sequence([
SymbolElem::packed(left),
body,
SymbolElem::packed(right),
]));
// Push size only if size is provided
if let Some(size) = size {
elem.push_size(size);
}
elem.pack().spanned(span)
}