Esempio n. 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;
                }
        }
Esempio n. 2
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(FunctionId.Workspace_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
                    if (this.SupportsSyntaxTree)
                    {
                        var tree = await this.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                        var oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                        return tree.GetChanges(oldTree);
                    }

                    text = await this.GetTextAsync(cancellationToken).ConfigureAwait(false);
                    oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    return text.GetTextChanges(oldText).ToList();
                }
            }
            catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
        /// <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(FunctionId.Workspace_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
                    if (this.SupportsSyntaxTree)
                    {
                        var tree = await this.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                        var oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                        return tree.GetChanges(oldTree);
                    }

                    text = await this.GetTextAsync(cancellationToken).ConfigureAwait(false);
                    oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    return text.GetTextChanges(oldText).ToList();
                }
            }
            catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }

        /// <summary>
        /// Gets the list of <see cref="DocumentId"/>s that are linked to this
        /// <see cref="Document" />. <see cref="Document"/>s are considered to be linked if they
        /// share the same <see cref="TextDocument.FilePath" />. This <see cref="DocumentId"/> is excluded from the 
        /// result.
        /// </summary>
        public ImmutableArray<DocumentId> GetLinkedDocumentIds()
        {
            var documentIdsWithPath = this.Project.Solution.GetDocumentIdsWithFilePath(this.FilePath);
            return documentIdsWithPath.Remove(this.Id);
        }
Esempio n. 4
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
                    if (this.SupportsSyntaxTree)
                    {
                        var tree = await this.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                        var oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                        return tree.GetChanges(oldTree);
                    }

                    text = await this.GetTextAsync(cancellationToken).ConfigureAwait(false);
                    oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    return text.GetTextChanges(oldText).ToList();
                }
            }
            catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }

        /// <summary>
        /// Creates a branched version of this document that has its semantic model frozen in whatever state it is available at the time,
        /// assuming a background process is constructing the semantics asynchronously. Repeated calls to this method may return
        /// documents with increasingly more complete semantics.
        /// 
        /// Use this method to gain access to potentially incomplete semantics quickly.
        /// </summary>
        internal async Task<Document> WithFrozenPartialSemanticsAsync(CancellationToken cancellationToken)
        {
            var solution = this.Project.Solution;
            var workspace = solution.Workspace;

            // only produce doc with frozen semantics if this document is part of the workspace's 
            // primary branch and there is actual background compilation going on, since w/o 
            // background compilation the semantics won't be moving toward completeness.  Also,
            // ensure that the project that this document is part of actually supports compilations,
            // as partial semantics don't make sense otherwise.
            if (solution.BranchId == workspace.PrimaryBranchId &&
                workspace.PartialSemanticsEnabled &&
                this.Project.SupportsCompilation)
            {
                var newSolution = await this.Project.Solution.WithFrozenPartialCompilationIncludingSpecificDocumentAsync(this.Id, cancellationToken).ConfigureAwait(false);
                return newSolution.GetDocument(this.Id);
            }
            else
            {
                return this;
            }
        }