From 6a3d01a4e2b4d2f2ed1890bd474dee14ab4ef416 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Sun, 24 May 2020 18:19:48 +0800 Subject: [PATCH 01/20] Implemented for fractions, radicals and superscripts --- CSharpMath.Editor/Extensions/MathList.cs | 58 +++++++++++++++++++++--- CSharpMath.Editor/MathKeyboard.cs | 12 ++++- CSharpMath.Editor/MathListIndex.cs | 6 +++ CSharpMath/Atom/MathList.cs | 2 +- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index 050f0870..de6cfdac 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -4,6 +4,8 @@ namespace CSharpMath.Editor { using Atom; using Atoms = Atom.Atoms; using Structures; + using System.Linq; + partial class Extensions { static void InsertAtAtomIndexAndAdvance(this MathList self, int atomIndex, MathAtom atom, ref MathListIndex advance, MathListSubIndexType advanceType) { if (atomIndex < 0 || atomIndex > self.Count) @@ -81,6 +83,46 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, } public static void RemoveAt(this MathList self, ref MathListIndex index) { + void RemoveAtInnerList(ref MathListIndex index, TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer { + if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); + if (index.IsBeforeSubList) { + index = index.LevelDown() + ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null"); + self.RemoveAt(ref index); + MathListIndex tempIndex = index; + int i = 0; + foreach (var innerList in atom.InnerLists) + if (!(innerList.Count == 1 && innerList[0] is Atoms.Placeholder)) + if (i++ < innerListIndex) { + foreach (var inner in innerList) + self.InsertAndAdvance(ref index, inner, MathListSubIndexType.None); + tempIndex = index; + } + else + foreach (var inner in innerList) + self.InsertAndAdvance(ref tempIndex, inner, MathListSubIndexType.None); + if(index.SubIndexType != MathListSubIndexType.None && tempIndex.AtomIndex == 0 // We deleted an atom only consisting of placeholders + || atom.Superscript.Count > 0 || atom.Subscript.Count > 0) + self.InsertAndAdvance(ref tempIndex, LaTeXSettings.Placeholder, MathListSubIndexType.None); + if(atom.Superscript.Count > 0) self[tempIndex.AtomIndex - 1].Superscript.Append(atom.Superscript); + if(atom.Subscript.Count > 0) self[tempIndex.AtomIndex - 1].Subscript.Append(atom.Subscript); + } else atom.InnerLists.ElementAt(innerListIndex).RemoveAt(ref index.SubIndex); + } + void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscript) { + if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); + if (index.IsBeforeSubList) { + index = index.LevelDown() + ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null"); + var tempIndex = index; + if (superscript) { + if (atom.Superscript.Count == 1 && atom.Superscript[0] is Atoms.Placeholder) + foreach (var inner in atom.Superscript) + self.InsertAndAdvance(ref tempIndex, inner, MathListSubIndexType.None); + atom.Superscript.Clear(); + } + } else (superscript ? atom.Superscript : atom.Subscript).RemoveAt(ref index.SubIndex); + } + index ??= MathListIndex.Level0Index(0); if (index.AtomIndex > self.Atoms.Count) throw new IndexOutOfRangeException($"Index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); @@ -132,28 +174,30 @@ public static void RemoveAt(this MathList self, ref MathListIndex index) { if (!(self.Atoms[index.AtomIndex] is Atoms.Radical radical)) throw new SubIndexTypeMismatchException(typeof(Atoms.Radical), index); if (index.SubIndexType == MathListSubIndexType.Degree) - radical.Degree.RemoveAt(ref index.SubIndex); - else radical.Radicand.RemoveAt(ref index.SubIndex); + RemoveAtInnerList(ref index, radical, 0); + else + RemoveAtInnerList(ref index, radical, 1); break; case MathListSubIndexType.Numerator: case MathListSubIndexType.Denominator: if (!(self.Atoms[index.AtomIndex] is Atoms.Fraction frac)) throw new SubIndexTypeMismatchException(typeof(Atoms.Fraction), index); if (index.SubIndexType == MathListSubIndexType.Numerator) - frac.Numerator.RemoveAt(ref index.SubIndex); - else frac.Denominator.RemoveAt(ref index.SubIndex); + RemoveAtInnerList(ref index, frac, 0); + else + RemoveAtInnerList(ref index, frac, 1); break; case MathListSubIndexType.Subscript: var current = self.Atoms[index.AtomIndex]; if (current.Subscript.IsEmpty()) throw new SubIndexTypeMismatchException(index); - current.Subscript.RemoveAt(ref index.SubIndex); + RemoveAtInnerScript(ref index, current, false); break; case MathListSubIndexType.Superscript: current = self.Atoms[index.AtomIndex]; if (current.Superscript.IsEmpty()) throw new SubIndexTypeMismatchException(index); - current.Superscript.RemoveAt(ref index.SubIndex); + RemoveAtInnerScript(ref index, current, true); break; case MathListSubIndexType.Inner: if (!(self.Atoms[index.AtomIndex] is Atoms.Inner inner)) @@ -167,7 +211,7 @@ public static void RemoveAt(this MathList self, ref MathListIndex index) { // We have deleted to the beginning of the line and it is not the outermost line if (self.AtomAt(index) is null) { self.InsertAndAdvance(ref index, LaTeXSettings.Placeholder, MathListSubIndexType.None); - index = index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?"); ; + index = index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?"); } } } diff --git a/CSharpMath.Editor/MathKeyboard.cs b/CSharpMath.Editor/MathKeyboard.cs index efb3a007..9ca7af13 100644 --- a/CSharpMath.Editor/MathKeyboard.cs +++ b/CSharpMath.Editor/MathKeyboard.cs @@ -87,7 +87,7 @@ public MathListIndex InsertionIndex { public LineStyle LineStyle { get; set; } public Structures.Color SelectColor { get; set; } public virtual RectangleF Measure => Display?.DisplayBounds() ?? RectangleF.Empty; - public bool HasText => MathList?.Atoms?.Count > 0; + public bool HasText => MathList.Atoms.Count > 0; public void RecreateDisplayFromMathList() { var position = Display?.Position ?? default; Display = Typesetter.CreateLine(MathList, Font, Context, LineStyle); @@ -389,9 +389,17 @@ void MoveCursorRight() { void DeleteBackwards() { // delete the last atom from the list - if (HasText && _insertionIndex.Previous is MathListIndex previous) { + if (HasText && _insertionIndex.PreviousOrBeforeWholeList is MathListIndex previous) { _insertionIndex = previous; MathList.RemoveAt(ref _insertionIndex); + } else { + var index = _insertionIndex.LevelDown(); + if (index != null) { + switch (_insertionIndex.FinalSubIndexType) { + default: + break; + } + } } } diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index cb880cd3..17926a44 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -80,6 +80,12 @@ public MathListIndex LevelUpWithSubIndex(MathListSubIndexType type, MathListInde MathListSubIndexType.None => AtomIndex > 0 ? Level0Index(AtomIndex - 1) : null, _ => SubIndex?.Previous is MathListIndex prevSubIndex ? IndexAtLocation(AtomIndex, SubIndexType, prevSubIndex) : null, }; + internal bool IsBeforeSubList => SubIndex is { AtomIndex: -1, SubIndexType: MathListSubIndexType.None }; + internal MathListIndex? PreviousOrBeforeWholeList => SubIndexType switch + { + MathListSubIndexType.None => AtomIndex > -1 ? Level0Index(AtomIndex - 1) : null, + _ => SubIndex?.PreviousOrBeforeWholeList is MathListIndex prevSubIndex ? IndexAtLocation(AtomIndex, SubIndexType, prevSubIndex) : null, + }; ///Returns the next index. public MathListIndex Next => SubIndexType switch diff --git a/CSharpMath/Atom/MathList.cs b/CSharpMath/Atom/MathList.cs index 7cfeeba2..d2a2f4b0 100644 --- a/CSharpMath/Atom/MathList.cs +++ b/CSharpMath/Atom/MathList.cs @@ -4,7 +4,7 @@ namespace CSharpMath.Atom { #pragma warning disable CA1710 // Identifiers should have correct suffix - // WTF CA1710, you want types inheriting IList to have the Collection suffix? + // WTF CA1710, you want types implementing IList to have the Collection suffix? class DisabledMathList : MathList { internal DisabledMathList() { } public override void Add(MathAtom item) => throw new InvalidOperationException("Scripts are not allowed!"); From 9e8e43521b7470ecc083b480d4684c059f716dd8 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Sun, 24 May 2020 23:18:41 +0800 Subject: [PATCH 02/20] Added tests --- CSharpMath.Editor.Tests/KeyPressTests.cs | 61 ++++++++++++++++++++++-- CSharpMath.Editor/Extensions/MathList.cs | 26 ++++++---- CSharpMath.Editor/MathKeyboard.cs | 2 +- CSharpMath.Editor/MathListIndex.cs | 2 + 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index e5d84b13..2099100e 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -227,11 +227,27 @@ public void Return(params K[] inputs) => [ Theory, T(@"", K.Backspace, K.Backspace, K.Backspace, K.Backspace, K.Backspace), + T(@"2", K.Backspace, K.Backspace, K.D1, K.Backspace, K.D2), T(@"1", K.D1, K.D2, K.Backspace), T(@"x^2", K.SmallX, K.Power, K.D2, K.D1, K.Backspace), - T(@"y_{3_4}", K.SmallY, K.Subscript, K.D3, K.Subscript, K.Backspace, K.Backspace, K.D4, K.D5, K.Backspace), - T(@"5^■", K.D5, K.Power, K.Iota, K.Kappa, K.SmallEta, K.Backspace, K.Backspace, K.Backspace, K.Backspace), - T(@"\frac{■}{\square }", K.Fraction, K.Backspace), + T(@"5", K.D5, K.Power, K.Iota, K.Kappa, K.SmallEta, K.Backspace, K.Backspace, K.Backspace, K.Backspace), + T(@"", K.Fraction, K.Backspace), + T(@"", K.Power, K.Backspace), + T(@"", K.Subscript, K.Backspace), + T(@"", K.SquareRoot, K.Backspace), + T(@"3", K.CubeRoot, K.Backspace), + T(@"", K.NthRoot, K.Backspace), + T(@"a", K.SmallA, K.Fraction, K.Backspace), + T(@"a", K.SmallA, K.SquareRoot, K.Backspace), + T(@"a3", K.SmallA, K.CubeRoot, K.Backspace), + T(@"a", K.SmallA, K.NthRoot, K.Backspace), + T(@"a", K.SmallA, K.Power, K.Backspace), + T(@"a", K.SmallA, K.Subscript, K.Backspace), + T(@"\square ^■", K.Power, K.Subscript, K.Backspace), + T(@"\square ^■", K.Power, K.Power, K.Backspace), + T(@"\square _■", K.Subscript, K.Power, K.Backspace), + T(@"\square _■", K.Subscript, K.Subscript, K.Backspace), + T(@"y_4", K.SmallY, K.Subscript, K.D3, K.Subscript, K.Backspace, K.Backspace, K.D4, K.D5, K.Backspace), T(@"", K.VerticalBar, K.VerticalBar, K.Backspace, K.Backspace, K.Backspace) ] public void Backspace(string latex, params K[] inputs) => Test(latex, inputs); @@ -239,6 +255,43 @@ public void Return(params K[] inputs) => [ Theory, T(@"", K.Left, K.Left, K.Backspace, K.Backspace, K.Right, K.Right, K.Backspace, K.Backspace, K.Left), + T(@"\frac{\square }{\square }", K.Fraction, K.Left, K.Backspace), + T(@"\sqrt{\square }", K.SquareRoot, K.Left, K.Backspace), + T(@"\sqrt[\square ]{\square }", K.NthRoot, K.Left, K.Backspace), + T(@"", K.Power, K.Left, K.Backspace), + T(@"", K.Subscript, K.Left, K.Backspace), + T(@".bcd", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".bcd", K.SquareRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".bcd", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".bcd", K.Power, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".bcd", K.Subscript, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"a.bcd", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"a.bcd", K.SmallA, K.SquareRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"a.bcd", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"a.bcd", K.SmallA, K.Power, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"a.bcd", K.SmallA, K.Subscript, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"", K.Fraction, K.Right, K.Backspace), + T(@"", K.SquareRoot, K.Right, K.Backspace), + T(@"", K.NthRoot, K.Right, K.Backspace), + T(@"", K.Power, K.Right, K.Backspace), + T(@"", K.Subscript, K.Right, K.Backspace), + T(@"bcd.", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), + T(@"bcd.", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), + T(@"abcd.", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), + T(@"abcd.", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), + T(@"", K.Fraction, K.Right, K.Right, K.Backspace), + T(@"", K.SquareRoot, K.Right, K.Right, K.Backspace), + T(@"", K.NthRoot, K.Right, K.Right, K.Backspace), + T(@"", K.Power, K.Right, K.Right, K.Backspace), + T(@"", K.Subscript, K.Right, K.Right, K.Backspace), + T(@"bcd.", K.Fraction, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"bcd.", K.NthRoot, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"abcd.", K.SmallA, K.Fraction, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"abcd.", K.SmallA, K.NthRoot, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"bcd.efg", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"bcd.efg", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"abcd.efg", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"abcd.efg", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"\frac{\square }{3}", K.Slash, K.D3, K.Left, K.Left, K.Backspace, K.Left), T(@"1_3", K.D1, K.D2, K.Subscript, K.D3, K.Left, K.Left, K.Backspace), T(@"1_3^2", K.D1, K.D4, K.Subscript, K.D3, K.Left, K.Left, K.Power, K.D2, K.Left, K.Left, K.Left, K.Left, K.Backspace), @@ -247,7 +300,7 @@ public void Return(params K[] inputs) => T(@"\sqrt[■]{\square }", K.NthRoot, K.SmallA, K.Backspace), T(@"\sqrt{■}", K.SquareRoot, K.SmallA, K.Backspace), T(@"\frac{1}{■}", K.Slash, K.D6, K.Backspace), - T(@"■_5", K.Subscript, K.D5, K.Left, K.Left, K.Backspace, K.X, K.Left, K.Left, K.Left, K.Backspace), + T(@"", K.Subscript, K.D5, K.Left, K.Left, K.Backspace), T(@"7+1^X", K.D7, K.Plus, K.D1, K.D2, K.Power, K.X, K.Left, K.Left, K.Backspace), T(@"7.^X", K.D7, K.Decimal, K.D1, K.Power, K.X, K.Left, K.Left, K.Backspace), T(@"7+■^X", K.D7, K.Plus, K.D1, K.Power, K.X, K.Left, K.Left, K.Backspace), diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index de6cfdac..fa782f1b 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -110,25 +110,31 @@ void RemoveAtInnerList(ref MathListIndex index, TAtom atom, int innerList } void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscript) { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); + var script = superscript ? atom.Superscript : atom.Subscript; if (index.IsBeforeSubList) { index = index.LevelDown() ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null"); + if (atom is Atoms.Placeholder && (superscript ? atom.Subscript : atom.Superscript).Count == 0) + self.RemoveAt(index.AtomIndex); + else index = index.Next; var tempIndex = index; - if (superscript) { - if (atom.Superscript.Count == 1 && atom.Superscript[0] is Atoms.Placeholder) - foreach (var inner in atom.Superscript) - self.InsertAndAdvance(ref tempIndex, inner, MathListSubIndexType.None); - atom.Superscript.Clear(); - } - } else (superscript ? atom.Superscript : atom.Subscript).RemoveAt(ref index.SubIndex); + if (!(script.Count == 1 && script[0] is Atoms.Placeholder)) + foreach (var inner in script) + self.InsertAndAdvance(ref tempIndex, inner, MathListSubIndexType.None); + script.Clear(); + } else script.RemoveAt(ref index.SubIndex); } - index ??= MathListIndex.Level0Index(0); if (index.AtomIndex > self.Atoms.Count) throw new IndexOutOfRangeException($"Index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); switch (index.SubIndexType) { case MathListSubIndexType.None: - self.RemoveAt(index.AtomIndex); + if (index.AtomIndex == -1) { + index = index.Next; + if (self.Atoms[index.AtomIndex] is Atoms.Placeholder) + self.RemoveAt(index.AtomIndex); + } else + self.RemoveAt(index.AtomIndex); break; case var _ when index.SubIndex is null: throw new InvalidCodePathException("index.SubIndex is null despite non-None subindex type"); @@ -202,7 +208,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip case MathListSubIndexType.Inner: if (!(self.Atoms[index.AtomIndex] is Atoms.Inner inner)) throw new SubIndexTypeMismatchException(typeof(Atoms.Inner), index); - inner.InnerList.RemoveAt(ref index.SubIndex); + RemoveAtInnerList(ref index, inner, 0); break; default: throw new SubIndexTypeMismatchException(index); diff --git a/CSharpMath.Editor/MathKeyboard.cs b/CSharpMath.Editor/MathKeyboard.cs index 9ca7af13..4c473033 100644 --- a/CSharpMath.Editor/MathKeyboard.cs +++ b/CSharpMath.Editor/MathKeyboard.cs @@ -499,7 +499,7 @@ void InsertSymbolName(string name, bool subscript = false, bool superscript = fa break; case MathKeyboardInput.BaseEPower: InsertAtom(LaTeXSettings.ForAscii((sbyte)'e') - ?? throw new InvalidCodePathException("LaTeXDefaults.ForAscii((byte)'e') is null")); + ?? throw new InvalidCodePathException($"{nameof(LaTeXSettings.ForAscii)}((sbyte)'e') is null")); HandleScriptButton(true); break; case MathKeyboardInput.Logarithm: diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index 17926a44..4c6977b5 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -80,7 +80,9 @@ public MathListIndex LevelUpWithSubIndex(MathListSubIndexType type, MathListInde MathListSubIndexType.None => AtomIndex > 0 ? Level0Index(AtomIndex - 1) : null, _ => SubIndex?.Previous is MathListIndex prevSubIndex ? IndexAtLocation(AtomIndex, SubIndexType, prevSubIndex) : null, }; + /// Should be used inside only! internal bool IsBeforeSubList => SubIndex is { AtomIndex: -1, SubIndexType: MathListSubIndexType.None }; + /// Valid for only! internal MathListIndex? PreviousOrBeforeWholeList => SubIndexType switch { MathListSubIndexType.None => AtomIndex > -1 ? Level0Index(AtomIndex - 1) : null, From 98aa35dfcb308c9e3d997e23fc3a41d295989b9e Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Sun, 24 May 2020 23:29:53 +0800 Subject: [PATCH 03/20] More tests --- CSharpMath.Editor.Tests/KeyPressTests.cs | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index 2099100e..1ba83928 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -255,11 +255,21 @@ public void Return(params K[] inputs) => [ Theory, T(@"", K.Left, K.Left, K.Backspace, K.Backspace, K.Right, K.Right, K.Backspace, K.Backspace, K.Left), - T(@"\frac{\square }{\square }", K.Fraction, K.Left, K.Backspace), - T(@"\sqrt{\square }", K.SquareRoot, K.Left, K.Backspace), - T(@"\sqrt[\square ]{\square }", K.NthRoot, K.Left, K.Backspace), - T(@"", K.Power, K.Left, K.Backspace), - T(@"", K.Subscript, K.Left, K.Backspace), + T(@".\frac{\square }{\square }", K.Fraction, K.Left, K.Backspace, K.Decimal), + T(@".\sqrt{\square }", K.SquareRoot, K.Left, K.Backspace, K.Decimal), + T(@".\sqrt[\square ]{\square }", K.NthRoot, K.Left, K.Backspace, K.Decimal), + T(@".", K.Power, K.Left, K.Backspace, K.Decimal), + T(@".", K.Subscript, K.Left, K.Backspace, K.Decimal), + T(@".", K.Fraction, K.Right, K.Backspace, K.Decimal), + T(@".", K.SquareRoot, K.Right, K.Backspace, K.Decimal), + T(@".", K.NthRoot, K.Right, K.Backspace, K.Decimal), + T(@".", K.Power, K.Right, K.Backspace, K.Decimal), + T(@".", K.Subscript, K.Right, K.Backspace, K.Decimal), + T(@".", K.Fraction, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.SquareRoot, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.NthRoot, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.Power, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.Subscript, K.Right, K.Right, K.Backspace, K.Decimal), T(@".bcd", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@".bcd", K.SquareRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@".bcd", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), @@ -270,20 +280,10 @@ public void Return(params K[] inputs) => T(@"a.bcd", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.Power, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.Subscript, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), - T(@"", K.Fraction, K.Right, K.Backspace), - T(@"", K.SquareRoot, K.Right, K.Backspace), - T(@"", K.NthRoot, K.Right, K.Backspace), - T(@"", K.Power, K.Right, K.Backspace), - T(@"", K.Subscript, K.Right, K.Backspace), T(@"bcd.", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), T(@"bcd.", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), T(@"abcd.", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), T(@"abcd.", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), - T(@"", K.Fraction, K.Right, K.Right, K.Backspace), - T(@"", K.SquareRoot, K.Right, K.Right, K.Backspace), - T(@"", K.NthRoot, K.Right, K.Right, K.Backspace), - T(@"", K.Power, K.Right, K.Right, K.Backspace), - T(@"", K.Subscript, K.Right, K.Right, K.Backspace), T(@"bcd.", K.Fraction, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"bcd.", K.NthRoot, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"abcd.", K.SmallA, K.Fraction, K.Right, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), From eccb0a83c41ad2386fe5de3a3dfcca7f836c49ea Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Sun, 24 May 2020 23:42:24 +0800 Subject: [PATCH 04/20] Tests for Inner --- CSharpMath.Editor.Tests/KeyPressTests.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index 1ba83928..e1d137b9 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -258,26 +258,49 @@ public void Return(params K[] inputs) => T(@".\frac{\square }{\square }", K.Fraction, K.Left, K.Backspace, K.Decimal), T(@".\sqrt{\square }", K.SquareRoot, K.Left, K.Backspace, K.Decimal), T(@".\sqrt[\square ]{\square }", K.NthRoot, K.Left, K.Backspace, K.Decimal), + T(@".\left( \square \right) ", K.BothRoundBrackets, K.Left, K.Backspace, K.Decimal), T(@".", K.Power, K.Left, K.Backspace, K.Decimal), T(@".", K.Subscript, K.Left, K.Backspace, K.Decimal), + T(@".\frac{\square }{\square }", K.SmallA, K.Fraction, K.Left, K.Backspace, K.Decimal), + T(@".\sqrt{\square }", K.SmallA, K.SquareRoot, K.Left, K.Backspace, K.Decimal), + T(@".\sqrt[\square ]{\square }", K.SmallA, K.NthRoot, K.Left, K.Backspace, K.Decimal), + T(@".\left( \square \right) ", K.SmallA, K.BothRoundBrackets, K.Left, K.Backspace, K.Decimal), + T(@".^{\square }", K.SmallA, K.Power, K.Left, K.Backspace, K.Decimal), + T(@"._{\square }", K.SmallA, K.Subscript, K.Left, K.Backspace, K.Decimal), T(@".", K.Fraction, K.Right, K.Backspace, K.Decimal), T(@".", K.SquareRoot, K.Right, K.Backspace, K.Decimal), T(@".", K.NthRoot, K.Right, K.Backspace, K.Decimal), + T(@".", K.BothRoundBrackets, K.Right, K.Backspace, K.Decimal), T(@".", K.Power, K.Right, K.Backspace, K.Decimal), T(@".", K.Subscript, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.Fraction, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.SquareRoot, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.NthRoot, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.BothRoundBrackets, K.Right, K.Backspace, K.Decimal), + T(@".", K.SmallA, K.Power, K.Right, K.Backspace, K.Decimal), + T(@".", K.SmallA, K.Subscript, K.Right, K.Backspace, K.Decimal), T(@".", K.Fraction, K.Right, K.Right, K.Backspace, K.Decimal), T(@".", K.SquareRoot, K.Right, K.Right, K.Backspace, K.Decimal), T(@".", K.NthRoot, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.BothRoundBrackets, K.Right, K.Right, K.Backspace, K.Decimal), T(@".", K.Power, K.Right, K.Right, K.Backspace, K.Decimal), T(@".", K.Subscript, K.Right, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.Fraction, K.Right, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.SquareRoot, K.Right, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.NthRoot, K.Right, K.Right, K.Backspace, K.Decimal), + T(@"a.", K.SmallA, K.BothRoundBrackets, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.SmallA, K.Power, K.Right, K.Right, K.Backspace, K.Decimal), + T(@".", K.SmallA, K.Subscript, K.Right, K.Right, K.Backspace, K.Decimal), T(@".bcd", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@".bcd", K.SquareRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@".bcd", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".bcd", K.BothRoundBrackets, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@".bcd", K.Power, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@".bcd", K.Subscript, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.SquareRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"a.bcd", K.SmallA, K.BothRoundBrackets, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.Power, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"a.bcd", K.SmallA, K.Subscript, K.SmallB, K.SmallC, K.SmallD, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"bcd.", K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.Backspace, K.Decimal), From ab4a4a7c48befbadc2bf9e65e3b3e2fdcc7355f1 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 25 May 2020 00:03:32 +0800 Subject: [PATCH 05/20] Delete trash --- CSharpMath.Editor/MathKeyboard.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CSharpMath.Editor/MathKeyboard.cs b/CSharpMath.Editor/MathKeyboard.cs index 4c473033..3c6fd48f 100644 --- a/CSharpMath.Editor/MathKeyboard.cs +++ b/CSharpMath.Editor/MathKeyboard.cs @@ -392,14 +392,6 @@ void DeleteBackwards() { if (HasText && _insertionIndex.PreviousOrBeforeWholeList is MathListIndex previous) { _insertionIndex = previous; MathList.RemoveAt(ref _insertionIndex); - } else { - var index = _insertionIndex.LevelDown(); - if (index != null) { - switch (_insertionIndex.FinalSubIndexType) { - default: - break; - } - } } } From 638bd1ef1e3beea2980968a78f23942ddbcb2b54 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 25 May 2020 00:14:15 +0800 Subject: [PATCH 06/20] Tests for delete at beginnning of script when both scripts are present --- CSharpMath.Editor.Tests/KeyPressTests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index e1d137b9..a5fda0d2 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -315,6 +315,22 @@ public void Return(params K[] inputs) => T(@"bcd.efg", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"abcd.efg", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"abcd.efg", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@"\square ^{\square }", K.Power, K.Right, K.Subscript, K.Backspace), + T(@"\square _{\square }", K.Subscript, K.Right, K.Power, K.Backspace), + T(@"X^{\square }", K.X, K.Power, K.Right, K.Subscript, K.Backspace), + T(@"X_{\square }", K.X, K.Subscript, K.Right, K.Power, K.Backspace), + T(@"\square ^Z", K.Power, K.Z, K.Right, K.Subscript, K.Backspace), + T(@"\square _{\square }Z", K.Subscript, K.Right, K.Power, K.Z, K.Left, K.Backspace), + T(@"X^Z", K.X, K.Power, K.Z, K.Right, K.Subscript, K.Backspace), + T(@"X_{\square }Z", K.X, K.Subscript, K.Right, K.Power, K.Z, K.Left, K.Backspace), + T(@"\square ^{\square }Y", K.Power, K.Right, K.Subscript, K.Y, K.Left, K.Backspace), + T(@"\square _Y", K.Subscript, K.Y, K.Right, K.Power, K.Backspace), + T(@"X^{\square }Y", K.X, K.Power, K.Right, K.Subscript, K.Y, K.Left, K.Backspace), + T(@"X_Y", K.X, K.Subscript, K.Y, K.Right, K.Power, K.Backspace), + T(@"\square ^ZY", K.Power, K.Z, K.Right, K.Subscript, K.Y, K.Left, K.Backspace), + T(@"\square _YZ", K.Subscript, K.Y, K.Right, K.Power, K.Z, K.Left, K.Backspace), + T(@"X^ZY", K.X, K.Power, K.Z, K.Right, K.Subscript, K.Y, K.Left, K.Backspace), + T(@"X_YZ", K.X, K.Subscript, K.Y, K.Right, K.Power, K.Z, K.Left, K.Backspace), T(@"\frac{\square }{3}", K.Slash, K.D3, K.Left, K.Left, K.Backspace, K.Left), T(@"1_3", K.D1, K.D2, K.Subscript, K.D3, K.Left, K.Left, K.Backspace), T(@"1_3^2", K.D1, K.D4, K.Subscript, K.D3, K.Left, K.Left, K.Power, K.D2, K.Left, K.Left, K.Left, K.Left, K.Backspace), From f6db396b6c09b6f75d04cbf1bd488e24a3df9829 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 25 May 2020 00:22:59 +0800 Subject: [PATCH 07/20] Also add power counterpart for this test --- CSharpMath.Editor.Tests/KeyPressTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index a5fda0d2..a393ad14 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -339,6 +339,7 @@ public void Return(params K[] inputs) => T(@"\sqrt[■]{\square }", K.NthRoot, K.SmallA, K.Backspace), T(@"\sqrt{■}", K.SquareRoot, K.SmallA, K.Backspace), T(@"\frac{1}{■}", K.Slash, K.D6, K.Backspace), + T(@"", K.Power, K.D5, K.Left, K.Left, K.Backspace), T(@"", K.Subscript, K.D5, K.Left, K.Left, K.Backspace), T(@"7+1^X", K.D7, K.Plus, K.D1, K.D2, K.Power, K.X, K.Left, K.Left, K.Backspace), T(@"7.^X", K.D7, K.Decimal, K.D1, K.Power, K.X, K.Left, K.Left, K.Backspace), From 8e2d2cadf0e2a108c19dd3db93326508a1da8180 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 25 May 2020 00:24:10 +0800 Subject: [PATCH 08/20] And placeholder counterparts --- CSharpMath.Editor.Tests/KeyPressTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index a393ad14..63fbad24 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -339,6 +339,8 @@ public void Return(params K[] inputs) => T(@"\sqrt[■]{\square }", K.NthRoot, K.SmallA, K.Backspace), T(@"\sqrt{■}", K.SquareRoot, K.SmallA, K.Backspace), T(@"\frac{1}{■}", K.Slash, K.D6, K.Backspace), + T(@"", K.Power, K.Left, K.Backspace), + T(@"", K.Subscript, K.Left, K.Backspace), T(@"", K.Power, K.D5, K.Left, K.Left, K.Backspace), T(@"", K.Subscript, K.D5, K.Left, K.Left, K.Backspace), T(@"7+1^X", K.D7, K.Plus, K.D1, K.D2, K.Power, K.X, K.Left, K.Left, K.Backspace), From fc58258c1344b002e96a2ed5de89a112870232d7 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 25 May 2020 14:12:35 +0800 Subject: [PATCH 09/20] Deleting placeholders at the start should not eliminate scripts --- CSharpMath.Editor.Tests/KeyPressTests.cs | 10 ++++++---- CSharpMath.Editor/Extensions/MathList.cs | 10 +++++++++- CSharpMath.Evaluation/Interpret.cs | 2 +- .../Resources/Resource.designer.cs | 1 - 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index 63fbad24..807530db 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -255,6 +255,8 @@ public void Return(params K[] inputs) => [ Theory, T(@"", K.Left, K.Left, K.Backspace, K.Backspace, K.Right, K.Right, K.Backspace, K.Backspace, K.Left), + T(@"", K.Power, K.Left, K.Backspace), + T(@"", K.Subscript, K.Left, K.Backspace), T(@".\frac{\square }{\square }", K.Fraction, K.Left, K.Backspace, K.Decimal), T(@".\sqrt{\square }", K.SquareRoot, K.Left, K.Backspace, K.Decimal), T(@".\sqrt[\square ]{\square }", K.NthRoot, K.Left, K.Backspace, K.Decimal), @@ -315,6 +317,10 @@ public void Return(params K[] inputs) => T(@"bcd.efg", K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"abcd.efg", K.SmallA, K.Fraction, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"abcd.efg", K.SmallA, K.NthRoot, K.SmallB, K.SmallC, K.SmallD, K.Right, K.SmallE, K.SmallF, K.SmallG, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".456", K.Subscript, K.D4, K.D5, K.D6, K.Left, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".789", K.Power, K.D7, K.D8, K.D9, K.Left, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".456789", K.Subscript, K.D4, K.D5, K.D6, K.Right, K.Power, K.D7, K.D8, K.D9, K.Left, K.Left, K.Left, K.Left, K.Left, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), + T(@".456789", K.Power, K.D7, K.D8, K.D9, K.Right, K.Subscript, K.D4, K.D5, K.D6, K.Left, K.Left, K.Left, K.Left, K.Backspace, K.Decimal), T(@"\square ^{\square }", K.Power, K.Right, K.Subscript, K.Backspace), T(@"\square _{\square }", K.Subscript, K.Right, K.Power, K.Backspace), T(@"X^{\square }", K.X, K.Power, K.Right, K.Subscript, K.Backspace), @@ -339,10 +345,6 @@ public void Return(params K[] inputs) => T(@"\sqrt[■]{\square }", K.NthRoot, K.SmallA, K.Backspace), T(@"\sqrt{■}", K.SquareRoot, K.SmallA, K.Backspace), T(@"\frac{1}{■}", K.Slash, K.D6, K.Backspace), - T(@"", K.Power, K.Left, K.Backspace), - T(@"", K.Subscript, K.Left, K.Backspace), - T(@"", K.Power, K.D5, K.Left, K.Left, K.Backspace), - T(@"", K.Subscript, K.D5, K.Left, K.Left, K.Backspace), T(@"7+1^X", K.D7, K.Plus, K.D1, K.D2, K.Power, K.X, K.Left, K.Left, K.Backspace), T(@"7.^X", K.D7, K.Decimal, K.D1, K.Power, K.X, K.Left, K.Left, K.Backspace), T(@"7+■^X", K.D7, K.Plus, K.D1, K.Power, K.X, K.Left, K.Left, K.Backspace), diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index fa782f1b..8800b8be 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -131,8 +131,16 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip case MathListSubIndexType.None: if (index.AtomIndex == -1) { index = index.Next; - if (self.Atoms[index.AtomIndex] is Atoms.Placeholder) + if (self.Atoms[index.AtomIndex] is Atoms.Placeholder { Superscript: var super, Subscript: var sub }) { self.RemoveAt(index.AtomIndex); + var tempIndex = index; + if (!(sub.Count == 1 && sub[0] is Atoms.Placeholder)) + foreach (var s in sub) + self.InsertAndAdvance(ref tempIndex, s, MathListSubIndexType.None); + if (!(super.Count == 1 && super[0] is Atoms.Placeholder)) + foreach (var s in super) + self.InsertAndAdvance(ref tempIndex, s, MathListSubIndexType.None); + } } else self.RemoveAt(index.AtomIndex); break; diff --git a/CSharpMath.Evaluation/Interpret.cs b/CSharpMath.Evaluation/Interpret.cs index 796784b0..f908406b 100644 --- a/CSharpMath.Evaluation/Interpret.cs +++ b/CSharpMath.Evaluation/Interpret.cs @@ -29,7 +29,7 @@ public static string Interpret(Atom.MathList mathList, System.Func // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. From 4ec984c4832de62c9a11cd9551711055566a3a1a Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Thu, 28 May 2020 00:29:22 +0800 Subject: [PATCH 10/20] More range checking --- CSharpMath.Editor/Extensions/MathList.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index 8800b8be..42a234ec 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -9,7 +9,7 @@ namespace CSharpMath.Editor { partial class Extensions { static void InsertAtAtomIndexAndAdvance(this MathList self, int atomIndex, MathAtom atom, ref MathListIndex advance, MathListSubIndexType advanceType) { if (atomIndex < 0 || atomIndex > self.Count) - throw new IndexOutOfRangeException($"Index {atomIndex} is out of bounds for list of size {self.Atoms.Count}"); + throw new IndexOutOfRangeException($"Insertion index {atomIndex} is out of bounds for list of size {self.Atoms.Count}"); // Test for placeholder to the right of index, e.g. \sqrt{‸■} -> \sqrt{2‸} if (atomIndex < self.Count && self[atomIndex] is Atoms.Placeholder placeholder) { atom.Superscript.Append(placeholder.Superscript); @@ -25,8 +25,8 @@ static void InsertAtAtomIndexAndAdvance(this MathList self, int atomIndex, MathA /// Inserts and modifies to advance to the next position. public static void InsertAndAdvance(this MathList self, ref MathListIndex index, MathAtom atom, MathListSubIndexType advanceType) { index ??= MathListIndex.Level0Index(0); - if (index.AtomIndex > self.Atoms.Count) - throw new IndexOutOfRangeException($"Index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); + if (index.AtomIndex < 0 || index.AtomIndex > self.Atoms.Count) + throw new IndexOutOfRangeException($"Insertion index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); switch (index.SubIndexType) { case MathListSubIndexType.None: self.InsertAtAtomIndexAndAdvance(index.AtomIndex, atom, ref index, advanceType); @@ -125,8 +125,8 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip } else script.RemoveAt(ref index.SubIndex); } - if (index.AtomIndex > self.Atoms.Count) - throw new IndexOutOfRangeException($"Index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); + if (index.AtomIndex < -1 || index.AtomIndex >= self.Atoms.Count) + throw new IndexOutOfRangeException($"Deletion index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); switch (index.SubIndexType) { case MathListSubIndexType.None: if (index.AtomIndex == -1) { From f0182315cdef3c261753ba881ee3fe503357de3f Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Wed, 17 Jun 2020 09:44:01 +0100 Subject: [PATCH 11/20] Remove refs on MathListIndex inputs --- CSharpMath.Editor/Extensions/MathList.cs | 45 +++++++++++++----------- CSharpMath.Editor/MathKeyboard.cs | 2 +- CSharpMath.Editor/MathListIndex.cs | 6 ++++ 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index 42a234ec..ece1d4b4 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -82,13 +82,14 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, } } - public static void RemoveAt(this MathList self, ref MathListIndex index) { - void RemoveAtInnerList(ref MathListIndex index, TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer { + public static void RemoveAt(this MathList self, MathListIndex index) { + void RemoveAtInnerList(TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); if (index.IsBeforeSubList) { - index = index.LevelDown() - ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null"); - self.RemoveAt(ref index); + index.SetTo( + index.LevelDown() + ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null")); + self.RemoveAt(index); MathListIndex tempIndex = index; int i = 0; foreach (var innerList in atom.InnerLists) @@ -106,23 +107,24 @@ void RemoveAtInnerList(ref MathListIndex index, TAtom atom, int innerList self.InsertAndAdvance(ref tempIndex, LaTeXSettings.Placeholder, MathListSubIndexType.None); if(atom.Superscript.Count > 0) self[tempIndex.AtomIndex - 1].Superscript.Append(atom.Superscript); if(atom.Subscript.Count > 0) self[tempIndex.AtomIndex - 1].Subscript.Append(atom.Subscript); - } else atom.InnerLists.ElementAt(innerListIndex).RemoveAt(ref index.SubIndex); + } else atom.InnerLists.ElementAt(innerListIndex).RemoveAt(index.SubIndex); } void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscript) { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); var script = superscript ? atom.Superscript : atom.Subscript; if (index.IsBeforeSubList) { - index = index.LevelDown() - ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null"); + index.SetTo( + index.LevelDown() + ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null")); if (atom is Atoms.Placeholder && (superscript ? atom.Subscript : atom.Superscript).Count == 0) self.RemoveAt(index.AtomIndex); - else index = index.Next; + else index.SetTo(index.Next); var tempIndex = index; if (!(script.Count == 1 && script[0] is Atoms.Placeholder)) foreach (var inner in script) self.InsertAndAdvance(ref tempIndex, inner, MathListSubIndexType.None); script.Clear(); - } else script.RemoveAt(ref index.SubIndex); + } else script.RemoveAt(index.SubIndex); } if (index.AtomIndex < -1 || index.AtomIndex >= self.Atoms.Count) @@ -130,7 +132,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip switch (index.SubIndexType) { case MathListSubIndexType.None: if (index.AtomIndex == -1) { - index = index.Next; + index.SetTo(index.Next); if (self.Atoms[index.AtomIndex] is Atoms.Placeholder { Superscript: var super, Subscript: var sub }) { self.RemoveAt(index.AtomIndex); var tempIndex = index; @@ -169,9 +171,10 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip previous.Subscript.Append(currentAtom.Subscript); self.RemoveAt(index.AtomIndex); // it was in the nucleus and we removed it, get out of the nucleus and get in the nucleus of the previous one. - index = downIndex.Previous is MathListIndex downPrev + index.SetTo( + downIndex.Previous is MathListIndex downPrev ? downPrev.LevelUpWithSubIndex(MathListSubIndexType.BetweenBaseAndScripts, MathListIndex.Level0Index(1)) - : downIndex; + : downIndex); break; } // insert placeholder since we couldn't place the scripts in previous atom @@ -179,27 +182,27 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip insertionAtom.Subscript.Append(currentAtom.Subscript); insertionAtom.Superscript.Append(currentAtom.Superscript); self.RemoveAt(index.AtomIndex); - index = downIndex; + index.SetTo(downIndex); self.InsertAndAdvance(ref index, insertionAtom, MathListSubIndexType.None); - index = index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?"); + index.SetTo(index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?")); return; case MathListSubIndexType.Radicand: case MathListSubIndexType.Degree: if (!(self.Atoms[index.AtomIndex] is Atoms.Radical radical)) throw new SubIndexTypeMismatchException(typeof(Atoms.Radical), index); if (index.SubIndexType == MathListSubIndexType.Degree) - RemoveAtInnerList(ref index, radical, 0); + RemoveAtInnerList(radical, 0); else - RemoveAtInnerList(ref index, radical, 1); + RemoveAtInnerList(radical, 1); break; case MathListSubIndexType.Numerator: case MathListSubIndexType.Denominator: if (!(self.Atoms[index.AtomIndex] is Atoms.Fraction frac)) throw new SubIndexTypeMismatchException(typeof(Atoms.Fraction), index); if (index.SubIndexType == MathListSubIndexType.Numerator) - RemoveAtInnerList(ref index, frac, 0); + RemoveAtInnerList(frac, 0); else - RemoveAtInnerList(ref index, frac, 1); + RemoveAtInnerList(frac, 1); break; case MathListSubIndexType.Subscript: var current = self.Atoms[index.AtomIndex]; @@ -216,7 +219,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip case MathListSubIndexType.Inner: if (!(self.Atoms[index.AtomIndex] is Atoms.Inner inner)) throw new SubIndexTypeMismatchException(typeof(Atoms.Inner), index); - RemoveAtInnerList(ref index, inner, 0); + RemoveAtInnerList(inner, 0); break; default: throw new SubIndexTypeMismatchException(index); @@ -225,7 +228,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip // We have deleted to the beginning of the line and it is not the outermost line if (self.AtomAt(index) is null) { self.InsertAndAdvance(ref index, LaTeXSettings.Placeholder, MathListSubIndexType.None); - index = index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?"); + index.SetTo(index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?")); } } } diff --git a/CSharpMath.Editor/MathKeyboard.cs b/CSharpMath.Editor/MathKeyboard.cs index 3c6fd48f..7592ff68 100644 --- a/CSharpMath.Editor/MathKeyboard.cs +++ b/CSharpMath.Editor/MathKeyboard.cs @@ -391,7 +391,7 @@ void DeleteBackwards() { // delete the last atom from the list if (HasText && _insertionIndex.PreviousOrBeforeWholeList is MathListIndex previous) { _insertionIndex = previous; - MathList.RemoveAt(ref _insertionIndex); + MathList.RemoveAt(_insertionIndex); } } diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index 4c6977b5..1b261ae4 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -43,8 +43,14 @@ private MathListIndex() { } public int AtomIndex { get; set; } ///The type of subindex, e.g. superscript, numerator etc. public MathListSubIndexType SubIndexType { get; set; } + ///The index into the sublist. public MathListIndex? SubIndex; + public void SetTo(MathListIndex replacement) { + AtomIndex = replacement.AtomIndex; + SubIndexType = replacement.SubIndexType; + SubIndex = replacement.SubIndex; + } /** Factory function to create a `MathListIndex` with no subindexes. The index of the atom that the `MathListIndex` points at. From 85427c6e59d6c563bf0168e2ec59b0797de0b359 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Wed, 17 Jun 2020 10:27:10 +0100 Subject: [PATCH 12/20] Move IsBeforeSubList and PreviousOrBeforeWholeList to prevent usage in wrong places --- CSharpMath.Editor/Extensions/MathList.cs | 20 +++++++++++++++++--- CSharpMath.Editor/MathKeyboard.cs | 2 +- CSharpMath.Editor/MathListIndex.cs | 8 -------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index ece1d4b4..e0c7467b 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -81,11 +81,25 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, throw new SubIndexTypeMismatchException(index); } } - + public static MathListIndex? PreviousOrBeforeWholeList(MathListIndex index) { + return + index.SubIndexType switch + { + MathListSubIndexType.None => index.AtomIndex > -1 ? MathListIndex.Level0Index(index.AtomIndex - 1) : null, + _ => + (index.SubIndex == null) ? null : + PreviousOrBeforeWholeList(index.SubIndex) is MathListIndex prevSubIndex + ? MathListIndex.IndexAtLocation(index.AtomIndex, index.SubIndexType, prevSubIndex) : null, + }; + } public static void RemoveAt(this MathList self, MathListIndex index) { + static bool IsBeforeSubList(MathListIndex index) { + return (index.SubIndex != null && index.SubIndex.AtomIndex == -1) && index.SubIndexType == MathListSubIndexType.None; + } + void RemoveAtInnerList(TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); - if (index.IsBeforeSubList) { + if (IsBeforeSubList(index)) { index.SetTo( index.LevelDown() ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null")); @@ -112,7 +126,7 @@ void RemoveAtInnerList(TAtom atom, int innerListIndex) where TAtom : Math void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscript) { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); var script = superscript ? atom.Superscript : atom.Subscript; - if (index.IsBeforeSubList) { + if (IsBeforeSubList(index)) { index.SetTo( index.LevelDown() ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null")); diff --git a/CSharpMath.Editor/MathKeyboard.cs b/CSharpMath.Editor/MathKeyboard.cs index 7592ff68..4e89024b 100644 --- a/CSharpMath.Editor/MathKeyboard.cs +++ b/CSharpMath.Editor/MathKeyboard.cs @@ -389,7 +389,7 @@ void MoveCursorRight() { void DeleteBackwards() { // delete the last atom from the list - if (HasText && _insertionIndex.PreviousOrBeforeWholeList is MathListIndex previous) { + if (HasText && (Extensions.PreviousOrBeforeWholeList(_insertionIndex)) is MathListIndex previous) { _insertionIndex = previous; MathList.RemoveAt(_insertionIndex); } diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index 1b261ae4..aec529b1 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -86,14 +86,6 @@ public MathListIndex LevelUpWithSubIndex(MathListSubIndexType type, MathListInde MathListSubIndexType.None => AtomIndex > 0 ? Level0Index(AtomIndex - 1) : null, _ => SubIndex?.Previous is MathListIndex prevSubIndex ? IndexAtLocation(AtomIndex, SubIndexType, prevSubIndex) : null, }; - /// Should be used inside only! - internal bool IsBeforeSubList => SubIndex is { AtomIndex: -1, SubIndexType: MathListSubIndexType.None }; - /// Valid for only! - internal MathListIndex? PreviousOrBeforeWholeList => SubIndexType switch - { - MathListSubIndexType.None => AtomIndex > -1 ? Level0Index(AtomIndex - 1) : null, - _ => SubIndex?.PreviousOrBeforeWholeList is MathListIndex prevSubIndex ? IndexAtLocation(AtomIndex, SubIndexType, prevSubIndex) : null, - }; ///Returns the next index. public MathListIndex Next => SubIndexType switch From 4858a6822fdaff149db8f9027c7692aea5e7b020 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Wed, 17 Jun 2020 10:30:33 +0100 Subject: [PATCH 13/20] Rename SetTo to ReplaceWith --- CSharpMath.Editor/Extensions/MathList.cs | 16 ++++++++-------- CSharpMath.Editor/MathListIndex.cs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index e0c7467b..a339de00 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -100,7 +100,7 @@ static bool IsBeforeSubList(MathListIndex index) { void RemoveAtInnerList(TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); if (IsBeforeSubList(index)) { - index.SetTo( + index.ReplaceWith( index.LevelDown() ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null")); self.RemoveAt(index); @@ -127,12 +127,12 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); var script = superscript ? atom.Superscript : atom.Subscript; if (IsBeforeSubList(index)) { - index.SetTo( + index.ReplaceWith( index.LevelDown() ?? throw new InvalidCodePathException($"{nameof(index.SubIndex)} is not null but {nameof(index.LevelDown)} is null")); if (atom is Atoms.Placeholder && (superscript ? atom.Subscript : atom.Superscript).Count == 0) self.RemoveAt(index.AtomIndex); - else index.SetTo(index.Next); + else index.ReplaceWith(index.Next); var tempIndex = index; if (!(script.Count == 1 && script[0] is Atoms.Placeholder)) foreach (var inner in script) @@ -146,7 +146,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip switch (index.SubIndexType) { case MathListSubIndexType.None: if (index.AtomIndex == -1) { - index.SetTo(index.Next); + index.ReplaceWith(index.Next); if (self.Atoms[index.AtomIndex] is Atoms.Placeholder { Superscript: var super, Subscript: var sub }) { self.RemoveAt(index.AtomIndex); var tempIndex = index; @@ -185,7 +185,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip previous.Subscript.Append(currentAtom.Subscript); self.RemoveAt(index.AtomIndex); // it was in the nucleus and we removed it, get out of the nucleus and get in the nucleus of the previous one. - index.SetTo( + index.ReplaceWith( downIndex.Previous is MathListIndex downPrev ? downPrev.LevelUpWithSubIndex(MathListSubIndexType.BetweenBaseAndScripts, MathListIndex.Level0Index(1)) : downIndex); @@ -196,9 +196,9 @@ downIndex.Previous is MathListIndex downPrev insertionAtom.Subscript.Append(currentAtom.Subscript); insertionAtom.Superscript.Append(currentAtom.Superscript); self.RemoveAt(index.AtomIndex); - index.SetTo(downIndex); + index.ReplaceWith(downIndex); self.InsertAndAdvance(ref index, insertionAtom, MathListSubIndexType.None); - index.SetTo(index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?")); + index.ReplaceWith(index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?")); return; case MathListSubIndexType.Radicand: case MathListSubIndexType.Degree: @@ -242,7 +242,7 @@ downIndex.Previous is MathListIndex downPrev // We have deleted to the beginning of the line and it is not the outermost line if (self.AtomAt(index) is null) { self.InsertAndAdvance(ref index, LaTeXSettings.Placeholder, MathListSubIndexType.None); - index.SetTo(index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?")); + index.ReplaceWith(index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?")); } } } diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index aec529b1..575fcf92 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -46,7 +46,7 @@ private MathListIndex() { } ///The index into the sublist. public MathListIndex? SubIndex; - public void SetTo(MathListIndex replacement) { + public void ReplaceWith(MathListIndex replacement) { AtomIndex = replacement.AtomIndex; SubIndexType = replacement.SubIndexType; SubIndex = replacement.SubIndex; From 624ce670c416b6172196eee9bb773d64a59158a4 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Thu, 25 Jun 2020 07:36:17 +0100 Subject: [PATCH 14/20] Accepted simplification recommendations --- CSharpMath.Editor/MathListIndex.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index 575fcf92..92347cd7 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -97,18 +97,15 @@ public MathListIndex LevelUpWithSubIndex(MathListSubIndexType type, MathListInde ///Returns true if any of the subIndexes of this index have the given type. public bool HasSubIndexOfType(MathListSubIndexType subIndexType) => - SubIndexType == subIndexType ? true : - SubIndex != null ? SubIndex.HasSubIndexOfType(subIndexType) : false; + SubIndexType == subIndexType || (SubIndex != null && SubIndex.HasSubIndexOfType(subIndexType)); public bool AtSameLevel(MathListIndex other) => - SubIndexType != other.SubIndexType ? false : + SubIndexType == other.SubIndexType && // No subindexes, they are at the same level. - SubIndexType == MathListSubIndexType.None ? true : + (SubIndexType == MathListSubIndexType.None || // the subindexes are used in different atoms - AtomIndex != other.AtomIndex ? false : - SubIndex != null && other.SubIndex != null ? SubIndex.AtSameLevel(other.SubIndex) : - // No subindexes, they are at the same level. - true; + (AtomIndex == other.AtomIndex && + (SubIndex == null || other.SubIndex == null || SubIndex.AtSameLevel(other.SubIndex)))); public int FinalIndex => SubIndexType is MathListSubIndexType.None || SubIndex is null ? AtomIndex : SubIndex.FinalIndex; @@ -126,9 +123,9 @@ SubIndex is null ? $@"[{AtomIndex}, {SubIndexType}:{SubIndex.ToString().Trim('[', ']')}]"; public bool EqualsToIndex(MathListIndex index) => - index is null || AtomIndex != index.AtomIndex || SubIndexType != index.SubIndexType ? false : - SubIndex != null && index.SubIndex != null ? SubIndex.EqualsToIndex(index.SubIndex) : - index.SubIndex == null; + !(index is null) && AtomIndex == index.AtomIndex && SubIndexType == index.SubIndexType && + (SubIndex != null && index.SubIndex != null ? SubIndex.EqualsToIndex(index.SubIndex) : + index.SubIndex == null); public override bool Equals(object obj) => obj is MathListIndex index && EqualsToIndex(index); From 4d2b72aeb95b8dca9b3b0789023e3e65371d569c Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Tue, 11 Aug 2020 00:52:27 +0100 Subject: [PATCH 15/20] tweak wording --- CSharpMath.Editor/MathListIndex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSharpMath.Editor/MathListIndex.cs b/CSharpMath.Editor/MathListIndex.cs index 92347cd7..3eb0b896 100644 --- a/CSharpMath.Editor/MathListIndex.cs +++ b/CSharpMath.Editor/MathListIndex.cs @@ -22,7 +22,7 @@ public enum MathListSubIndexType : byte { } /** -* An index that points to a particular character in the MathList. The index is a LinkedList that represents +* An index that points to a particular atom in the MathList. The index is a LinkedList that represents * a path from the beginning of the MathList to reach a particular atom in the list. The next node of the path * is represented by the subIndex. The path terminates when the subIndex is nil. * From c8675a1a93278abee37e6a05143acf70b998bd77 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Tue, 11 Aug 2020 01:01:00 +0100 Subject: [PATCH 16/20] remove unnecessary null checks --- CSharpMath/Atom/Atoms/Accent.cs | 4 ++-- CSharpMath/Atom/Atoms/Fraction.cs | 4 ++-- CSharpMath/Atom/Atoms/Inner.cs | 8 ++++---- CSharpMath/Atom/Atoms/Overline.cs | 4 ++-- CSharpMath/Atom/Atoms/RaiseBox.cs | 4 ++-- CSharpMath/Atom/IMathObject.cs | 8 -------- CSharpMath/Atom/MathAtom.cs | 4 ++-- CSharpMath/Atom/MathList.cs | 11 +++-------- 8 files changed, 17 insertions(+), 30 deletions(-) diff --git a/CSharpMath/Atom/Atoms/Accent.cs b/CSharpMath/Atom/Atoms/Accent.cs index 95735aac..6a5b5600 100644 --- a/CSharpMath/Atom/Atoms/Accent.cs +++ b/CSharpMath/Atom/Atoms/Accent.cs @@ -18,8 +18,8 @@ protected override MathAtom CloneInside(bool finalize) => new Accent(Nucleus, InnerList.Clone(finalize)); public override bool ScriptsAllowed => true; public bool EqualsAccent(Accent other) => - EqualsAtom(other) && InnerList.NullCheckingStructuralEquality(other?.InnerList); - public override bool Equals(object obj) => obj is Accent a ? EqualsAccent(a) : false; + EqualsAtom(other) && InnerList.Equals(other.InnerList); + public override bool Equals(object obj) => obj is Accent a && EqualsAccent(a); public override int GetHashCode() => (base.GetHashCode(), InnerList).GetHashCode(); } } \ No newline at end of file diff --git a/CSharpMath/Atom/Atoms/Fraction.cs b/CSharpMath/Atom/Atoms/Fraction.cs index 2a28d515..a7371d7a 100644 --- a/CSharpMath/Atom/Atoms/Fraction.cs +++ b/CSharpMath/Atom/Atoms/Fraction.cs @@ -29,8 +29,8 @@ protected override MathAtom CloneInside(bool finalize) => public override bool Equals(object obj) => obj is Fraction f && EqualsFraction(f); public bool EqualsFraction(Fraction other) => EqualsAtom(other) - && Numerator.NullCheckingStructuralEquality(other.Numerator) - && Denominator.NullCheckingStructuralEquality(other.Denominator) + && Numerator.Equals(other.Numerator) + && Denominator.Equals(other.Denominator) && LeftDelimiter == other.LeftDelimiter && RightDelimiter == other.RightDelimiter; public override int GetHashCode() => diff --git a/CSharpMath/Atom/Atoms/Inner.cs b/CSharpMath/Atom/Atoms/Inner.cs index 05026ebd..56bcca51 100644 --- a/CSharpMath/Atom/Atoms/Inner.cs +++ b/CSharpMath/Atom/Atoms/Inner.cs @@ -16,10 +16,10 @@ protected override MathAtom CloneInside(bool finalize) => new Inner(LeftBoundary, InnerList.Clone(finalize), RightBoundary); public bool EqualsInner(Inner otherInner) => EqualsAtom(otherInner) - && InnerList.NullCheckingStructuralEquality(otherInner.InnerList) - && LeftBoundary.NullCheckingStructuralEquality(otherInner.LeftBoundary) - && RightBoundary.NullCheckingStructuralEquality(otherInner.RightBoundary); - public override bool Equals(object obj) => obj is Inner i ? EqualsInner(i) : false; + && InnerList.Equals(otherInner.InnerList) + && LeftBoundary.Equals(otherInner.LeftBoundary) + && RightBoundary.Equals(otherInner.RightBoundary); + public override bool Equals(object obj) => obj is Inner i && EqualsInner(i); public override int GetHashCode() => (base.GetHashCode(), InnerList, LeftBoundary, RightBoundary).GetHashCode(); public override string DebugString => diff --git a/CSharpMath/Atom/Atoms/Overline.cs b/CSharpMath/Atom/Atoms/Overline.cs index de7c7f67..65152fe3 100644 --- a/CSharpMath/Atom/Atoms/Overline.cs +++ b/CSharpMath/Atom/Atoms/Overline.cs @@ -16,8 +16,8 @@ protected override MathAtom CloneInside(bool finalize) => .AppendInBracesOrLiteralNull(InnerList?.DebugString) .ToString(); public bool EqualsOverline(Overline other) => - EqualsAtom(other) && InnerList.NullCheckingStructuralEquality(other?.InnerList); - public override bool Equals(object obj) => obj is Overline o ? EqualsOverline(o) : false; + EqualsAtom(other) && InnerList.Equals(other.InnerList); + public override bool Equals(object obj) => obj is Overline o && EqualsOverline(o); public override int GetHashCode() => (base.GetHashCode(), InnerList).GetHashCode(); } diff --git a/CSharpMath/Atom/Atoms/RaiseBox.cs b/CSharpMath/Atom/Atoms/RaiseBox.cs index 2c839516..5f3e5cd4 100644 --- a/CSharpMath/Atom/Atoms/RaiseBox.cs +++ b/CSharpMath/Atom/Atoms/RaiseBox.cs @@ -13,7 +13,7 @@ protected override MathAtom CloneInside(bool finalize) => public override int GetHashCode() => (base.GetHashCode(), Raise, InnerList).GetHashCode(); public override bool Equals(object obj) => - obj is RaiseBox r ? EqualsAtom(r) && Raise == r.Raise - && InnerList.NullCheckingStructuralEquality(r.InnerList) : false; + obj is RaiseBox r && EqualsAtom(r) && Raise == r.Raise + && InnerList.Equals(r.InnerList); } } \ No newline at end of file diff --git a/CSharpMath/Atom/IMathObject.cs b/CSharpMath/Atom/IMathObject.cs index 217ec576..d5ef2ef8 100644 --- a/CSharpMath/Atom/IMathObject.cs +++ b/CSharpMath/Atom/IMathObject.cs @@ -6,12 +6,4 @@ public interface IMathObject { public interface IMathListContainer : IMathObject { System.Collections.Generic.IEnumerable InnerLists { get; } } -} -namespace CSharpMath { - using Atom; - partial class Extensions { - /// Safe to call, even if one or both are null. Returns true if both are null. - public static bool NullCheckingStructuralEquality(this IMathObject? obj1, IMathObject? obj2) => - obj1 == null ? obj2 == null : obj2 == null ? false : obj1.Equals(obj2); - } } \ No newline at end of file diff --git a/CSharpMath/Atom/MathAtom.cs b/CSharpMath/Atom/MathAtom.cs index 9426bac5..b9db6ec1 100644 --- a/CSharpMath/Atom/MathAtom.cs +++ b/CSharpMath/Atom/MathAtom.cs @@ -85,8 +85,8 @@ public bool EqualsAtom(MathAtom otherAtom) => GetType() == otherAtom.GetType() && //IndexRange == otherAtom.IndexRange && //FontStyle == otherAtom.FontStyle && - Superscript.NullCheckingStructuralEquality(otherAtom.Superscript) && - Subscript.NullCheckingStructuralEquality(otherAtom.Subscript); + Superscript.Equals(otherAtom.Superscript) && + Subscript.Equals(otherAtom.Subscript); public override bool Equals(object obj) => obj is MathAtom a && EqualsAtom(a); bool IEquatable.Equals(MathAtom otherAtom) => EqualsAtom(otherAtom); public override int GetHashCode() => (Superscript, Subscript, Nucleus).GetHashCode(); diff --git a/CSharpMath/Atom/MathList.cs b/CSharpMath/Atom/MathList.cs index 802d1777..9fa3aab6 100644 --- a/CSharpMath/Atom/MathList.cs +++ b/CSharpMath/Atom/MathList.cs @@ -111,14 +111,11 @@ public MathList Clone(bool finalize) { public virtual void Append(IEnumerable list) => Atoms.AddRange(list); public void RemoveAtoms(int index, int count) => Atoms.RemoveRange(index, count); public bool EqualsList(MathList otherList) { - if (otherList == null) { - return false; - } if (otherList.Count != Count) { return false; } for (int i = 0; i < Count; i++) { - if (!this[i].NullCheckingStructuralEquality(otherList[i])) { + if (!this[i].Equals(otherList[i])) { return false; } } @@ -132,13 +129,11 @@ public override int GetHashCode() => IEnumerator IEnumerable.GetEnumerator() => Atoms.GetEnumerator(); public int IndexOf(MathAtom item) => Atoms.IndexOf(item); public void Insert(int index, MathAtom item) { - if (item != null) Atoms.Insert(index, item); - else throw new ArgumentNullException(nameof(item), "MathList cannot contain null."); + Atoms.Insert(index, item); } public void RemoveAt(int index) => Atoms.RemoveAt(index); public virtual void Add(MathAtom item) { - if (item != null) Atoms.Add(item); - else throw new ArgumentNullException(nameof(item), "MathList cannot contain null."); + Atoms.Add(item); } public void Clear() => Atoms.Clear(); public bool Contains(MathAtom item) => Atoms.Contains(item); From ac0172115d380106907f188acad239de32e781f6 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Tue, 11 Aug 2020 01:15:23 +0100 Subject: [PATCH 17/20] add documentation TODOs --- CSharpMath.Editor/Extensions/MathList.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index a339de00..ca565420 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -7,6 +7,7 @@ namespace CSharpMath.Editor { using System.Linq; partial class Extensions { + // TODO: document this function. The name sounds is reasonable but the inputs are not transparent. static void InsertAtAtomIndexAndAdvance(this MathList self, int atomIndex, MathAtom atom, ref MathListIndex advance, MathListSubIndexType advanceType) { if (atomIndex < 0 || atomIndex > self.Count) throw new IndexOutOfRangeException($"Insertion index {atomIndex} is out of bounds for list of size {self.Atoms.Count}"); @@ -81,6 +82,7 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, throw new SubIndexTypeMismatchException(index); } } + // TODO document this function public static MathListIndex? PreviousOrBeforeWholeList(MathListIndex index) { return index.SubIndexType switch @@ -94,6 +96,7 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, } public static void RemoveAt(this MathList self, MathListIndex index) { static bool IsBeforeSubList(MathListIndex index) { + // TODO: remove the index.SubIndex.AtomIndex == -1 condition as this is not valid return (index.SubIndex != null && index.SubIndex.AtomIndex == -1) && index.SubIndexType == MathListSubIndexType.None; } From 5b1ad8e1d0f63e3ccabba41fdd92634f3950ab76 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Tue, 11 Aug 2020 01:22:12 +0100 Subject: [PATCH 18/20] Add TODOs --- CSharpMath.Editor/Extensions/MathList.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index ca565420..5de9ab6c 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -95,11 +95,15 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, }; } public static void RemoveAt(this MathList self, MathListIndex index) { + // TODO: document this function static bool IsBeforeSubList(MathListIndex index) { // TODO: remove the index.SubIndex.AtomIndex == -1 condition as this is not valid return (index.SubIndex != null && index.SubIndex.AtomIndex == -1) && index.SubIndexType == MathListSubIndexType.None; } - + // TODO: document this function + // From github conv so far: + // "atom is a MathAtom directly contained in self that contains(index.SubIndex.AtomIndex > -1) + // is(index.SubIndex.AtomIndex = -1) the atom to remove." void RemoveAtInnerList(TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); if (IsBeforeSubList(index)) { @@ -126,6 +130,7 @@ void RemoveAtInnerList(TAtom atom, int innerListIndex) where TAtom : Math if(atom.Subscript.Count > 0) self[tempIndex.AtomIndex - 1].Subscript.Append(atom.Subscript); } else atom.InnerLists.ElementAt(innerListIndex).RemoveAt(index.SubIndex); } + // TODO: document this function void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscript) { if (index.SubIndex is null) throw new InvalidCodePathException($"{nameof(index.SubIndex)} should exist"); var script = superscript ? atom.Superscript : atom.Subscript; @@ -148,6 +153,7 @@ void RemoveAtInnerScript(ref MathListIndex index, MathAtom atom, bool superscrip throw new IndexOutOfRangeException($"Deletion index {index.AtomIndex} is out of bounds for list of size {self.Atoms.Count}"); switch (index.SubIndexType) { case MathListSubIndexType.None: + // TODO: remove the index.SubIndex.AtomIndex == -1 condition as this is not valid if (index.AtomIndex == -1) { index.ReplaceWith(index.Next); if (self.Atoms[index.AtomIndex] is Atoms.Placeholder { Superscript: var super, Subscript: var sub }) { From 9e91a94c092da564d8acbdb36aedda85838e52fd Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Tue, 11 Aug 2020 01:32:19 +0100 Subject: [PATCH 19/20] failing test is unnecessary --- CSharpMath.CoreTests/MathListTest.cs | 6 ------ CSharpMath.Editor/Extensions/MathList.cs | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/CSharpMath.CoreTests/MathListTest.cs b/CSharpMath.CoreTests/MathListTest.cs index bfbb81df..3c4fe9ac 100644 --- a/CSharpMath.CoreTests/MathListTest.cs +++ b/CSharpMath.CoreTests/MathListTest.cs @@ -30,12 +30,6 @@ public void TestAdd() { Assert.Equal(atom2, list[1]); } - [Fact] - public void TestAddErrors() { - var list = new MathList(); - Assert.Throws(() => list.Add(null!)); - } - [Fact] public void TestInsert() { var list = new MathList(); diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index 5de9ab6c..0f601340 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -87,6 +87,7 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, return index.SubIndexType switch { + // TODO: remove the index.SubIndex.AtomIndex == -1 possibility as this is not valid MathListSubIndexType.None => index.AtomIndex > -1 ? MathListIndex.Level0Index(index.AtomIndex - 1) : null, _ => (index.SubIndex == null) ? null : From 5a764bbb244a7d7cf2dd209fbb76c410ed7de6c0 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Tue, 11 Aug 2020 01:33:29 +0100 Subject: [PATCH 20/20] add TODO --- CSharpMath.Editor/Extensions/MathList.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CSharpMath.Editor/Extensions/MathList.cs b/CSharpMath.Editor/Extensions/MathList.cs index 0f601340..dd5ea9e0 100644 --- a/CSharpMath.Editor/Extensions/MathList.cs +++ b/CSharpMath.Editor/Extensions/MathList.cs @@ -95,6 +95,7 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index, ? MathListIndex.IndexAtLocation(index.AtomIndex, index.SubIndexType, prevSubIndex) : null, }; } + // TODO: document this function public static void RemoveAt(this MathList self, MathListIndex index) { // TODO: document this function static bool IsBeforeSubList(MathListIndex index) {