mkorje 24bac30c84
Allow a function as an argument to size in stretch and lr
Previously there was always a short fall when scaling delimiters, even if
the user requested a specific size. This is no longer the case; the short
fall is only present in the default for `lr` (`x => x - 0.1em`) - the
size of the delimiters is now actually what was specified in the size
argument. This also makes the default for `lr` much clearer to the user.

A slight hack was used by exploiting the `name` property in the `func`
attribute macro so that the default value in the docs for `lr.size` would
clearly show what the default function was (instead of just its name
`default_lr_size` which is meaningless and inaccessible to the user).
2025-07-23 17:50:58 +10:00

130 lines
3.3 KiB
Rust

use crate::foundations::{Content, Packed, elem};
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_set() && elem.$content.is_set() {
base.$content = elem.$content.clone();
elem.$content.unset();
}
};
}
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,
}