/// <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); }
void Apply() { // use original edit spans to update the selection location so that we get the finest // granied selection update possible. It should not be done on merged edits. ArrayList edits = this.editList; if (this.view != null) { // Now calculate the updated selection position based on what the edits are going to // do to the buffer. this.UpdateSelection(edits); } if (merge) { // Merge the edits into larger chunks for performance reasons. edits = this.MergeEdits(edits); } // Now apply the edits in reverse order because that one each edit will not interfere with the // span of the next edit. for (int i = edits.Count - 1; i >= 0; i--) { EditSpan es = (EditSpan)edits[i]; TextSpan span = es.Span; string text = es.Text; this.source.SetText(span, text); } this.editList.Clear(); // done! }
void AddCombinedEdit(EditSpan combined, StringBuilder buffer, ArrayList merged) { if (combined != null) { // add combined edit span. combined.Text = buffer.ToString(); merged.Add(combined); buffer.Length = 0; } }
/// <include file='doc\EditArray.uex' path='docs/doc[@for="EditArray.ToString"]/*' /> public override string ToString() { StringBuilder s = new StringBuilder(); for (int i = this.editList.Count - 1; i >= 0; i--) { EditSpan e = (EditSpan)this.editList[i]; s.AppendFormat("({0},{1}:{2},{3}) >>> '{4}'", e.Span.iStartLine, e.Span.iStartIndex, e.Span.iEndLine, e.Span.iEndIndex, GetDebugString(e.Text)); s.AppendLine(); } return(s.ToString()); }
void TraceEdits() { for (int j = 0; j < this.editList.Count - 1; j++) { EditSpan f = (EditSpan)this.editList[j]; TextSpan span = f.Span; string t = this.source.GetText(span); Trace.WriteLine( string.Format("{0}: {1},{2},{3},{4} '{5}'=>'{6}'", j, span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex, GetDebugString(t), GetDebugString(f.Text))); } }
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); }
/// <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); }
public override TextSpan UncommentLines(TextSpan span, string lineComment) { // Remove line comments int clen = lineComment.Length; var editMgr = new EditArray(this, null, true, "UncommentLines"); for (int line = span.iStartLine; line <= span.iEndLine; line++) { int i = this.ScanToNonWhitespaceChar(line); string text = base.GetLine(line); if ((i + clen) <= text.Length && text.Substring(i, clen) == lineComment) { var es = new EditSpan(new TextSpan() { iEndLine = line, iStartLine = line, iStartIndex = i, iEndIndex = i + clen }, ""); editMgr.Add(es); // remove line comment. if (line == span.iStartLine && span.iStartIndex != 0) span.iStartIndex = i; } } editMgr.ApplyEdits(); span.iStartIndex = 0; return span; }