private static bool TopLevelChanged(SyntaxTree oldTree, SourceText oldText, SyntaxTree newTree, SourceText newText) { // ** currently, it doesn't do any text based quick check. we can add them later if current logic is not performant enough for typing case. var change = newText.GetEncompassingTextChangeRange(oldText); if (change == default) { // nothing has changed return(false); } // if texts are small enough, just use the equivalent to find out whether there was top level edits if (oldText.Length < MaxTextChangeRangeLength && newText.Length < MaxTextChangeRangeLength) { var topLevel = !newTree.IsEquivalentTo(oldTree, topLevel: true); return(topLevel); } // okay, text is not small and whole text is changed, then we always treat it as top level edit if (change.NewLength == newText.Length) { return(true); } // if changes are small enough, we use IsEquivalentTo to find out whether there was a top level edit if (change.Span.Length < MaxTextChangeRangeLength && change.NewLength < MaxTextChangeRangeLength) { var topLevel = !newTree.IsEquivalentTo(oldTree, topLevel: true); return(topLevel); } // otherwise, we always consider top level change return(true); }
// Returns the minimal TextSpan that encompasses all the differences between the old and the new text. protected static void TrackEncompassingChange(SourceText oldText, SourceText newText, out TextSpan spanBeforeChange, out TextSpan spanAfterChange) { if (oldText is null) { throw new ArgumentNullException(nameof(oldText)); } if (newText is null) { throw new ArgumentNullException(nameof(newText)); } var affectedRange = newText.GetEncompassingTextChangeRange(oldText); spanBeforeChange = affectedRange.Span; spanAfterChange = new TextSpan(spanBeforeChange.Start, affectedRange.NewLength); }
private void TrackChangeInSpan(SourceText oldText, TextSpan originalSpan, SourceText newText, out TextSpan changedSpan, out TextSpan changeEncompassingSpan) { var affectedRange = newText.GetEncompassingTextChangeRange(oldText); // The span of text before the edit which is being changed changeEncompassingSpan = affectedRange.Span; if (!originalSpan.Contains(changeEncompassingSpan)) { _logger.LogDebug($"The changed region {changeEncompassingSpan} was not a subset of the span {originalSpan} being tracked. This is unexpected."); } // We now know what was the range that changed and the length of that span after the change. // Let's now compute what the original span looks like after the change. // We know it still starts from the same location but could have grown or shrunk in length. // Compute the change in length and then update the original span. var changeInOriginalSpanLength = affectedRange.NewLength - changeEncompassingSpan.Length; changedSpan = TextSpan.FromBounds(originalSpan.Start, originalSpan.End + changeInOriginalSpanLength); }