Repository: typst/typst
File: crates/typst/src/math/stretch.rs (Rust)

Code before:
/// 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(LayoutMath)]
pub struct StretchElem {
    /// The base to stretch.
    #[required]
    pub base: Content,

    /// The size to stretch to, relative to the glyph's current size.
    pub size: Smart<Rel<Length>>,

    /// Whether the size should be relative to the width of any top or bottom
    /// attachments.
    ///
    /// ```example
    /// #set math.stretch(attach: false)
    /// $ stretch(->, size: #250%)_"very long text" $
    /// ```
    #[default(true)]
    pub attach: bool,
}

impl LayoutMath for Packed<StretchElem> {
    #[typst_macros::time(name = "math.stretch", span = self.span())]
    fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
        let mut fragment = ctx.layout_into_fragment(self.base(), styles)?;
        stretch_fragment(
            ctx,
            styles,
            &mut fragment,
            None,
            None,
            self.size(styles),
            Abs::zero(),
        );
        ctx.push(fragment);
        Ok(())
    }
}

/// Attempts to stretch the given fragment by/to the amount given in stretch.
pub(super) fn stretch_fragment(
    ctx: &mut MathContext,
    styles: StyleChain,
    fragment: &mut MathFragment,

Review comment (suggestion):
The use case for `attach: false` seems very rare to me.

I can see how giving sizes as percentages relative to the glyph can be nice, but one can always use em units after all.

Not sure here.

Code after:
/// 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(LayoutMath)]
pub struct StretchElem {
    /// The glyph to stretch.
    #[required]
    pub body: Content,

    /// The size to stretch to, relative to the glyph's current size.
    pub size: Smart<Rel<Length>>,
}

impl LayoutMath for Packed<StretchElem> {
    #[typst_macros::time(name = "math.stretch", span = self.span())]
    fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
        let mut fragment = ctx.layout_into_fragment(self.body(), styles)?;
        stretch_fragment(
            ctx,
            styles,
            &mut fragment,
            None,
            None,
            self.size(styles),
            Abs::zero(),
        );
        ctx.push(fragment);
        Ok(())
    }
}

/// Attempts to stretch the given fragment by/to the amount given in stretch.
pub(super) fn stretch_fragment(
    ctx: &mut MathContext,
    styles: StyleChain,
    fragment: &mut MathFragment,
    axis: Option<Axis>,
    relative_to: Option<Abs>,
    stretch: Smart<Rel<Length>>,
    short_fall: Abs,
) {
    let glyph = match fragment {
        MathFragment::Glyph(glyph) => glyph.clone(),
        MathFragment::Variant(variant) => {
            GlyphFragment::new(ctx, styles, variant.c, variant.span)