internal void ComputeSourceEdits(FrugalList <TextChange> changes) { ITextEdit xedit = this.group.GetEdit((BaseBuffer)this.sourceBuffer); foreach (TextChange change in changes) { if (change.OldLength > 0) { IList <SnapshotSpan> sourceDeletionSpans = this.currentElisionSnapshot.MapToSourceSnapshots(new Span(change.OldPosition, change.OldLength)); foreach (SnapshotSpan sourceDeletionSpan in sourceDeletionSpans) { xedit.Delete(sourceDeletionSpan); } } if (change.NewLength > 0) { // change includes an insertion ReadOnlyCollection <SnapshotPoint> sourceInsertionPoints = this.currentElisionSnapshot.MapInsertionPointToSourceSnapshots(change.OldPosition, null); if (sourceInsertionPoints.Count == 1) { // the insertion point is unambiguous xedit.Insert(sourceInsertionPoints[0].Position, change.NewText); } else { // the insertion is at the boundary of source spans int[] insertionSizes = new int[sourceInsertionPoints.Count]; if (this.resolver != null) { this.resolver.FillInInsertionSizes(new SnapshotPoint(this.currentElisionSnapshot, change.OldPosition), sourceInsertionPoints, change.NewText, insertionSizes); } // if resolver was not provided, we just use zeros for the insertion sizes, which will push the entire insertion // into the last slot. int pos = 0; for (int i = 0; i < insertionSizes.Length; ++i) { // contend with any old garbage that the client passed back. int size = (i == insertionSizes.Length - 1) ? change.NewLength - pos : Math.Min(insertionSizes[i], change.NewLength - pos); if (size > 0) { xedit.Insert(sourceInsertionPoints[i].Position, TextChange.ChangeNewSubstring(change, pos, size)); pos += size; if (pos == change.NewLength) { break; // inserted text is used up, whether we've visited all of the insertionSizes or not } } } } } } this.editApplicationInProgress = true; }