From e07f175b448143b11c61ce0ebe84c42a6e21b727 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 31 Aug 2026 06:13:09 +0800 Subject: [PATCH] feat: support rising diagonal ellipsis --- CSharpMath.Core.Tests/Atom/LaTeXParserTest.cs | 17 +++++++++++++++++ CSharpMath/Atom/LaTeXSettings.cs | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CSharpMath.Core.Tests/Atom/LaTeXParserTest.cs b/CSharpMath.Core.Tests/Atom/LaTeXParserTest.cs index 9d122367..cf2b8ee7 100644 --- a/CSharpMath.Core.Tests/Atom/LaTeXParserTest.cs +++ b/CSharpMath.Core.Tests/Atom/LaTeXParserTest.cs @@ -52,6 +52,7 @@ public static Action CheckAtom [InlineData(@"\pi+\theta\geq 3", new[] { typeof(Variable), typeof(BinaryOperator), typeof(Variable), typeof(Relation), typeof(Number) }, @"\pi +\theta \geq 3")] // aliases [InlineData(@"\pi\ne 5 \land 3", new[] { typeof(Variable), typeof(Relation), typeof(Number), typeof(BinaryOperator), typeof(Number) }, @"\pi \neq 5\wedge 3")] + [InlineData(@"\udots", new[] { typeof(Ordinary) }, @"\udots ")] // control space [InlineData(@"x \ y", new[] { typeof(Variable), typeof(Ordinary), typeof(Variable) }, @"x\ y")] // spacing @@ -96,6 +97,22 @@ public void ControlWordDoesNotConsumeFollowingStar() { Assert.Equal(@"\sin *", LaTeXParser.MathListToLaTeX(list).ToString()); } + [Fact] + public void TestUdotsPreservesOrdinaryNucleusInScriptsAndTables() { + var direct = Assert.IsType(ParseLaTeX(@"\udots").Atoms[0]); + Assert.Equal("\u22F0", direct.Nucleus); + Assert.Equal(@"\udots ", LaTeXParser.MathListToLaTeX(new MathList(direct)).ToString()); + + var scripted = Assert.IsType(ParseLaTeX(@"\udots^a_b").Atoms[0]); + Assert.Equal("\u22F0", scripted.Nucleus); + Assert.NotNull(scripted.Superscript); + Assert.NotNull(scripted.Subscript); + + var matrix = Assert.IsType(ParseLaTeX(@"\begin{matrix}\udots&x\\y&\udots\end{matrix}").Atoms[0]); + Assert.Equal("\u22F0", matrix.Cells[0][0].Atoms.OfType().Single().Nucleus); + Assert.Equal("\u22F0", matrix.Cells[1][1].Atoms.OfType().Single().Nucleus); + } + /// new[] { Base list }, new[] { Script of first atom }, new[] { Script of first atom inside script of first atom } [Theory] [InlineData("x^2", "x^2", new[] { typeof(Variable) }, new[] { typeof(Number) })] diff --git a/CSharpMath/Atom/LaTeXSettings.cs b/CSharpMath/Atom/LaTeXSettings.cs index 3ef5599a..db86e8e8 100644 --- a/CSharpMath/Atom/LaTeXSettings.cs +++ b/CSharpMath/Atom/LaTeXSettings.cs @@ -591,6 +591,7 @@ atom is Accent accent { @"\dag", new Ordinary("†") }, { @"\ddag", new Ordinary("‡") }, { @"\dots", new Ordinary("…") }, + { @"\udots", new Ordinary("⋰") }, { @"\pounds", new Ordinary("£") }, // \{ is defined in Table 1 // \} is defined in Table 1 @@ -1189,4 +1190,4 @@ atom is Accent accent // \varsupsetneqq -> ⫌ + U+FE00 (Variation Selector 1) Not dealing with variation selectors, thank you very much }; } -} \ No newline at end of file +}