/// <include file='doc\EditArray.uex' path='docs/doc[@for="EditArray.Add"]/*' /> /// <summary> /// Add a new atomic edit to the array. The edits cannot intersect each other. /// The spans in each edit must be based on the current state of the buffer, /// and not based on post-edit spans. This EditArray will calculate the /// post edit spans for you. /// </summary> /// <param name="editSpan"></param> public void Add(EditSpan editSpan) { if (editSpan == null) { throw new ArgumentNullException("editSpan"); } for (int i = this.editList.Count - 1; i >= 0; i--) { EditSpan e = (EditSpan)this.editList[i]; if (TextSpanHelper.Intersects(editSpan.Span, e.Span)) { string msg = SR.GetString(SR.EditIntersects, i); #if LANGTRACE Debug.Assert(false, msg); TraceEdits(); #endif throw new System.ArgumentException(msg); } if (TextSpanHelper.StartsAfterStartOf(editSpan.Span, e.Span)) { this.editList.Insert(i + 1, editSpan); return; } } this.editList.Insert(0, editSpan); }
const int ChunkThreshold = 1000; // don't combine chunks separate by more than 1000 characters. ArrayList MergeEdits(ArrayList edits) { StringBuilder buffer = new StringBuilder(); EditSpan combined = null; ArrayList merged = new ArrayList(); ArrayList markers = GetTextMarkers(); int markerPos = 0; TextSpan marker = (markers.Count > 0) ? (TextSpan)markers[0] : new TextSpan(); foreach (EditSpan editSpan in edits) { TextSpan span = editSpan.Span; string text = editSpan.Text; if (markerPos < markers.Count && (TextSpanHelper.StartsAfterStartOf(span, marker) || TextSpanHelper.EndsAfterStartOf(span, marker))) { AddCombinedEdit(combined, buffer, merged); if (TextSpanHelper.Intersects(span, marker)) { combined = null; // Have to apply this as a distinct edit operation. merged.Add(editSpan); } else { combined = editSpan; buffer.Append(text); } while (++markerPos < markers.Count) { marker = (TextSpan)markers[markerPos]; if (!TextSpanHelper.StartsAfterStartOf(span, marker) && !TextSpanHelper.EndsAfterStartOf(span, marker)) { break; } } } else if (combined == null) { combined = editSpan; buffer.Append(text); } else { // A little sanity check here, if there are too many characters in between the two // edits, then keep them separate. TextSpan s = combined.Span; string between = this.source.GetText(s.iEndLine, s.iEndIndex, span.iStartLine, span.iStartIndex); if (between.Length > ChunkThreshold) { AddCombinedEdit(combined, buffer, merged); combined = editSpan; buffer.Append(text); } else { // merge edit spans by adding the text in-between the current and previous spans. buffer.Append(between); buffer.Append(text); // and add the new text. s.iEndIndex = span.iEndIndex; s.iEndLine = span.iEndLine; combined.Span = s; } } } AddCombinedEdit(combined, buffer, merged); return(merged); }