typst_library/math/
frac.rs

1use typst_syntax::Spanned;
2
3use crate::diag::bail;
4use crate::foundations::{Cast, Content, Value, elem};
5use crate::math::Mathy;
6
7/// A mathematical fraction.
8///
9/// # Example
10/// ```example
11/// $ 1/2 < (x+1)/2 $
12/// $ ((x+1)) / 2 = frac(a, b) $
13/// ```
14///
15/// # Syntax
16/// This function also has dedicated syntax: Use a slash to turn neighbouring
17/// expressions into a fraction. Multiple atoms can be grouped into a single
18/// expression using round grouping parentheses. Such parentheses are removed
19/// from the output, but you can nest multiple to force them.
20#[elem(title = "Fraction", Mathy)]
21pub struct FracElem {
22    /// The fraction's numerator.
23    #[required]
24    pub num: Content,
25
26    /// The fraction's denominator.
27    #[required]
28    pub denom: Content,
29
30    /// How the fraction should be laid out.
31    ///
32    /// ```example:"Styles"
33    /// $ frac(x, y, style: "vertical") $
34    /// $ frac(x, y, style: "skewed") $
35    /// $ frac(x, y, style: "horizontal") $
36    /// ```
37    ///
38    /// ```example:"Setting the default"
39    /// #set math.frac(style: "skewed")
40    /// $ a / b $
41    /// ```
42    ///
43    /// ```example:"Handling of grouping parentheses"
44    /// // Grouping parentheses are removed.
45    /// #set math.frac(style: "vertical")
46    /// $ (a + b) / b $
47    ///
48    /// // Grouping parentheses are removed.
49    /// #set math.frac(style: "skewed")
50    /// $ (a + b) / b $
51    ///
52    /// // Grouping parentheses are retained.
53    /// #set math.frac(style: "horizontal")
54    /// $ (a + b) / b $
55    /// ```
56    #[default(FracStyle::Vertical)]
57    pub style: FracStyle,
58
59    /// Whether the numerator was originally surrounded by parentheses
60    /// that were stripped by the parser.
61    #[internal]
62    #[parse(None)]
63    #[default(false)]
64    pub num_deparenthesized: bool,
65
66    /// Whether the denominator was originally surrounded by parentheses
67    /// that were stripped by the parser.
68    #[internal]
69    #[parse(None)]
70    #[default(false)]
71    pub denom_deparenthesized: bool,
72}
73
74/// Fraction style
75#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)]
76pub enum FracStyle {
77    /// Stacked numerator and denominator with a bar.
78    #[default]
79    Vertical,
80    /// Numerator and denominator separated by a slash.
81    Skewed,
82    /// Numerator and denominator placed inline and parentheses are not
83    /// absorbed.
84    Horizontal,
85}
86
87/// A binomial expression.
88///
89/// # Example
90/// ```example
91/// $ binom(n, k) $
92/// $ binom(n, k_1, k_2, k_3, ..., k_m) $
93/// ```
94#[elem(title = "Binomial", Mathy)]
95pub struct BinomElem {
96    /// The binomial's upper index.
97    #[required]
98    pub upper: Content,
99
100    /// The binomial's lower index.
101    #[required]
102    #[variadic]
103    #[parse(
104        let values = args.all::<Spanned<Value>>()?;
105        if values.is_empty() {
106            // Prevents one element binomials
107            bail!(args.span, "missing argument: lower");
108        }
109        values.into_iter().map(|spanned| spanned.v.display()).collect()
110    )]
111    pub lower: Vec<Content>,
112}