summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/math/lr.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-10-27 19:04:55 +0100
committerGitHub <noreply@github.com>2024-10-27 18:04:55 +0000
commitbe7cfc85d08c545abfac08098b7b33b4bd71f37e (patch)
treef4137fa2aaa57babae1f7603a9b2ed7e688f43d8 /crates/typst-library/src/math/lr.rs
parentb8034a343831e8609aec2ec81eb7eeda57aa5d81 (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.rs135
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)
+}