internal List<UnchangedSegment> GetReuseMapTo(SourceText newVersion) { SourceText 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.GetTextChanges(newVersion)) { bool needsSegmentRemoval = false; var insertionLength = change.NewText != null ? change.NewText.Length : 0; for (int i = 0; i < reuseMap.Count; i++) { UnchangedSegment segment = reuseMap[i]; if (segment.NewOffset + segment.Length <= change.Span.Start) { // change is completely after this segment continue; } if (change.Span.End <= segment.NewOffset) { // change is completely before this segment segment.NewOffset += insertionLength - change.Span.Length; 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.Span.Start - segment.NewOffset); Debug.Assert(segmentBefore.Length < segment.Length); int lengthAtEnd = segment.NewOffset + segment.Length - (change.Span.End); var segmentAfter = new UnchangedSegment( segment.OldOffset + segment.Length - lengthAtEnd, change.Span.Start + 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; }
internal List <UnchangedSegment> GetReuseMapTo(SourceText newVersion) { SourceText 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.GetTextChanges(newVersion)) { bool needsSegmentRemoval = false; var insertionLength = change.NewText != null ? change.NewText.Length : 0; for (int i = 0; i < reuseMap.Count; i++) { UnchangedSegment segment = reuseMap[i]; if (segment.NewOffset + segment.Length <= change.Span.Start) { // change is completely after this segment continue; } if (change.Span.End <= segment.NewOffset) { // change is completely before this segment segment.NewOffset += insertionLength - change.Span.Length; 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.Span.Start - segment.NewOffset); Debug.Assert(segmentBefore.Length < segment.Length); int lengthAtEnd = segment.NewOffset + segment.Length - (change.Span.End); var segmentAfter = new UnchangedSegment( segment.OldOffset + segment.Length - lengthAtEnd, change.Span.Start + 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); }