mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Better math atoms
This commit is contained in:
parent
a50cb58823
commit
ea378e89b4
@ -10,7 +10,7 @@ use super::*;
|
|||||||
/// ## Category
|
/// ## Category
|
||||||
/// math
|
/// math
|
||||||
#[func]
|
#[func]
|
||||||
#[capable(Texify)]
|
#[capable(LayoutMath)]
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct AtomNode(pub EcoString);
|
pub struct AtomNode(pub EcoString);
|
||||||
|
|
||||||
@ -21,26 +21,35 @@ impl AtomNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Texify for AtomNode {
|
impl LayoutMath for AtomNode {
|
||||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
let multi = self.0.graphemes(true).count() > 1;
|
let mut chars = self.0.chars();
|
||||||
if multi {
|
if let Some(glyph) = chars
|
||||||
t.push_str("\\mathrm{");
|
.next()
|
||||||
}
|
.filter(|_| chars.next().is_none())
|
||||||
|
.and_then(|c| GlyphFragment::try_new(ctx, c))
|
||||||
for c in self.0.chars() {
|
{
|
||||||
let supportive = c == '|';
|
// A single letter that is available in the math font.
|
||||||
if supportive {
|
if ctx.style.size == MathSize::Display
|
||||||
t.support();
|
&& glyph.class() == Some(MathClass::Large)
|
||||||
|
{
|
||||||
|
let height = scaled!(ctx, display_operator_min_height);
|
||||||
|
ctx.push(glyph.stretch_vertical(ctx, height, Abs::zero()));
|
||||||
|
} else {
|
||||||
|
ctx.push(glyph);
|
||||||
}
|
}
|
||||||
t.push_escaped(c);
|
} else if self.0.chars().all(|c| c.is_ascii_digit()) {
|
||||||
if supportive {
|
// A number that should respect math styling and can therefore
|
||||||
t.support();
|
// not fall back to the normal text layout.
|
||||||
|
let mut vec = vec![];
|
||||||
|
for c in self.0.chars() {
|
||||||
|
vec.push(GlyphFragment::new(ctx, c).into());
|
||||||
}
|
}
|
||||||
}
|
let frame = MathRow(vec).to_frame(ctx);
|
||||||
|
ctx.push(frame);
|
||||||
if multi {
|
} else {
|
||||||
t.push_str("}");
|
// Anything else is handled by Typst's standard text layout.
|
||||||
|
TextNode(self.0.clone()).pack().layout_math(ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use unicode_xid::UnicodeXID;
|
use unicode_xid::UnicodeXID;
|
||||||
use unscanny::Scanner;
|
use unscanny::Scanner;
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ impl Lexer<'_> {
|
|||||||
|
|
||||||
Some(c) => match self.mode {
|
Some(c) => match self.mode {
|
||||||
LexMode::Markup => self.markup(start, c),
|
LexMode::Markup => self.markup(start, c),
|
||||||
LexMode::Math => self.math(c),
|
LexMode::Math => self.math(start, c),
|
||||||
LexMode::Code => self.code(start, c),
|
LexMode::Code => self.code(start, c),
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -404,7 +405,7 @@ impl Lexer<'_> {
|
|||||||
|
|
||||||
/// Math.
|
/// Math.
|
||||||
impl Lexer<'_> {
|
impl Lexer<'_> {
|
||||||
fn math(&mut self, c: char) -> SyntaxKind {
|
fn math(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
match c {
|
match c {
|
||||||
'\\' => self.backslash(),
|
'\\' => self.backslash(),
|
||||||
':' if self.s.at(is_id_start) => self.maybe_symbol(),
|
':' if self.s.at(is_id_start) => self.maybe_symbol(),
|
||||||
@ -441,13 +442,7 @@ impl Lexer<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Other math atoms.
|
// Other math atoms.
|
||||||
_ => {
|
_ => self.atom(start, c),
|
||||||
// Keep numbers together.
|
|
||||||
if c.is_numeric() {
|
|
||||||
self.s.eat_while(char::is_numeric);
|
|
||||||
}
|
|
||||||
SyntaxKind::Atom
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,6 +464,22 @@ impl Lexer<'_> {
|
|||||||
|
|
||||||
SyntaxKind::Ident
|
SyntaxKind::Ident
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn atom(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
|
// Keep numbers and grapheme clusters together.
|
||||||
|
if c.is_numeric() {
|
||||||
|
self.s.eat_while(char::is_numeric);
|
||||||
|
} else {
|
||||||
|
let len = self
|
||||||
|
.s
|
||||||
|
.get(start..self.s.string().len())
|
||||||
|
.graphemes(true)
|
||||||
|
.next()
|
||||||
|
.map_or(0, str::len);
|
||||||
|
self.s.jump(start + len);
|
||||||
|
}
|
||||||
|
SyntaxKind::Atom
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Code.
|
/// Code.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user