typst_library/math/
style.rs

1use crate::foundations::{func, Cast, Content, Smart};
2use crate::math::EquationElem;
3
4/// Bold font style in math.
5///
6/// ```example
7/// $ bold(A) := B^+ $
8/// ```
9#[func(keywords = ["mathbf"])]
10pub fn bold(
11    /// The content to style.
12    body: Content,
13) -> Content {
14    body.styled(EquationElem::set_bold(true))
15}
16
17/// Upright (non-italic) font style in math.
18///
19/// ```example
20/// $ upright(A) != A $
21/// ```
22#[func(keywords = ["mathup"])]
23pub fn upright(
24    /// The content to style.
25    body: Content,
26) -> Content {
27    body.styled(EquationElem::set_italic(Smart::Custom(false)))
28}
29
30/// Italic font style in math.
31///
32/// For roman letters and greek lowercase letters, this is already the default.
33#[func(keywords = ["mathit"])]
34pub fn italic(
35    /// The content to style.
36    body: Content,
37) -> Content {
38    body.styled(EquationElem::set_italic(Smart::Custom(true)))
39}
40
41/// Serif (roman) font style in math.
42///
43/// This is already the default.
44#[func(keywords = ["mathrm"])]
45pub fn serif(
46    /// The content to style.
47    body: Content,
48) -> Content {
49    body.styled(EquationElem::set_variant(MathVariant::Serif))
50}
51
52/// Sans-serif font style in math.
53///
54/// ```example
55/// $ sans(A B C) $
56/// ```
57#[func(title = "Sans Serif", keywords = ["mathsf"])]
58pub fn sans(
59    /// The content to style.
60    body: Content,
61) -> Content {
62    body.styled(EquationElem::set_variant(MathVariant::Sans))
63}
64
65/// Calligraphic font style in math.
66///
67/// ```example
68/// Let $cal(P)$ be the set of ...
69/// ```
70///
71/// This corresponds both to LaTeX's `\mathcal` and `\mathscr` as both of these
72/// styles share the same Unicode codepoints. Switching between the styles is
73/// thus only possible if supported by the font via
74/// [font features]($text.features).
75///
76/// For the default math font, the roundhand style is available through the
77/// `ss01` feature. Therefore, you could define your own version of `\mathscr`
78/// like this:
79///
80/// ```example
81/// #let scr(it) = text(
82///   features: ("ss01",),
83///   box($cal(it)$),
84/// )
85///
86/// We establish $cal(P) != scr(P)$.
87/// ```
88///
89/// (The box is not conceptually necessary, but unfortunately currently needed
90/// due to limitations in Typst's text style handling in math.)
91#[func(title = "Calligraphic", keywords = ["mathcal", "mathscr"])]
92pub fn cal(
93    /// The content to style.
94    body: Content,
95) -> Content {
96    body.styled(EquationElem::set_variant(MathVariant::Cal))
97}
98
99/// Fraktur font style in math.
100///
101/// ```example
102/// $ frak(P) $
103/// ```
104#[func(title = "Fraktur", keywords = ["mathfrak"])]
105pub fn frak(
106    /// The content to style.
107    body: Content,
108) -> Content {
109    body.styled(EquationElem::set_variant(MathVariant::Frak))
110}
111
112/// Monospace font style in math.
113///
114/// ```example
115/// $ mono(x + y = z) $
116/// ```
117#[func(title = "Monospace", keywords = ["mathtt"])]
118pub fn mono(
119    /// The content to style.
120    body: Content,
121) -> Content {
122    body.styled(EquationElem::set_variant(MathVariant::Mono))
123}
124
125/// Blackboard bold (double-struck) font style in math.
126///
127/// For uppercase latin letters, blackboard bold is additionally available
128/// through [symbols]($category/symbols/sym) of the form `NN` and `RR`.
129///
130/// ```example
131/// $ bb(b) $
132/// $ bb(N) = NN $
133/// $ f: NN -> RR $
134/// ```
135#[func(title = "Blackboard Bold", keywords = ["mathbb"])]
136pub fn bb(
137    /// The content to style.
138    body: Content,
139) -> Content {
140    body.styled(EquationElem::set_variant(MathVariant::Bb))
141}
142
143/// Forced display style in math.
144///
145/// This is the normal size for block equations.
146///
147/// ```example
148/// $sum_i x_i/2 = display(sum_i x_i/2)$
149/// ```
150#[func(title = "Display Size", keywords = ["displaystyle"])]
151pub fn display(
152    /// The content to size.
153    body: Content,
154    /// Whether to impose a height restriction for exponents, like regular sub-
155    /// and superscripts do.
156    #[named]
157    #[default(false)]
158    cramped: bool,
159) -> Content {
160    body.styled(EquationElem::set_size(MathSize::Display))
161        .styled(EquationElem::set_cramped(cramped))
162}
163
164/// Forced inline (text) style in math.
165///
166/// This is the normal size for inline equations.
167///
168/// ```example
169/// $ sum_i x_i/2
170///     = inline(sum_i x_i/2) $
171/// ```
172#[func(title = "Inline Size", keywords = ["textstyle"])]
173pub fn inline(
174    /// The content to size.
175    body: Content,
176    /// Whether to impose a height restriction for exponents, like regular sub-
177    /// and superscripts do.
178    #[named]
179    #[default(false)]
180    cramped: bool,
181) -> Content {
182    body.styled(EquationElem::set_size(MathSize::Text))
183        .styled(EquationElem::set_cramped(cramped))
184}
185
186/// Forced script style in math.
187///
188/// This is the smaller size used in powers or sub- or superscripts.
189///
190/// ```example
191/// $sum_i x_i/2 = script(sum_i x_i/2)$
192/// ```
193#[func(title = "Script Size", keywords = ["scriptstyle"])]
194pub fn script(
195    /// The content to size.
196    body: Content,
197    /// Whether to impose a height restriction for exponents, like regular sub-
198    /// and superscripts do.
199    #[named]
200    #[default(true)]
201    cramped: bool,
202) -> Content {
203    body.styled(EquationElem::set_size(MathSize::Script))
204        .styled(EquationElem::set_cramped(cramped))
205}
206
207/// Forced second script style in math.
208///
209/// This is the smallest size, used in second-level sub- and superscripts
210/// (script of the script).
211///
212/// ```example
213/// $sum_i x_i/2 = sscript(sum_i x_i/2)$
214/// ```
215#[func(title = "Script-Script Size", keywords = ["scriptscriptstyle"])]
216pub fn sscript(
217    /// The content to size.
218    body: Content,
219    /// Whether to impose a height restriction for exponents, like regular sub-
220    /// and superscripts do.
221    #[named]
222    #[default(true)]
223    cramped: bool,
224) -> Content {
225    body.styled(EquationElem::set_size(MathSize::ScriptScript))
226        .styled(EquationElem::set_cramped(cramped))
227}
228
229/// The size of elements in an equation.
230///
231/// See the TeXbook p. 141.
232#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Cast, Hash)]
233pub enum MathSize {
234    /// Second-level sub- and superscripts.
235    ScriptScript,
236    /// Sub- and superscripts.
237    Script,
238    /// Math in text.
239    Text,
240    /// Math on its own line.
241    Display,
242}
243
244/// A mathematical style variant, as defined by Unicode.
245#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Cast, Hash)]
246pub enum MathVariant {
247    #[default]
248    Serif,
249    Sans,
250    Cal,
251    Frak,
252    Mono,
253    Bb,
254}