internal static void AddSegments(ArrayBuilder <SourceText> segments, SourceText text) { CompositeText composite = text as CompositeText; if (composite == null) { segments.Add(text); } else { segments.AddRange(composite.Segments); } }
/// <summary> /// Constructs a new SourceText from this text with the specified changes. /// </summary> /// <param name="changes"></param> public virtual SourceText WithChanges(IEnumerable <TextChange> changes) { if (changes == null) { throw new ArgumentNullException(nameof(changes)); } if (!changes.Any()) { return(this); } var segments = ArrayBuilder <SourceText> .GetInstance(); var changeRanges = ArrayBuilder <TextChangeRange> .GetInstance(); int position = 0; foreach (var change in changes) { // there can be no overlapping changes if (change.Span.Start < position) { throw new ArgumentException(nameof(changes)); } var newTextLength = change.NewText?.Length ?? 0; // ignore changes that don't change anything if (change.Span.Length == 0 && newTextLength == 0) { continue; } // if we've skipped a range, add if (change.Span.Start > position) { var subText = GetSubText(new TextSpan(position, change.Span.Start - position)); CompositeText.AddSegments(segments, subText); } if (newTextLength > 0) { var segment = From(change.NewText, Encoding, ChecksumAlgorithm); CompositeText.AddSegments(segments, segment); } position = change.Span.End; changeRanges.Add(new TextChangeRange(change.Span, newTextLength)); } // no changes actually happened? if (position == 0 && segments.Count == 0) { changeRanges.Free(); return(this); } if (position < Length) { var subText = GetSubText(new TextSpan(position, Length - position)); CompositeText.AddSegments(segments, subText); } var newText = CompositeText.ToSourceTextAndFree(segments, this, true); if (newText != this) { return(new ChangedText(this, newText, changeRanges.ToImmutableAndFree())); } return(this); }