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

Delete when in a placeholder should simplify containing expression #117

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from

Conversation

Happypig375
Copy link
Collaborator

Implements #108

@charlesroddie
Copy link
Collaborator

Great. Will review on Mon.

@charlesroddie
Copy link
Collaborator

Functionality seems good from my testing.

@@ -81,12 +83,66 @@ partial class Extensions {
}

public static void RemoveAt(this MathList self, ref MathListIndex index) {
index ??= MathListIndex.Level0Index(0);
void RemoveAtInnerList<TAtom>(ref MathListIndex index, TAtom atom, int innerListIndex) where TAtom : MathAtom, IMathListContainer {
Copy link
Collaborator

@charlesroddie charlesroddie May 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you document this a bit? It's not clear from the name of the function and inputs:

  • Is atom an Atom that resides at index?
  • Is atom the thing to be removed, or is instead a subatom of atom residing at innerListIndex within atom?

Copy link
Collaborator Author

@Happypig375 Happypig375 May 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

atom is a MathAtom directly contained in self that contains(index.SubIndex.AtomIndex > -1)/is(index.SubIndex.AtomIndex = -1) the atom to remove.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK that takes us closer. What would be the right type for AtomIndex to have? Nullable<int>?

Copy link
Collaborator Author

@Happypig375 Happypig375 May 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An AtomIndex of -1 indicates deletion at the beginning of line (not pointing to any atom). It is not a valid value for other methods accepting MathListIndex, which is why PreviousOrBeforeWholeList is internal.

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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this function

@Happypig375
Copy link
Collaborator Author

@charlesroddie What is the status of this?

@charlesroddie
Copy link
Collaborator

charlesroddie commented Jun 17, 2020

Main issue is the -1s. I've started doing a bit of cleaning to try to understand this. Removed some refs which allow removing a duplicate "index" input. (Before there were two indexes which were supposed to be the same.) Also moved IsBeforeSubList and PreviousOrBeforeWholeList to prevent usage in the wrong places. It will take more thinking and cleaning to be sure what to do about the -1s.

Options: 1. keep the current hack, 2. adjust the docs on MathListIndex to allow it to be either the current "points to a particular character in the MathList" or "a sublist in a MathList", 3. avoid using MathListIndex for deletes. I haven't understood the code well enough to decide on this.

@Happypig375
Copy link
Collaborator Author

Does it make sense for a data structure to have a Replace method?

@@ -81,11 +81,25 @@ partial class Extensions {
throw new SubIndexTypeMismatchException(index);
}
}

public static MathListIndex? PreviousOrBeforeWholeList(MathListIndex index) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an extension method?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps. I tried to move it inside the Delete method because the xml comment said "only use from Delete..." but it also needed to be used in DeleteBackwards in MathKeyboard.

@charlesroddie
Copy link
Collaborator

Does it make sense for a data structure to have a Replace method?

The items are settable anyway so the Replace method isn't doing anything that can't be done without it. I think it's better for clarity than having the ref inputs. Although immutable will be better still :).

@Happypig375
Copy link
Collaborator Author

The items are settable anyway so the Replace method isn't doing anything that can't be done without it. I think it's better for clarity than having the ref inputs. Although immutable will be better still :).

With ref, I can easily make a "copy" by assigning the value to a new variable. Now a new Copy method is required. With immutability, even more parameters will need to be passed around as each operation will produce a new MathListIndex.

@Happypig375
Copy link
Collaborator Author

@charlesroddie What now?

@charlesroddie
Copy link
Collaborator

charlesroddie commented Jun 24, 2020

Currently MathListIndex is well documented. We can't disobey its definition.

The code in MathList.cs I haven't been able to understand from the names and type signatures. So I wouldn't be able to make a start documenting it. To get this mergeable we'll need to document the functions in MathList.cs and make the usage of MathListIndex compatible with its definition. I'm not sure which of these two is the best place is to begin.

I'm happy to take a call on Sat UK morning to look at this code.

Do you think we should change MathListIndex to point to any atom in a MathList, rather than just a character at a leaf of the MathList? Or does another type need to be created for this purpose?

@charlesroddie
Copy link
Collaborator

Let's separate the behaviour from the data structures a little. Also this is a bit of a tangent. Personally I prefer treating "sin" as one thing, so you cannot navigate inside it. That's the behavior of LyX for example. Word is illogical about this so we can ignore that.

An atom is a basic unit (regardless of whether the smallest atom is "s" or "sin" in "sin"). So a MathListIndex can index into an atom and we can replace "character" with "atom". But that's not the tricky change here.

@Happypig375
Copy link
Collaborator Author

Let's separate the behaviour from the data structures a little. Also this is a bit of a tangent.

What behaviour can be done depends on the data structure. If the structure disallows certain states, then behaviour relying on those states cannot exist. The resolution on MathListIndex's definition directly affects #83.

Personally I prefer treating "sin" as one thing, so you cannot navigate inside it. That's the behavior of LyX for example.

Then again, LyX does not have #83, as s i n does not produce \sin and \sin is its own button, just like current CSharpMath.

Word is illogical about this so we can ignore that.

s i n Space produces \sin, but deleting inside individual characters inside \sin makes roman characters, not reverting to variables. This does seem like unwanted behaviour.

An atom is a basic unit (regardless of whether the smallest atom is "s" or "sin" in "sin").

Then again, we can potentially enable dividing MathAtoms into characters just like how we can divide atoms into subatomic particles.

So a MathListIndex can index into an atom and we can replace "character" with "atom". But that's not the tricky change here.

The original documentation from iosMath does seem to use "character" and "atom" interchangeably, so this is also a solution.

@charlesroddie
Copy link
Collaborator

I'm juggling a few things but will have another look at this tomorrow. Can you explain what "deletion at the beginning of line (not pointing to any atom)" means? Perhaps an example?

@Happypig375
Copy link
Collaborator Author

image

@charlesroddie
Copy link
Collaborator

I see thanks. And do we need to do anything in that case? Do you have a strong preference about the right behavior when you press delete there?

@Happypig375
Copy link
Collaborator Author

I prefer the behaviour as done in this PR before your commits.

@charlesroddie
Copy link
Collaborator

MathQuill deletes the "sin" and moves the 789 down and so does LyX. Word selects the entire "sin^789" expression.

What did this branch do? I don't remember committing any behavioural changes in this branch.

@Happypig375
Copy link
Collaborator Author

What did this branch do?

I followed MathQuill.

I don't remember committing any behavioural changes in this branch.

Yes. See all the failed tests.

This was referenced Jul 14, 2020
@Happypig375
Copy link
Collaborator Author

This is a draft until tests pass.

@Happypig375 Happypig375 marked this pull request as draft July 16, 2020 15:28
@Happypig375
Copy link
Collaborator Author

What's the status of this PR?

@charlesroddie
Copy link
Collaborator

Sorry for delay. I'll look at this today

@charlesroddie
Copy link
Collaborator

What is a "finalized list"? (Wording used in many places and connected with a finalize:bool.)

@charlesroddie
Copy link
Collaborator

charlesroddie commented Aug 11, 2020

I've left TODOs for what would be needed to merge this.

The major functions are still unclear to me and I would have to piece them together from their implementations which would take a long time.

My guesses about the implementation: the cursor is at a certain position (also described by a MathListIndex I presume?), and there may be a MathListIndex describing something to be deleted to the left of it (your diagram of \sin^{789}, top). There may not be (your diagram, bottom), in which case an invalid MathListIndex is generated. This should not be done; instead the logic should go something like this:

let rec delete(atom, cursorPosition:MathListIndex) =
    match cursorPosition.SubIndex with
    | None -> // (this case is not reached recursively)
        if cursorPosition.AtomIndex = 0 then atom // do nothing
        else remove(atom, getMathIndexBefore cursorPosition)
    | Some subIndex ->
        if subIndex.Subindex = None && subIndex.AtomIndex = 0 then // on left of SubIndex
            match SubIndexType with
            | Superscript -> atom.Superscript // replace the atom with the superscript part as in the comments on your diagram
            | Subscript -> atom.Subscript
            ...
        else
            atom with the subindexed part `inner` replaced with delete(inner,cursorPosition.SubIndex)

Doesn't have to be done exactly like this but note the non-use of invalid MathListIndexes.

@charlesroddie
Copy link
Collaborator

I believe a MathListIndex should have a SubIndex if an only if SubIndexType <> MathListSubIndexType.None.

We should bring this constraint into the type structure: remove MathListSubIndexType.None and have

public (MathListSubIndexType SubIndexType, MathListIndex SubIndex)? SubIndexInfo;

I've started this but not ready to commit.

@Happypig375
Copy link
Collaborator Author

What is a "finalized list"? (Wording used in many places and connected with a finalize:bool.)

Unfinalized list Finalized list
Each digit is its own Number atom Digits are concatenated into one Number atom
BinaryOperators with no left argument stay as BinaryOperators They are converted to UnaryOperators
Atoms don't have Range and FusedAtoms Range and FusedAtoms are assigned

@Happypig375
Copy link
Collaborator Author

Regarding invalid indexes: Now we use MathListIndex to indicate both spaces between atoms (remove) and atom slots (insert)?

@charlesroddie
Copy link
Collaborator

Regarding invalid indexes: Now we use MathListIndex to indicate both spaces between atoms (remove) and atom slots (insert)?

I think you meant remove and insert the other way around? The interpretation for Atoms is now clear (at least pending resolution of BetweenBaseAndScripts). Representing cursor positions is something I'm trying to understand in order to document. Best to work on this in the other PR (cleaning up MathListIndex). Help appreciated with documentation of the existing structure and code and implementation of BetweenBaseAndScripts there. That will clear a significant piece of technical debt and allow looking at this PR again.

@Happypig375
Copy link
Collaborator Author

The best way of testing the indexes is to debug CSharpMath.Forms.Example.UWP, navigate to the Editor tab, and insert/navigate.
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants