public void Update(ITextSourceVersion newVersion) { // Apply document changes to all highlighting sections: foreach (TextChangeEventArgs change in OldVersion.GetChangesTo(newVersion)) { foreach (HighlightedSection section in HighlightedLine.Sections) { int endOffset = section.Offset + section.Length; section.Offset = change.GetNewOffset(section.Offset); endOffset = change.GetNewOffset(endOffset); section.Length = endOffset - section.Offset; } } // The resulting sections might have become invalid: // - zero-length if section was deleted, // - a section might have moved outside the range of this document line (newline inserted in document = line split up) // So we will remove all highlighting sections which have become invalid. int lineStart = HighlightedLine.DocumentLine.Offset; int lineEnd = lineStart + HighlightedLine.DocumentLine.Length; for (int i = 0; i < HighlightedLine.Sections.Count; i++) { HighlightedSection section = HighlightedLine.Sections[i]; if (section.Offset < lineStart || section.Offset + section.Length > lineEnd || section.Length <= 0) { HighlightedLine.Sections.RemoveAt(i--); } } this.OldVersion = newVersion; this.IsValid = false; }
public void Apply(IDocument document) { using (document.OpenUndoGroup()) { var changes = oldVersion.GetChangesTo(newVersion); foreach (var change in changes) { document.Replace(change.Offset, change.RemovalLength, change.InsertedText); } } }
internal List <UnchangedSegment> GetReuseMapTo(ITextSourceVersion newVersion) { ITextSourceVersion oldVersion = this.Version; if (oldVersion == null || newVersion == null) { return(null); } if (!oldVersion.BelongsToSameDocumentAs(newVersion)) { return(null); } List <UnchangedSegment> reuseMap = new List <UnchangedSegment>(); reuseMap.Add(new UnchangedSegment(0, 0, this.TextLength)); foreach (var change in oldVersion.GetChangesTo(newVersion)) { bool needsSegmentRemoval = false; for (int i = 0; i < reuseMap.Count; i++) { UnchangedSegment segment = reuseMap[i]; if (segment.NewOffset + segment.Length <= change.Offset) { // change is completely after this segment continue; } if (change.Offset + change.RemovalLength <= segment.NewOffset) { // change is completely before this segment segment.NewOffset += change.InsertionLength - change.RemovalLength; reuseMap[i] = segment; continue; } // Change is overlapping segment. // Split segment into two parts: the part before change, and the part after change. var segmentBefore = new UnchangedSegment(segment.OldOffset, segment.NewOffset, change.Offset - segment.NewOffset); Debug.Assert(segmentBefore.Length < segment.Length); int lengthAtEnd = segment.NewOffset + segment.Length - (change.Offset + change.RemovalLength); var segmentAfter = new UnchangedSegment( segment.OldOffset + segment.Length - lengthAtEnd, change.Offset + change.InsertionLength, lengthAtEnd); Debug.Assert(segmentAfter.Length < segment.Length); Debug.Assert(segmentBefore.Length + segmentAfter.Length <= segment.Length); Debug.Assert(segmentBefore.NewOffset + segmentBefore.Length <= segmentAfter.NewOffset); Debug.Assert(segmentBefore.OldOffset + segmentBefore.Length <= segmentAfter.OldOffset); if (segmentBefore.Length > 0 && segmentAfter.Length > 0) { reuseMap[i] = segmentBefore; reuseMap.Insert(++i, segmentAfter); } else if (segmentBefore.Length > 0) { reuseMap[i] = segmentBefore; } else { reuseMap[i] = segmentAfter; if (segmentAfter.Length <= 0) { needsSegmentRemoval = true; } } } if (needsSegmentRemoval) { reuseMap.RemoveAll(s => s.Length <= 0); } } return(reuseMap); }