/// <summary> /// Updates the start and end offsets of all segments stored in this collection. /// </summary> /// <param name="e">DocumentChangeEventArgs instance describing the change to the document.</param> public void UpdateOffsets(DocumentChangeEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } if (isConnectedToDocument) { throw new InvalidOperationException("This TextSegmentCollection will automatically update offsets; do not call UpdateOffsets manually!"); } OnDocumentChanged(e); CheckProperties(); }
internal void Push(TextDocument document, DocumentChangeEventArgs e) { if (state == StatePlayback) { throw new InvalidOperationException("Document changes during undo/redo operations are not allowed."); } if (state == StatePlaybackModifyDocument) { state = StatePlayback; // allow only 1 change per expected modification } else { Push(new DocumentChangeOperation(document, e)); } }
void OnDocumentChanged(DocumentChangeEventArgs e) { OffsetChangeMap map = e.OffsetChangeMapOrNull; if (map != null) { foreach (OffsetChangeMapEntry entry in map) { UpdateOffsetsInternal(entry); } } else { UpdateOffsetsInternal(e.CreateSingleChangeMapEntry()); } }
internal void Push(TextDocument document, DocumentChangeEventArgs e) { if (state == StatePlayback) throw new InvalidOperationException("Document changes during undo/redo operations are not allowed."); if (state == StatePlaybackModifyDocument) state = StatePlayback; // allow only 1 change per expected modification else Push(new DocumentChangeOperation(document, e)); }
public DocumentChangeOperation(TextDocument document, DocumentChangeEventArgs change) { this.document = document; this.change = change; }
void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap) { if (length == 0 && newText.Length == 0) { return; } // trying to replace a single character in 'Normal' mode? // for single characters, 'CharacterReplace' mode is equivalent, but more performant // (we don't have to touch the anchorTree at all in 'CharacterReplace' mode) if (length == 1 && newText.Length == 1 && offsetChangeMap == null) { offsetChangeMap = OffsetChangeMap.Empty; } string removedText = rope.ToString(offset, length); DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap); // fire DocumentChanging event if (Changing != null) { Changing(this, args); } undoStack.Push(this, args); cachedText = null; // reset cache of complete document text fireTextChanged = true; DelayedEvents delayedEvents = new DelayedEvents(); lock (lockObject) { // create linked list of checkpoints, if required if (currentCheckpoint != null) { currentCheckpoint = currentCheckpoint.Append(args); } // now update the textBuffer and lineTree if (offset == 0 && length == rope.Length) { // optimize replacing the whole document rope.Clear(); rope.InsertText(0, newText); lineManager.Rebuild(); } else { rope.RemoveRange(offset, length); lineManager.Remove(offset, length); #if DEBUG lineTree.CheckProperties(); #endif rope.InsertText(offset, newText); lineManager.Insert(offset, newText); #if DEBUG lineTree.CheckProperties(); #endif } } // update text anchors if (offsetChangeMap == null) { anchorTree.HandleTextChange(args.CreateSingleChangeMapEntry(), delayedEvents); } else { foreach (OffsetChangeMapEntry entry in offsetChangeMap) { anchorTree.HandleTextChange(entry, delayedEvents); } } // raise delayed events after our data structures are consistent again delayedEvents.RaiseEvents(); // fire DocumentChanged event if (Changed != null) { Changed(this, args); } }
internal ChangeTrackingCheckpoint Append(DocumentChangeEventArgs change) { Debug.Assert(this.next == null); this.next = new ChangeTrackingCheckpoint(this.documentIdentifier, change, unchecked (this.id + 1)); return(this.next); }
internal ChangeTrackingCheckpoint(object documentIdentifier, DocumentChangeEventArgs value, int id) { this.documentIdentifier = documentIdentifier; this.value = value; this.id = id; }
void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap) { if (length == 0 && newText.Length == 0) return; // trying to replace a single character in 'Normal' mode? // for single characters, 'CharacterReplace' mode is equivalent, but more performant // (we don't have to touch the anchorTree at all in 'CharacterReplace' mode) if (length == 1 && newText.Length == 1 && offsetChangeMap == null) offsetChangeMap = OffsetChangeMap.Empty; string removedText = rope.ToString(offset, length); DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap); // fire DocumentChanging event if (Changing != null) Changing(this, args); undoStack.Push(this, args); cachedText = null; // reset cache of complete document text fireTextChanged = true; DelayedEvents delayedEvents = new DelayedEvents(); lock (lockObject) { // create linked list of checkpoints, if required if (currentCheckpoint != null) { currentCheckpoint = currentCheckpoint.Append(args); } // now update the textBuffer and lineTree if (offset == 0 && length == rope.Length) { // optimize replacing the whole document rope.Clear(); rope.InsertText(0, newText); lineManager.Rebuild(); } else { rope.RemoveRange(offset, length); lineManager.Remove(offset, length); #if DEBUG lineTree.CheckProperties(); #endif rope.InsertText(offset, newText); lineManager.Insert(offset, newText); #if DEBUG lineTree.CheckProperties(); #endif } } // update text anchors if (offsetChangeMap == null) { anchorTree.HandleTextChange(args.CreateSingleChangeMapEntry(), delayedEvents); } else { foreach (OffsetChangeMapEntry entry in offsetChangeMap) { anchorTree.HandleTextChange(entry, delayedEvents); } } // raise delayed events after our data structures are consistent again delayedEvents.RaiseEvents(); // fire DocumentChanged event if (Changed != null) Changed(this, args); }
internal ChangeTrackingCheckpoint Append(DocumentChangeEventArgs change) { Debug.Assert(this.next == null); this.next = new ChangeTrackingCheckpoint(this.documentIdentifier, change, unchecked( this.id + 1 )); return this.next; }