parent
6c542ea1a4
commit
03675fc429
@ -77,18 +77,9 @@ impl LayoutMath for AttachElem {
|
||||
let b = layout_attachment(ctx, Self::b)?;
|
||||
ctx.unstyle();
|
||||
|
||||
let as_limits = self.base().is::<LimitsElem>()
|
||||
|| (!self.base().is::<ScriptsElem>()
|
||||
&& ctx.style.size == MathSize::Display
|
||||
&& base.class() == Some(MathClass::Large)
|
||||
&& match &base {
|
||||
MathFragment::Variant(variant) => LIMITS.contains(&variant.c),
|
||||
MathFragment::Frame(fragment) => fragment.limits,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let (t, tr) = if as_limits || tr.is_some() { (t, tr) } else { (None, t) };
|
||||
let (b, br) = if as_limits || br.is_some() { (b, br) } else { (None, b) };
|
||||
let limits = base.limits().active(ctx);
|
||||
let (t, tr) = if limits || tr.is_some() { (t, tr) } else { (None, t) };
|
||||
let (b, br) = if limits || br.is_some() { (b, br) } else { (None, b) };
|
||||
layout_attachments(ctx, base, [tl, t, tr, bl, b, br])
|
||||
}
|
||||
}
|
||||
@ -112,7 +103,10 @@ pub struct ScriptsElem {
|
||||
impl LayoutMath for ScriptsElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
self.body().layout_math(ctx)
|
||||
let mut fragment = ctx.layout_fragment(&self.body())?;
|
||||
fragment.set_limits(Limits::Never);
|
||||
ctx.push(fragment);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,10 +129,56 @@ pub struct LimitsElem {
|
||||
impl LayoutMath for LimitsElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
self.body().layout_math(ctx)
|
||||
let mut fragment = ctx.layout_fragment(&self.body())?;
|
||||
fragment.set_limits(Limits::Always);
|
||||
ctx.push(fragment);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes in which situation a frame should use limits for attachments.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Limits {
|
||||
/// Always scripts.
|
||||
Never,
|
||||
/// Display limits only in `display` math.
|
||||
Display,
|
||||
/// Always limits.
|
||||
Always,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether limits should be displayed in this context
|
||||
pub fn active(&self, ctx: &MathContext) -> bool {
|
||||
match self {
|
||||
Self::Always => true,
|
||||
Self::Display => ctx.style.size == MathSize::Display,
|
||||
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 {
|
||||
($e: ident, $attr: ident) => {
|
||||
$e.as_ref().map(|e| e.$attr()).unwrap_or_default()
|
||||
@ -358,14 +398,3 @@ fn is_atomic_text_frame(frame: &Frame) -> bool {
|
||||
.filter(|item| !matches!(item, FrameItem::Meta(_, _)));
|
||||
matches!(iter.next(), Some(FrameItem::Text(_))) && iter.next().is_none()
|
||||
}
|
||||
|
||||
/// Unicode codepoints that should have sub- and superscripts attached as limits.
|
||||
#[rustfmt::skip]
|
||||
const 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}',
|
||||
];
|
||||
|
@ -90,6 +90,15 @@ impl MathFragment {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_limits(&mut self, limits: Limits) {
|
||||
match self {
|
||||
Self::Glyph(glyph) => glyph.limits = limits,
|
||||
Self::Variant(variant) => variant.limits = limits,
|
||||
Self::Frame(fragment) => fragment.limits = limits,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_spaced(&self) -> bool {
|
||||
match self {
|
||||
MathFragment::Frame(frame) => frame.spaced,
|
||||
@ -113,6 +122,15 @@ impl MathFragment {
|
||||
_ => Frame::new(self.size()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limits(&self) -> Limits {
|
||||
match self {
|
||||
MathFragment::Glyph(glyph) => glyph.limits,
|
||||
MathFragment::Variant(variant) => variant.limits,
|
||||
MathFragment::Frame(fragment) => fragment.limits,
|
||||
_ => Limits::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GlyphFragment> for MathFragment {
|
||||
@ -149,6 +167,7 @@ pub struct GlyphFragment {
|
||||
pub class: Option<MathClass>,
|
||||
pub span: Span,
|
||||
pub meta: Vec<Meta>,
|
||||
pub limits: Limits,
|
||||
}
|
||||
|
||||
impl GlyphFragment {
|
||||
@ -164,6 +183,10 @@ impl GlyphFragment {
|
||||
}
|
||||
|
||||
pub fn with_id(ctx: &MathContext, c: char, id: GlyphId, span: Span) -> Self {
|
||||
let class = match c {
|
||||
':' => Some(MathClass::Relation),
|
||||
_ => unicode_math_class::class(c),
|
||||
};
|
||||
let mut fragment = Self {
|
||||
id,
|
||||
c,
|
||||
@ -175,11 +198,9 @@ impl GlyphFragment {
|
||||
width: Abs::zero(),
|
||||
ascent: Abs::zero(),
|
||||
descent: Abs::zero(),
|
||||
limits: Limits::for_char(c),
|
||||
italics_correction: Abs::zero(),
|
||||
class: match c {
|
||||
':' => Some(MathClass::Relation),
|
||||
_ => unicode_math_class::class(c),
|
||||
},
|
||||
class,
|
||||
span,
|
||||
meta: MetaElem::data_in(ctx.styles()),
|
||||
};
|
||||
@ -224,6 +245,7 @@ impl GlyphFragment {
|
||||
italics_correction: self.italics_correction,
|
||||
class: self.class,
|
||||
span: self.span,
|
||||
limits: self.limits,
|
||||
frame: self.into_frame(),
|
||||
}
|
||||
}
|
||||
@ -268,6 +290,7 @@ pub struct VariantFragment {
|
||||
pub font_size: Abs,
|
||||
pub class: Option<MathClass>,
|
||||
pub span: Span,
|
||||
pub limits: Limits,
|
||||
}
|
||||
|
||||
impl Debug for VariantFragment {
|
||||
@ -282,7 +305,7 @@ pub struct FrameFragment {
|
||||
pub style: MathStyle,
|
||||
pub font_size: Abs,
|
||||
pub class: MathClass,
|
||||
pub limits: bool,
|
||||
pub limits: Limits,
|
||||
pub spaced: bool,
|
||||
pub base_ascent: Abs,
|
||||
}
|
||||
@ -296,7 +319,7 @@ impl FrameFragment {
|
||||
font_size: ctx.size,
|
||||
style: ctx.style,
|
||||
class: MathClass::Normal,
|
||||
limits: false,
|
||||
limits: Limits::Never,
|
||||
spaced: false,
|
||||
base_ascent,
|
||||
}
|
||||
@ -306,7 +329,7 @@ impl FrameFragment {
|
||||
Self { class, ..self }
|
||||
}
|
||||
|
||||
pub fn with_limits(self, limits: bool) -> Self {
|
||||
pub fn with_limits(self, limits: Limits) -> Self {
|
||||
Self { limits, ..self }
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub struct OpElem {
|
||||
#[required]
|
||||
pub text: EcoString,
|
||||
|
||||
/// Whether the operator should force attachments to display as limits.
|
||||
/// Whether the operator should show attachments as limits in display mode.
|
||||
#[default(false)]
|
||||
pub limits: bool,
|
||||
}
|
||||
@ -39,7 +39,11 @@ impl LayoutMath for OpElem {
|
||||
ctx.push(
|
||||
FrameFragment::new(ctx, fragment.into_frame())
|
||||
.with_class(MathClass::Large)
|
||||
.with_limits(self.limits(ctx.styles())),
|
||||
.with_limits(if self.limits(ctx.styles()) {
|
||||
Limits::Display
|
||||
} else {
|
||||
Limits::Never
|
||||
}),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -185,6 +185,7 @@ fn assemble(
|
||||
italics_correction: Abs::zero(),
|
||||
class: base.class,
|
||||
span: base.span,
|
||||
limits: base.limits,
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
@ -91,3 +91,11 @@ $ limits(integral)_a^b != integral_a^b $
|
||||
---
|
||||
// Error: 30-34 unknown variable: oops
|
||||
$ attach(A, t: #locate(it => oops)) $
|
||||
|
||||
---
|
||||
// Show and let rules for limits and scripts
|
||||
#let eq = $ ∫_a^b iota_a^b $
|
||||
#eq
|
||||
#show "∫": math.limits
|
||||
#show math.iota: math.limits
|
||||
#eq
|
||||
|
Loading…
x
Reference in New Issue
Block a user