internal static int TrackPositionForwardInTime()

in src/Editor/Text/Impl/TextModel/HighFidelityTrackingPoint.cs [141:282]


        internal static int TrackPositionForwardInTime(PointTrackingMode trackingMode,
                                                       TrackingFidelityMode fidelity,
                                                       ref List<VersionNumberPosition> noninvertibleHistory,
                                                       int currentPosition,
                                                       ITextVersion currentVersion,
                                                       ITextVersion targetVersion)
        {
            System.Diagnostics.Debug.Assert(targetVersion.VersionNumber > currentVersion.VersionNumber);

            // track forward in time
            ITextVersion roverVersion = currentVersion;
            while (roverVersion != targetVersion)
            {
                currentVersion = roverVersion;
                roverVersion = currentVersion.Next;

                if (fidelity == TrackingFidelityMode.UndoRedo &&
                    roverVersion.ReiteratedVersionNumber != roverVersion.VersionNumber &&
                    noninvertibleHistory != null)
                {
                    int p = noninvertibleHistory.BinarySearch
                                (new VersionNumberPosition(roverVersion.ReiteratedVersionNumber, 0),
                                 VersionNumberPositionComparer.Instance);
                    if (p >= 0)
                    {
                        currentPosition = noninvertibleHistory[p].Position;
                        continue;
                    }
                }

                int changeCount = currentVersion.Changes.Count;
                if (changeCount == 0)
                {
                    // A version which has no text changes preserves the reiterated version number of the previous version,
                    // so its version number and reiterated version number will be different. We need to record a possibly 
                    // noninvertible change with the reiterated version number as well as with the version number. 
                    Debug.Assert(roverVersion.VersionNumber != roverVersion.ReiteratedVersionNumber);
                    if (roverVersion.VersionNumber != roverVersion.ReiteratedVersionNumber)
                    {
                        RecordNoninvertibleTransition(ref noninvertibleHistory, currentPosition, roverVersion.ReiteratedVersionNumber);
                    }
                    continue;
                }

                int currentVersionStartingPosition = currentPosition;
                for (int c = 0; c < changeCount; ++c)
                {
                    ITextChange textChange = currentVersion.Changes[c];
                    if (IsOpaque(textChange))
                    {
                        if (textChange.NewPosition + textChange.OldLength <= currentPosition)
                        {
                            // point is to the right of the opaque change. shift it.
                            currentPosition += textChange.Delta;
                            continue;
                        }
                        else if (textChange.NewPosition <= currentPosition)
                        {
                            // point is within the opaque change. stay put (but within the change)
                            if (textChange.NewEnd <= currentPosition)
                            {
                                // we shift to the left because the new text is shorter than what
                                // it replaced. this is a noninvertible transition, so remember it.
                                RecordNoninvertibleTransition(ref noninvertibleHistory, currentVersionStartingPosition, currentVersion.VersionNumber);
                                currentPosition = textChange.NewEnd;
                            }
                            // No further change in this version can affect us.
                            break;
                        }
                        else
                        {
                            // point is to the left of the opaque change. no effect, and we are done.
                            break;
                        }
                    }

                    if (trackingMode == PointTrackingMode.Positive)
                    {
                        // Positive tracking mode: point moves with insertions at its location.
                        if (textChange.NewPosition <= currentPosition)
                        {
                            if (textChange.NewPosition + textChange.OldLength <= currentPosition)
                            {
                                // easy: the change is entirely to the left of our position.
                                // if NewPosition + OldLength == currentPosition, it means that the character
                                // immediately before our position was deleted (or replaced). When going back
                                // in time we will see this as an insertion, and since our tracking mode is positive,
                                // we will put ourselves after it.
                                currentPosition += textChange.Delta;
                            }
                            else
                            {
                                // textChange deleted text at the position of the tracked point; now the point is
                                // pushed to the end of the textChange insertion.

                                // This is a noninvertible transition. Remember it.
                                RecordNoninvertibleTransition(ref noninvertibleHistory, currentVersionStartingPosition, currentVersion.VersionNumber);
                                currentPosition = textChange.NewEnd;
                                break;
                            }
                        }
                        else
                        {
                            // the change is entirely to the right of our position; since changes are
                            // sorted, we are done.
                            break;
                        }
                    }
                    else
                    {
                        // Negative tracking mode: point doesn't move with respect to insertions at its location.
                        if (textChange.NewPosition < currentPosition)
                        {
                            if (textChange.NewPosition + textChange.OldLength < currentPosition)
                            {
                                // easy: the change is entirely to the left of our position. Since we
                                // are paying attention to the tracking mode when tracking back (to handle the
                                // before-the-origin-version case), we need to consider NewPosition + OldLength ==
                                // currentPosition case as noninvertible.
                                currentPosition += textChange.Delta;
                            }
                            else
                            {
                                // textChange deleted text at the position of the tracked point; now the point is
                                // at the position of the change, prior to any insertion.

                                // This is a nonivertible transition.
                                RecordNoninvertibleTransition(ref noninvertibleHistory, currentVersionStartingPosition, currentVersion.VersionNumber);
                                currentPosition = textChange.NewPosition;
                                break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            return currentPosition;
        }