diff --git a/crates/typst-library/src/math/attach.rs b/crates/typst-library/src/math/attach.rs index ee65b657..d74beafe 100644 --- a/crates/typst-library/src/math/attach.rs +++ b/crates/typst-library/src/math/attach.rs @@ -216,10 +216,16 @@ pub enum Limits { impl Limits { /// The default limit configuration if the given character is the base. pub fn for_char(c: char) -> Self { - if Self::DEFAULT_TO_LIMITS.contains(&c) { - Limits::Display - } else { - Limits::Never + match unicode_math_class::class(c) { + Some(MathClass::Large) => { + if is_integral_char(c) { + Limits::Never + } else { + Limits::Display + } + } + Some(MathClass::Relation) => Limits::Always, + _ => Limits::Never, } } @@ -231,18 +237,6 @@ impl Limits { Self::Never => false, } } - - /// Unicode codepoints that should show attachments as limits in display - /// mode. - #[rustfmt::skip] - const DEFAULT_TO_LIMITS: &[char] = &[ - /* ∏ */ '\u{220F}', /* ∐ */ '\u{2210}', /* ∑ */ '\u{2211}', - /* ⋀ */ '\u{22C0}', /* ⋁ */ '\u{22C1}', - /* ⋂ */ '\u{22C2}', /* ⋃ */ '\u{22C3}', - /* ⨀ */ '\u{2A00}', /* ⨁ */ '\u{2A01}', /* ⨂ */ '\u{2A02}', - /* ⨃ */ '\u{2A03}', /* ⨄ */ '\u{2A04}', - /* ⨅ */ '\u{2A05}', /* ⨆ */ '\u{2A06}', - ]; } macro_rules! measure { @@ -444,6 +438,11 @@ fn compute_shifts_up_and_down( (shift_up, shift_down) } +/// Determines if the character is one of a variety of integral signs +fn is_integral_char(c: char) -> bool { + ('∫'..='∳').contains(&c) || ('⨋'..='⨜').contains(&c) +} + /// Whether the fragment consists of a single character or atomic piece of text. fn is_character_box(fragment: &MathFragment) -> bool { match fragment { diff --git a/tests/ref/math/attach-p3.png b/tests/ref/math/attach-p3.png index ac3c3895..104534b7 100644 Binary files a/tests/ref/math/attach-p3.png and b/tests/ref/math/attach-p3.png differ diff --git a/tests/typ/math/attach-p3.typ b/tests/typ/math/attach-p3.typ index 0fc25d63..c681af2a 100644 --- a/tests/typ/math/attach-p3.typ +++ b/tests/typ/math/attach-p3.typ @@ -22,3 +22,21 @@ $ attach(A, t: #locate(it => oops)) $ #show math.iota: math.limits.with(inline: false) #eq $iota_a^b$ + +--- +// Test default of limit attachments on relations at all sizes +#set page(width: auto) +$ a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b $ +$a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b$ + +$a scripts(=)^"def" b quad a scripts(lt.eq)_"really" b quad a scripts(arrow.r.long.squiggly)^"slowly" b$ + +--- +// Test default of scripts attachments on integrals at display size +$ integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b $ +$integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b$ + +--- +// Test default of limit attachments on large operators at display size only +$ tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1 $ +$tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1$