Change the default math class of U+22A5 ⊥ UP TACK to Normal (#5714)

This commit is contained in:
Malo 2025-01-31 11:05:03 +01:00 committed by GitHub
parent 46727878da
commit f239b0a6a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 41 additions and 10 deletions

1
Cargo.lock generated
View File

@ -3106,6 +3106,7 @@ dependencies = [
"rayon", "rayon",
"siphasher 1.0.1", "siphasher 1.0.1",
"thin-vec", "thin-vec",
"unicode-math-class",
] ]
[[package]] [[package]]

View File

@ -13,6 +13,7 @@ use typst_library::math::{EquationElem, MathSize};
use typst_library::text::{Font, Glyph, Lang, Region, TextElem, TextItem}; use typst_library::text::{Font, Glyph, Lang, Region, TextElem, TextItem};
use typst_library::visualize::Paint; use typst_library::visualize::Paint;
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::default_math_class;
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use super::{stretch_glyph, MathContext, Scaled}; use super::{stretch_glyph, MathContext, Scaled};
@ -275,11 +276,7 @@ impl GlyphFragment {
span: Span, span: Span,
) -> Self { ) -> Self {
let class = EquationElem::class_in(styles) let class = EquationElem::class_in(styles)
.or_else(|| match c { .or_else(|| default_math_class(c))
':' => Some(MathClass::Relation),
'.' | '/' | '⋯' | '⋱' | '⋰' | '⋮' => Some(MathClass::Normal),
_ => unicode_math_class::class(c),
})
.unwrap_or(MathClass::Normal); .unwrap_or(MathClass::Normal);
let mut fragment = Self { let mut fragment = Self {
@ -629,7 +626,7 @@ pub enum Limits {
impl Limits { impl Limits {
/// The default limit configuration if the given character is the base. /// The default limit configuration if the given character is the base.
pub fn for_char(c: char) -> Self { pub fn for_char(c: char) -> Self {
match unicode_math_class::class(c) { match default_math_class(c) {
Some(MathClass::Large) => { Some(MathClass::Large) => {
if is_integral_char(c) { if is_integral_char(c) {
Limits::Never Limits::Never

View File

@ -1,6 +1,6 @@
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use typst_syntax::Spanned; use typst_syntax::Spanned;
use typst_utils::Numeric; use typst_utils::{default_math_class, Numeric};
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use crate::diag::{bail, At, HintedStrResult, StrResult}; use crate::diag::{bail, At, HintedStrResult, StrResult};
@ -292,7 +292,7 @@ impl Delimiter {
pub fn char(c: char) -> StrResult<Self> { pub fn char(c: char) -> StrResult<Self> {
if !matches!( if !matches!(
unicode_math_class::class(c), default_math_class(c),
Some(MathClass::Opening | MathClass::Closing | MathClass::Fence), Some(MathClass::Opening | MathClass::Closing | MathClass::Fence),
) { ) {
bail!("invalid delimiter: \"{}\"", c) bail!("invalid delimiter: \"{}\"", c)
@ -311,7 +311,7 @@ impl Delimiter {
Some(']') => Self(Some('[')), Some(']') => Self(Some('[')),
Some('{') => Self(Some('}')), Some('{') => Self(Some('}')),
Some('}') => Self(Some('{')), Some('}') => Self(Some('{')),
Some(c) => match unicode_math_class::class(c) { Some(c) => match default_math_class(c) {
Some(MathClass::Opening) => Self(char::from_u32(c as u32 + 1)), Some(MathClass::Opening) => Self(char::from_u32(c as u32 + 1)),
Some(MathClass::Closing) => Self(char::from_u32(c as u32 - 1)), Some(MathClass::Closing) => Self(char::from_u32(c as u32 - 1)),
_ => Self(Some(c)), _ => Self(Some(c)),

View File

@ -3,6 +3,7 @@ use std::mem;
use std::ops::{Index, IndexMut, Range}; use std::ops::{Index, IndexMut, Range};
use ecow::{eco_format, EcoString}; use ecow::{eco_format, EcoString};
use typst_utils::default_math_class;
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use crate::set::{syntax_set, SyntaxSet}; use crate::set::{syntax_set, SyntaxSet};
@ -468,7 +469,7 @@ fn math_class(text: &str) -> Option<MathClass> {
chars chars
.next() .next()
.filter(|_| chars.next().is_none()) .filter(|_| chars.next().is_none())
.and_then(unicode_math_class::class) .and_then(default_math_class)
} }
/// Parse an argument list in math: `(a, b; c, d; size: #50%)`. /// Parse an argument list in math: `(a, b; c, d; size: #50%)`.

View File

@ -18,6 +18,7 @@ portable-atomic = { workspace = true }
rayon = { workspace = true } rayon = { workspace = true }
siphasher = { workspace = true } siphasher = { workspace = true }
thin-vec = { workspace = true } thin-vec = { workspace = true }
unicode-math-class = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View File

@ -31,6 +31,7 @@ use std::ops::{Add, Deref, Div, Mul, Neg, Sub};
use std::sync::Arc; use std::sync::Arc;
use siphasher::sip128::{Hasher128, SipHasher13}; use siphasher::sip128::{Hasher128, SipHasher13};
use unicode_math_class::MathClass;
/// Turn a closure into a struct implementing [`Debug`]. /// Turn a closure into a struct implementing [`Debug`].
pub fn debug<F>(f: F) -> impl Debug pub fn debug<F>(f: F) -> impl Debug
@ -337,3 +338,28 @@ pub trait Numeric:
/// Whether `self` consists only of finite parts. /// Whether `self` consists only of finite parts.
fn is_finite(self) -> bool; fn is_finite(self) -> bool;
} }
/// Returns the default math class of a character in Typst, if it has one.
///
/// This is determined by the Unicode math class, with some manual overrides.
pub fn default_math_class(c: char) -> Option<MathClass> {
match c {
// Better spacing.
// https://github.com/typst/typst/commit/2e039cb052fcb768027053cbf02ce396f6d7a6be
':' => Some(MathClass::Relation),
// Better spacing when used alongside + PLUS SIGN.
// https://github.com/typst/typst/pull/1726
'⋯' | '⋱' | '⋰' | '⋮' => Some(MathClass::Normal),
// Better spacing.
// https://github.com/typst/typst/pull/1855
'.' | '/' => Some(MathClass::Normal),
// ⊥ UP TACK should not be a relation, contrary to ⟂ PERPENDICULAR.
// https://github.com/typst/typst/pull/5714
'\u{22A5}' => Some(MathClass::Normal),
c => unicode_math_class::class(c),
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

View File

@ -45,3 +45,8 @@ $class("large", ->)_a$
$limits(class("normal", ->))_a$ $limits(class("normal", ->))_a$
$ scripts(class("relation", x))_a $ $ scripts(class("relation", x))_a $
--- issue-4985-up-tack-is-normal-perp-is-relation ---
$ top = 1 \
bot = 2 \
a perp b $