Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation by up/down arrows #124

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 200 additions & 9 deletions CSharpMath.Editor.Tests/KeyPressTests.cs

Large diffs are not rendered by default.

112 changes: 90 additions & 22 deletions CSharpMath.Editor/Extensions/MathList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,39 @@ 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)
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);
atom.Subscript.Append(placeholder.Subscript);
self[atomIndex] = atom;
} else self.Insert(atomIndex, atom);
advance = advanceType switch
{
MathListSubIndexType.None => advance.Next,
_ => advance.LevelUpWithSubIndex(advanceType, MathListIndex.Level0Index(0)),
};
advance = advanceType switch
{
MathListSubIndexType.None =>
atom.Superscript.IsEmpty() && atom.Subscript.IsEmpty()
? advance.Next
: advance.LevelUpWithSubIndex(MathListSubIndexType.BetweenBaseAndScripts, MathListIndex.Level0Index(1)),
_ => advance.LevelUpWithSubIndex(advanceType, MathListIndex.Level0Index(0)),
};
} else {
self.Insert(atomIndex, atom);
advance = advanceType switch
{
MathListSubIndexType.None => advance.Next,
_ => advance.LevelUpWithSubIndex(advanceType, MathListIndex.Level0Index(0)),
};
}
}
/// <summary>Inserts <paramref name="atom"/> and modifies <paramref name="index"/> to advance to the next position.</summary>
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);
Expand Down Expand Up @@ -81,12 +93,66 @@ public static void InsertAndAdvance(this MathList self, ref MathListIndex index,
}

public static void RemoveAt(this MathList self, ref MathListIndex index) {
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}");
void RemoveAtInnerList<TAtom>(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");
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 (!(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);
}

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:
self.RemoveAt(index.AtomIndex);
if (index.AtomIndex == -1) {
index = index.Next;
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;
case var _ when index.SubIndex is null:
throw new InvalidCodePathException("index.SubIndex is null despite non-None subindex type");
Expand Down Expand Up @@ -132,33 +198,35 @@ 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))
throw new SubIndexTypeMismatchException(typeof(Atoms.Inner), index);
inner.InnerList.RemoveAt(ref index.SubIndex);
RemoveAtInnerList(ref index, inner, 0);
break;
default:
throw new SubIndexTypeMismatchException(index);
Expand All @@ -167,7 +235,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?");
}
}
}
Expand Down Expand Up @@ -218,7 +286,7 @@ public static void RemoveAtoms(this MathList self, MathListRange? nullableRange)
}

public static MathAtom? AtomAt(this MathList self, MathListIndex? index) {
if (index is null || index.AtomIndex >= self.Atoms.Count) return null;
if (index is null || index.AtomIndex < 0 || index.AtomIndex >= self.Atoms.Count) return null;
var atom = self.Atoms[index.AtomIndex];
switch (index.SubIndexType) {
case MathListSubIndexType.None:
Expand Down
Loading