/// <summary> Finds a series of nodes that are affected by a change at the given index. </summary> /// <param name="range"> The range at which a change is being applied </param> /// <returns> The nodes that are affected by the change. </returns> private FoundNode GetAffectedNodes(Range range) { var listNode = _subFragments.First; int absoluteIndexOfLastSubFragment = 0; var foundNode = new FoundNode(); while (listNode != null) { MarkupNodeReference subFragment = listNode.Value; var subFragmentAbsoluteStart = absoluteIndexOfLastSubFragment + subFragment.RelativeOffsetSinceLastNode; var nodeRange = new Range(subFragmentAbsoluteStart, subFragmentAbsoluteStart + subFragment.Length); if (range.EndIndex < nodeRange.StartIndex) { // the change is before every remaining sub-fragment, so we can bail out now foundNode.MarkRemaining(listNode); break; } if (nodeRange.OverlapsInclusive(range)) { foundNode.RememberFirstAndLast(nodeRange.StartIndex, listNode); } absoluteIndexOfLastSubFragment = nodeRange.StartIndex; listNode = listNode.Next; } return(foundNode); }
/// <summary> Transforms a single range using the given modification. </summary> private Range Transform(Range range, RangeModification modification) { if (modification.WasAdded) { if (range.ContainsExclusive(modification.Index)) { return(new Range(range.StartIndex, range.EndIndex + modification.NumberOfItems)); } else if (range.StartIndex < modification.Index) { return(range); } else { return(new Range(range.StartIndex + modification.NumberOfItems, range.EndIndex + modification.NumberOfItems)); } } else { var deletionRange = new Range(modification.Index, modification.Index + modification.NumberOfItems); if (deletionRange.ContainsInclusive(range.StartIndex) && deletionRange.ContainsInclusive(range.EndIndex)) { // if the deletion range took out the range, remove it altogether return(new Range(deletionRange.StartIndex, deletionRange.StartIndex)); } else if (deletionRange.OverlapsInclusive(range)) { if (deletionRange.StartIndex <= range.StartIndex) { int overlappingCharCount = deletionRange.EndIndex - range.StartIndex; int numberOfCharactersBefore = range.StartIndex - deletionRange.StartIndex; int numberOfAvailableCharsToDelete = Math.Min(overlappingCharCount, range.Length); return(new Range(range.StartIndex - numberOfCharactersBefore, range.EndIndex - numberOfCharactersBefore - numberOfAvailableCharsToDelete)); } else /* range.StartIndex <= deletionRange.EndIndex */ { var numberOfCharsToDelete = Math.Min(range.EndIndex - deletionRange.StartIndex, deletionRange.Length); return(new Range(range.StartIndex, range.EndIndex - numberOfCharsToDelete)); } } else if (deletionRange.StartIndex < range.StartIndex) { return(new Range(range.StartIndex - modification.NumberOfItems, range.EndIndex - modification.NumberOfItems)); } else { return(range); } } }