typst_library/math/attach.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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use crate::foundations::{elem, Content, Packed};
use crate::layout::{Length, Rel};
use crate::math::{EquationElem, Mathy};
/// A base with optional attachments.
///
/// ```example
/// $ attach(
/// Pi, t: alpha, b: beta,
/// tl: 1, tr: 2+3, bl: 4+5, br: 6,
/// ) $
/// ```
#[elem(Mathy)]
pub struct AttachElem {
/// The base to which things are attached.
#[required]
pub base: Content,
/// The top attachment, smartly positioned at top-right or above the base.
///
/// You can wrap the base in `{limits()}` or `{scripts()}` to override the
/// smart positioning.
pub t: Option<Content>,
/// The bottom attachment, smartly positioned at the bottom-right or below
/// the base.
///
/// You can wrap the base in `{limits()}` or `{scripts()}` to override the
/// smart positioning.
pub b: Option<Content>,
/// The top-left attachment (before the base).
pub tl: Option<Content>,
/// The bottom-left attachment (before base).
pub bl: Option<Content>,
/// The top-right attachment (after the base).
pub tr: Option<Content>,
/// The bottom-right attachment (after the base).
pub br: Option<Content>,
}
impl Packed<AttachElem> {
/// If an AttachElem's base is also an AttachElem, merge attachments into the
/// base AttachElem where possible.
pub fn merge_base(&self) -> Option<Self> {
// Extract from an EquationElem.
let mut base = &self.base;
while let Some(equation) = base.to_packed::<EquationElem>() {
base = &equation.body;
}
// Move attachments from elem into base where possible.
if let Some(base) = base.to_packed::<AttachElem>() {
let mut elem = self.clone();
let mut base = base.clone();
macro_rules! merge {
($content:ident) => {
if base.$content.is_none() && elem.$content.is_some() {
base.$content = elem.$content.clone();
elem.$content = None;
}
};
}
merge!(t);
merge!(b);
merge!(tl);
merge!(tr);
merge!(bl);
merge!(br);
elem.base = base.pack();
return Some(elem);
}
None
}
}
/// Grouped primes.
///
/// ```example
/// $ a'''_b = a^'''_b $
/// ```
///
/// # Syntax
/// This function has dedicated syntax: use apostrophes instead of primes. They
/// will automatically attach to the previous element, moving superscripts to
/// the next level.
#[elem(Mathy)]
pub struct PrimesElem {
/// The number of grouped primes.
#[required]
pub count: usize,
}
/// Forces a base to display attachments as scripts.
///
/// ```example
/// $ scripts(sum)_1^2 != sum_1^2 $
/// ```
#[elem(Mathy)]
pub struct ScriptsElem {
/// The base to attach the scripts to.
#[required]
pub body: Content,
}
/// Forces a base to display attachments as limits.
///
/// ```example
/// $ limits(A)_1^2 != A_1^2 $
/// ```
#[elem(Mathy)]
pub struct LimitsElem {
/// The base to attach the limits to.
#[required]
pub body: Content,
/// Whether to also force limits in inline equations.
///
/// When applying limits globally (e.g., through a show rule), it is
/// typically a good idea to disable this.
#[default(true)]
pub inline: bool,
}
/// Stretches a glyph.
///
/// This function can also be used to automatically stretch the base of an
/// attachment, so that it fits the top and bottom attachments.
///
/// Note that only some glyphs can be stretched, and which ones can depend on
/// the math font being used. However, most math fonts are the same in this
/// regard.
///
/// ```example
/// $ H stretch(=)^"define" U + p V $
/// $ f : X stretch(->>, size: #150%)_"surjective" Y $
/// $ x stretch(harpoons.ltrb, size: #3em) y
/// stretch(\[, size: #150%) z $
/// ```
#[elem(Mathy)]
pub struct StretchElem {
/// The glyph to stretch.
#[required]
pub body: Content,
/// The size to stretch to, relative to the maximum size of the glyph and
/// its attachments.
#[resolve]
#[default(Rel::one())]
pub size: Rel<Length>,
}