Example #1
0
        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}");
            }
            switch (index.SubIndexType)
            {
            case MathListSubIndexType.None:
                self.RemoveAt(index.AtomIndex);
                break;

            case var _ when index.SubIndex is null:
                throw new InvalidCodePathException("index.SubIndex is null despite non-None subindex type");

            case MathListSubIndexType.BetweenBaseAndScripts:
                var currentAtom = self.Atoms[index.AtomIndex];
                if (currentAtom.Subscript.IsEmpty() && currentAtom.Superscript.IsEmpty())
                {
                    throw new SubIndexTypeMismatchException(index);
                }
                var downIndex = index.LevelDown();
                if (downIndex is null)
                {
                    throw new InvalidCodePathException("downIndex is null");
                }
                if (index.AtomIndex > 0 &&
                    self.Atoms[index.AtomIndex - 1] is MathAtom previous &&
                    previous.Subscript.IsEmpty() &&
                    previous.Superscript.IsEmpty() &&
                    previous switch
                {
                    Atoms.BinaryOperator _ => false,
                    Atoms.UnaryOperator _ => false,
                    Atoms.Relation _ => false,
                    Atoms.Punctuation _ => false,
                    Atoms.Space _ => false,
                    _ => true
                })
                {
                    previous.Superscript.Append(currentAtom.Superscript);
                    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
              ? downPrev.LevelUpWithSubIndex(MathListSubIndexType.BetweenBaseAndScripts, MathListIndex.Level0Index(1))
              : downIndex;

                    break;
                }
                // insert placeholder since we couldn't place the scripts in previous atom
                var insertionAtom = LaTeXSettings.Placeholder;
                insertionAtom.Subscript.Append(currentAtom.Subscript);
                insertionAtom.Superscript.Append(currentAtom.Superscript);
                self.RemoveAt(index.AtomIndex);
                index = downIndex;
                self.InsertAndAdvance(ref index, insertionAtom, MathListSubIndexType.None);
                index = index.Previous ?? throw new InvalidCodePathException("Cannot go back after insertion?");
                return;
Example #2
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}");
            }
            switch (index.SubIndexType)
            {
            case MathListSubIndexType.None:
                self.InsertAtAtomIndexAndAdvance(index.AtomIndex, atom, ref index, advanceType);
                break;

            case var _ when index.SubIndex is null:
                throw new InvalidCodePathException("index.SubIndex is null despite non-None subindex type");

            case MathListSubIndexType.BetweenBaseAndScripts:
                var currentAtom = self.Atoms[index.AtomIndex];
                if (currentAtom.Subscript.IsEmpty() && currentAtom.Superscript.IsEmpty())
                {
                    throw new SubIndexTypeMismatchException(index);
                }
                if (atom.Subscript.IsNonEmpty() || atom.Superscript.IsNonEmpty())
                {
                    throw new ArgumentException("Cannot fuse with an atom that already has a subscript or a superscript");
                }
                atom.Subscript.Append(currentAtom.Subscript);
                atom.Superscript.Append(currentAtom.Superscript);
                currentAtom.Subscript.Clear();
                currentAtom.Superscript.Clear();
                var atomIndex = index.AtomIndex;
                // Prevent further subindexing inside BetweenBaseAndScripts
                if (advanceType != MathListSubIndexType.None &&
                    index.LevelDown() is MathListIndex levelDown)
                {
                    index = levelDown.Next;
                }
                self.InsertAtAtomIndexAndAdvance(atomIndex + 1, atom, ref index, advanceType);
                break;

            case MathListSubIndexType.Degree:
            case MathListSubIndexType.Radicand:
                if (!(self.Atoms[index.AtomIndex] is Atoms.Radical radical))
                {
                    throw new SubIndexTypeMismatchException(typeof(Atoms.Radical), index);
                }
                if (index.SubIndexType == MathListSubIndexType.Degree)
                {
                    radical.Degree.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                }
                else
                {
                    radical.Radicand.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                }
                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.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                }
                else
                {
                    frac.Denominator.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                }
                break;

            case MathListSubIndexType.Subscript:
                self.Atoms[index.AtomIndex].Subscript.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                break;

            case MathListSubIndexType.Superscript:
                self.Atoms[index.AtomIndex].Superscript.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                break;

            case MathListSubIndexType.Inner:
                if (!(self.Atoms[index.AtomIndex] is Atoms.Inner inner))
                {
                    throw new SubIndexTypeMismatchException(typeof(Atoms.Inner), index);
                }
                inner.InnerList.InsertAndAdvance(ref index.SubIndex, atom, advanceType);
                break;

            default:
                throw new SubIndexTypeMismatchException(index);
            }
        }