internal void Delete(ref DeferredEventList deferredEventList) { // we cannot fire an event here because this method is called while the LineManager adjusts the // lineCollection, so an event handler could see inconsistent state _lineSegment = null; deferredEventList.AddDeletedAnchor(this); }
/// <summary> /// Replaces the specified offset. /// </summary> /// <param name="offset">The offset.</param> /// <param name="length">The length.</param> /// <param name="text">The text.</param> public void Replace(int offset, int length, string text) { int lineStart = GetLineNumberForOffset(offset); int oldNumberOfLines = TotalNumberOfLines; DeferredEventList deferredEventList = new DeferredEventList(); RemoveInternal(ref deferredEventList, offset, length); int numberOfLinesAfterRemoving = TotalNumberOfLines; if (!string.IsNullOrEmpty(text)) { InsertInternal(offset, text); } // Only fire events after RemoveInternal+InsertInternal finished completely: // Otherwise we would expose inconsistent state to the event handlers. RunHighlighter(lineStart, 1 + Math.Max(0, TotalNumberOfLines - numberOfLinesAfterRemoving)); if (deferredEventList.RemovedLines != null) { foreach (LineSegment ls in deferredEventList.RemovedLines) { OnLineDeleted(new LineEventArgs(_document, ls)); } } deferredEventList.RaiseEvents(); if (TotalNumberOfLines != oldNumberOfLines) { OnLineCountChanged(new LineCountChangedEventArgs(_document, lineStart, TotalNumberOfLines - oldNumberOfLines)); } }
void RemoveInternal(ref DeferredEventList deferredEventList, int offset, int length) { Debug.Assert(length >= 0); if (length == 0) { return; } LineSegmentTree.Enumerator it = _lineSegments.GetEnumeratorForOffset(offset); LineSegment startSegment = it.Current; int startSegmentOffset = startSegment.Offset; if (offset + length < startSegmentOffset + startSegment.TotalLength) { // just removing a part of this line segment startSegment.RemovedLinePart(ref deferredEventList, offset - startSegmentOffset, length); SetSegmentLength(startSegment, startSegment.TotalLength - length); return; } // merge startSegment with another line segment because startSegment's delimiter was deleted // possibly remove lines in between if multiple delimiters were deleted int charactersRemovedInStartLine = startSegmentOffset + startSegment.TotalLength - offset; Debug.Assert(charactersRemovedInStartLine > 0); startSegment.RemovedLinePart(ref deferredEventList, offset - startSegmentOffset, charactersRemovedInStartLine); LineSegment endSegment = _lineSegments.GetByOffset(offset + length); if (endSegment == startSegment) { // special case: we are removing a part of the last line up to the // end of the document SetSegmentLength(startSegment, startSegment.TotalLength - length); return; } int endSegmentOffset = endSegment.Offset; int charactersLeftInEndLine = endSegmentOffset + endSegment.TotalLength - (offset + length); endSegment.RemovedLinePart(ref deferredEventList, 0, endSegment.TotalLength - charactersLeftInEndLine); startSegment.MergedWith(endSegment, offset - startSegmentOffset); SetSegmentLength(startSegment, startSegment.TotalLength - charactersRemovedInStartLine + charactersLeftInEndLine); startSegment.DelimiterLength = endSegment.DelimiterLength; // remove all segments between startSegment (excl.) and endSegment (incl.) it.MoveNext(); LineSegment segmentToRemove; do { segmentToRemove = it.Current; it.MoveNext(); _lineSegments.RemoveSegment(segmentToRemove); segmentToRemove.Deleted(ref deferredEventList); } while (segmentToRemove != endSegment); }
/// <summary> /// Is called when the <see cref="LineSegment"/> is deleted. /// </summary> /// <param name="deferredEventList">The deferred event list.</param> internal void Deleted(ref DeferredEventList deferredEventList) { //Console.WriteLine("Deleted"); _treeEntry = LineSegmentTree.Enumerator.Invalid; if (_anchors != null) { foreach (TextAnchor anchor in _anchors) { anchor.Delete(ref deferredEventList); } _anchors = null; } }
/// <summary> /// Is called when a part of the line is removed. /// </summary> internal void RemovedLinePart(ref DeferredEventList deferredEventList, int startColumn, int length) { if (length == 0) { return; } Debug.Assert(length > 0); if (_anchors != null) { List <TextAnchor> deletedAnchors = null; foreach (TextAnchor anchor in _anchors) { if (anchor.ColumnNumber > startColumn) { if (anchor.ColumnNumber >= startColumn + length) { anchor.ColumnNumber -= length; } else { if (deletedAnchors == null) { deletedAnchors = new List <TextAnchor>(); } anchor.Delete(ref deferredEventList); deletedAnchors.Add(anchor); } } } if (deletedAnchors != null) { foreach (TextAnchor anchor in deletedAnchors) { _anchors.Remove(anchor); } } } }
/// <summary> /// Is called when a part of the line is removed. /// </summary> internal void RemovedLinePart(ref DeferredEventList deferredEventList, int startColumn, int length) { if (length == 0) return; Debug.Assert(length > 0); if (_anchors != null) { List<TextAnchor> deletedAnchors = null; foreach (TextAnchor anchor in _anchors) { if (anchor.ColumnNumber > startColumn) { if (anchor.ColumnNumber >= startColumn + length) { anchor.ColumnNumber -= length; } else { if (deletedAnchors == null) deletedAnchors = new List<TextAnchor>(); anchor.Delete(ref deferredEventList); deletedAnchors.Add(anchor); } } } if (deletedAnchors != null) { foreach (TextAnchor anchor in deletedAnchors) { _anchors.Remove(anchor); } } } }
void RemoveInternal(ref DeferredEventList deferredEventList, int offset, int length) { Debug.Assert(length >= 0); if (length == 0) return; LineSegmentTree.Enumerator it = _lineSegments.GetEnumeratorForOffset(offset); LineSegment startSegment = it.Current; int startSegmentOffset = startSegment.Offset; if (offset + length < startSegmentOffset + startSegment.TotalLength) { // just removing a part of this line segment startSegment.RemovedLinePart(ref deferredEventList, offset - startSegmentOffset, length); SetSegmentLength(startSegment, startSegment.TotalLength - length); return; } // merge startSegment with another line segment because startSegment's delimiter was deleted // possibly remove lines in between if multiple delimiters were deleted int charactersRemovedInStartLine = startSegmentOffset + startSegment.TotalLength - offset; Debug.Assert(charactersRemovedInStartLine > 0); startSegment.RemovedLinePart(ref deferredEventList, offset - startSegmentOffset, charactersRemovedInStartLine); LineSegment endSegment = _lineSegments.GetByOffset(offset + length); if (endSegment == startSegment) { // special case: we are removing a part of the last line up to the // end of the document SetSegmentLength(startSegment, startSegment.TotalLength - length); return; } int endSegmentOffset = endSegment.Offset; int charactersLeftInEndLine = endSegmentOffset + endSegment.TotalLength - (offset + length); endSegment.RemovedLinePart(ref deferredEventList, 0, endSegment.TotalLength - charactersLeftInEndLine); startSegment.MergedWith(endSegment, offset - startSegmentOffset); SetSegmentLength(startSegment, startSegment.TotalLength - charactersRemovedInStartLine + charactersLeftInEndLine); startSegment.DelimiterLength = endSegment.DelimiterLength; // remove all segments between startSegment (excl.) and endSegment (incl.) it.MoveNext(); LineSegment segmentToRemove; do { segmentToRemove = it.Current; it.MoveNext(); _lineSegments.RemoveSegment(segmentToRemove); segmentToRemove.Deleted(ref deferredEventList); } while (segmentToRemove != endSegment); }
/// <summary> /// Replaces the specified offset. /// </summary> /// <param name="offset">The offset.</param> /// <param name="length">The length.</param> /// <param name="text">The text.</param> public void Replace(int offset, int length, string text) { int lineStart = GetLineNumberForOffset(offset); int oldNumberOfLines = TotalNumberOfLines; DeferredEventList deferredEventList = new DeferredEventList(); RemoveInternal(ref deferredEventList, offset, length); int numberOfLinesAfterRemoving = TotalNumberOfLines; if (!string.IsNullOrEmpty(text)) { InsertInternal(offset, text); } // Only fire events after RemoveInternal+InsertInternal finished completely: // Otherwise we would expose inconsistent state to the event handlers. RunHighlighter(lineStart, 1 + Math.Max(0, TotalNumberOfLines - numberOfLinesAfterRemoving)); if (deferredEventList.RemovedLines != null) { foreach (LineSegment ls in deferredEventList.RemovedLines) OnLineDeleted(new LineEventArgs(_document, ls)); } deferredEventList.RaiseEvents(); if (TotalNumberOfLines != oldNumberOfLines) { OnLineCountChanged(new LineCountChangedEventArgs(_document, lineStart, TotalNumberOfLines - oldNumberOfLines)); } }