Beispiel #1
0
        /// <summary>
        /// Get the text changes between this document and a prior version of the same document.
        /// The changes, when applied to the text of the old document, will produce the text of the current document.
        /// </summary>
        public async Task <IEnumerable <TextChange> > GetTextChangesAsync(Document oldDocument, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                using (Logger.LogBlock(FeatureId.Document, FunctionId.Document_GetTextChanges, this.Name, cancellationToken))
                {
                    if (oldDocument == this)
                    {
                        // no changes
                        return(SpecializedCollections.EmptyEnumerable <TextChange>());
                    }

                    if (this.Id != oldDocument.Id)
                    {
                        throw new ArgumentException(WorkspacesResources.DocumentVersionIsDifferent);
                    }

                    // first try to see if text already knows its changes
                    IList <TextChange> textChanges = null;

                    SourceText text;
                    SourceText oldText;
                    if (this.TryGetText(out text) && oldDocument.TryGetText(out oldText))
                    {
                        if (text == oldText)
                        {
                            return(SpecializedCollections.EmptyEnumerable <TextChange>());
                        }

                        var container = text.Container;
                        if (container != null)
                        {
                            textChanges = text.GetTextChanges(oldText).ToList();

                            // if changes are significant (not the whole document being replaced) then use these changes
                            if (textChanges.Count > 1 || (textChanges.Count == 1 && textChanges[0].Span != new TextSpan(0, oldText.Length)))
                            {
                                return(textChanges);
                            }
                        }
                    }

                    // get changes by diffing the trees
                    SyntaxTree tree = await this.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                    SyntaxTree oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                    return(tree.GetChanges(oldTree));
                }
            }
            catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
        }
Beispiel #2
0
        /// <summary>
        /// Generates Diff results for each change that occurred from the ancestor to the changed
        /// </summary>
        /// <param name="ancestor">
        /// The abstract syntax tree that the changed version originated from
        /// </param>
        /// <param name="changed">The abstract syntax tree that resulted from changing the ancestor</param>
        /// <returns>Changes between the ancestor and changed</returns>
        public static IEnumerable<Diff> Compare(SyntaxTree ancestor, SyntaxTree changed)
        {
            var offset = 0; //Tracks differences in indexes moving through the changed syntax tree
            foreach (var change in changed.GetChanges(ancestor))
            { //Assumes that this list is sorted by place in file
                var origLength = change.Span.Length;
                var offsetChange = (change.NewText.Length - origLength);

                var chanStart = change.Span.Start + offset;
                var chanLength = origLength + offsetChange;

                offset += offsetChange;

                var d = new Diff
                {
                    Ancestor = SpanDetails.Create(change.Span, ancestor),
                    Changed = SpanDetails.Create(new TextSpan(chanStart, chanLength), changed)
                };

                yield return d;
            }
        }
Beispiel #3
0
    private static bool TryGetChangesIgnoringWhiteSpace(SyntaxTree oldTree, SyntaxTree newTree, out IEnumerable<string> textchanges) 
    {
      #region CodeContracts
      Contract.Requires(oldTree != null);
      Contract.Requires(newTree != null);
      Contract.Ensures(!Contract.Result<bool>() || Contract.ValueAtReturn<IEnumerable<string>>(out textchanges) != null);
      #endregion CodeContracts

      var workspace = MSBuildWorkspace.Create();
      oldTree = Formatter.Format(oldTree.GetRoot(), workspace).SyntaxTree;
      newTree = Formatter.Format(newTree.GetRoot(), workspace).SyntaxTree;
      textchanges = null;
      if (oldTree == newTree) 
      {
        return false;
      }
      var changes = newTree.GetChanges(oldTree);
      if (!changes.Any()) {
        return false;
      }
      textchanges = changes.Select(x => x.NewText.Trim());
      //textchanges = changes.Select(x => x.NewText.Trim());
      if (textchanges.All(x => x == ""))
      {
        return false;
      }
      return true;

    }