Add missing under/over-delimiters (#4637)

This commit is contained in:
mkorje 2024-08-05 11:28:17 +00:00 committed by GitHub
parent 211b546e4e
commit 810491c9d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 191 additions and 39 deletions

View File

@ -176,6 +176,10 @@ pub fn module() -> Module {
math.define_elem::<OverbraceElem>();
math.define_elem::<UnderbracketElem>();
math.define_elem::<OverbracketElem>();
math.define_elem::<UnderparenElem>();
math.define_elem::<OverparenElem>();
math.define_elem::<UndershellElem>();
math.define_elem::<OvershellElem>();
math.define_elem::<CancelElem>();
math.define_elem::<FracElem>();
math.define_elem::<BinomElem>();

View File

@ -2,9 +2,9 @@ use crate::diag::SourceResult;
use crate::foundations::{elem, Content, Packed, StyleChain};
use crate::layout::{Abs, Em, FixedAlignment, Frame, FrameItem, Point, Size};
use crate::math::{
alignments, scaled_font_size, style_cramped, style_for_subscript, AlignmentResult,
FrameFragment, GlyphFragment, LayoutMath, LeftRightAlternator, MathContext, MathRun,
Scaled,
alignments, scaled_font_size, style_cramped, style_for_subscript,
style_for_superscript, AlignmentResult, FrameFragment, GlyphFragment, LayoutMath,
LeftRightAlternator, MathContext, MathRun, Scaled,
};
use crate::syntax::Span;
use crate::text::TextElem;
@ -12,11 +12,13 @@ use crate::visualize::{FixedStroke, Geometry};
const BRACE_GAP: Em = Em::new(0.25);
const BRACKET_GAP: Em = Em::new(0.25);
const PAREN_GAP: Em = Em::new(0.25);
const SHELL_GAP: Em = Em::new(0.25);
/// A marker to distinguish under- vs. overlines.
enum LineKind {
Over,
enum Position {
Under,
Over,
}
/// A horizontal line under content.
@ -34,7 +36,7 @@ pub struct UnderlineElem {
impl LayoutMath for Packed<UnderlineElem> {
#[typst_macros::time(name = "math.underline", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverline(ctx, styles, self.body(), self.span(), LineKind::Under)
layout_underoverline(ctx, styles, self.body(), self.span(), Position::Under)
}
}
@ -53,7 +55,7 @@ pub struct OverlineElem {
impl LayoutMath for Packed<OverlineElem> {
#[typst_macros::time(name = "math.overline", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverline(ctx, styles, self.body(), self.span(), LineKind::Over)
layout_underoverline(ctx, styles, self.body(), self.span(), Position::Over)
}
}
@ -63,11 +65,11 @@ fn layout_underoverline(
styles: StyleChain,
body: &Content,
span: Span,
line: LineKind,
position: Position,
) -> SourceResult<()> {
let (extra_height, content, line_pos, content_pos, baseline, bar_height);
match line {
LineKind::Under => {
match position {
Position::Under => {
let sep = scaled!(ctx, styles, underbar_extra_descender);
bar_height = scaled!(ctx, styles, underbar_rule_thickness);
let gap = scaled!(ctx, styles, underbar_vertical_gap);
@ -79,7 +81,7 @@ fn layout_underoverline(
content_pos = Point::zero();
baseline = content.ascent()
}
LineKind::Over => {
Position::Over => {
let sep = scaled!(ctx, styles, overbar_extra_ascender);
bar_height = scaled!(ctx, styles, overbar_rule_thickness);
let gap = scaled!(ctx, styles, overbar_vertical_gap);
@ -145,7 +147,7 @@ impl LayoutMath for Packed<UnderbraceElem> {
&self.annotation(styles),
'⏟',
BRACE_GAP,
false,
Position::Under,
self.span(),
)
}
@ -177,7 +179,7 @@ impl LayoutMath for Packed<OverbraceElem> {
&self.annotation(styles),
'⏞',
BRACE_GAP,
true,
Position::Over,
self.span(),
)
}
@ -200,7 +202,7 @@ pub struct UnderbracketElem {
}
impl LayoutMath for Packed<UnderbracketElem> {
#[typst_macros::time(name = "math.underbrace", span = self.span())]
#[typst_macros::time(name = "math.underbracket", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverspreader(
ctx,
@ -209,7 +211,7 @@ impl LayoutMath for Packed<UnderbracketElem> {
&self.annotation(styles),
'⎵',
BRACKET_GAP,
false,
Position::Under,
self.span(),
)
}
@ -241,7 +243,135 @@ impl LayoutMath for Packed<OverbracketElem> {
&self.annotation(styles),
'⎴',
BRACKET_GAP,
true,
Position::Over,
self.span(),
)
}
}
/// A horizontal parenthesis under content, with an optional annotation below.
///
/// ```example
/// $ underparen(1 + 2 + ... + 5, "numbers") $
/// ```
#[elem(LayoutMath)]
pub struct UnderparenElem {
/// The content above the parenthesis.
#[required]
pub body: Content,
/// The optional content below the parenthesis.
#[positional]
pub annotation: Option<Content>,
}
impl LayoutMath for Packed<UnderparenElem> {
#[typst_macros::time(name = "math.underparen", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverspreader(
ctx,
styles,
self.body(),
&self.annotation(styles),
'⏝',
PAREN_GAP,
Position::Under,
self.span(),
)
}
}
/// A horizontal parenthesis over content, with an optional annotation above.
///
/// ```example
/// $ overparen(1 + 2 + ... + 5, "numbers") $
/// ```
#[elem(LayoutMath)]
pub struct OverparenElem {
/// The content below the parenthesis.
#[required]
pub body: Content,
/// The optional content above the parenthesis.
#[positional]
pub annotation: Option<Content>,
}
impl LayoutMath for Packed<OverparenElem> {
#[typst_macros::time(name = "math.overparen", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverspreader(
ctx,
styles,
self.body(),
&self.annotation(styles),
'⏜',
PAREN_GAP,
Position::Over,
self.span(),
)
}
}
/// A horizontal tortoise shell bracket under content, with an optional annotation below.
///
/// ```example
/// $ undershell(1 + 2 + ... + 5, "numbers") $
/// ```
#[elem(LayoutMath)]
pub struct UndershellElem {
/// The content above the tortoise shell bracket.
#[required]
pub body: Content,
/// The optional content below the tortoise shell bracket.
#[positional]
pub annotation: Option<Content>,
}
impl LayoutMath for Packed<UndershellElem> {
#[typst_macros::time(name = "math.undershell", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverspreader(
ctx,
styles,
self.body(),
&self.annotation(styles),
'⏡',
SHELL_GAP,
Position::Under,
self.span(),
)
}
}
/// A horizontal tortoise shell bracket over content, with an optional annotation above.
///
/// ```example
/// $ overshell(1 + 2 + ... + 5, "numbers") $
/// ```
#[elem(LayoutMath)]
pub struct OvershellElem {
/// The content below the tortoise shell bracket.
#[required]
pub body: Content,
/// The optional content above the tortoise shell bracket.
#[positional]
pub annotation: Option<Content>,
}
impl LayoutMath for Packed<OvershellElem> {
#[typst_macros::time(name = "math.overshell", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
layout_underoverspreader(
ctx,
styles,
self.body(),
&self.annotation(styles),
'⏠',
SHELL_GAP,
Position::Over,
self.span(),
)
}
@ -256,7 +386,7 @@ fn layout_underoverspreader(
annotation: &Option<Content>,
c: char,
gap: Em,
reverse: bool,
position: Position,
span: Span,
) -> SourceResult<()> {
let font_size = scaled_font_size(ctx, styles);
@ -267,29 +397,29 @@ fn layout_underoverspreader(
let glyph = GlyphFragment::new(ctx, styles, c, span);
let stretched = glyph.stretch_horizontal(ctx, body.width(), Abs::zero());
let mut rows = vec![MathRun::new(vec![body]), stretched.into()];
let (sup_style, sub_style);
let row_styles = if reverse {
sup_style = style_for_subscript(styles);
styles.chain(&sup_style)
} else {
sub_style = style_for_subscript(styles);
styles.chain(&sub_style)
};
rows.extend(
annotation
.as_ref()
.map(|annotation| ctx.layout_into_run(annotation, row_styles))
.transpose()?,
);
let mut baseline = 0;
if reverse {
rows.reverse();
baseline = rows.len() - 1;
let mut rows = vec![];
let baseline = match position {
Position::Under => {
rows.push(MathRun::new(vec![body]));
rows.push(stretched.into());
if let Some(annotation) = annotation {
let under_style = style_for_subscript(styles);
let annotation_styles = styles.chain(&under_style);
rows.push(ctx.layout_into_run(annotation, annotation_styles)?);
}
0
}
Position::Over => {
if let Some(annotation) = annotation {
let over_style = style_for_superscript(styles);
let annotation_styles = styles.chain(&over_style);
rows.push(ctx.layout_into_run(annotation, annotation_styles)?);
}
rows.push(stretched.into());
rows.push(MathRun::new(vec![body]));
rows.len() - 1
}
};
let frame = stack(
rows,

View File

@ -46,6 +46,10 @@
"overbrace",
"underbracket",
"overbracket",
"underparen",
"overparen",
"undershell",
"overshell",
]
details: |
Delimiters above or below parts of an equation.

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

View File

@ -19,3 +19,17 @@ $ x = overbracket(
$ underbracket([1, 2/3], "relevant stuff")
arrow.l.r.double.long
overbracket([4/5,6], "irrelevant stuff") $
--- math-underover-parens ---
// Test parentheses.
$ overparen(
underparen(x + y, "long comment"),
1 + 2 + ... + 5
) $
--- math-underover-shells ---
// Test tortoise shell brackets.
$ undershell(
1 + overshell(2 + ..., x + y),
"all stuff"
) $