private async Task <Document> DetermineNewDocumentAsync(CompletionItem completionItem, SourceText sourceText, CancellationToken cancellationToken)
        {
            // The span we're going to replace
            var line = sourceText.Lines[MemberInsertionCompletionItem.GetLine(completionItem)];
            //var line = textSnapshot.GetLineFromLineNumber(MemberInsertionCompletionItem.GetLine(completionItem));

            //var sourceText = textSnapshot.AsText();
            var document = sourceText.GetOpenDocumentInCurrentContextWithChanges();

            Contract.ThrowIfNull(document);

            // Annotate the line we care about so we can find it after adding usings
            var tree          = document.GetSyntaxTreeAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var token         = GetToken(completionItem, tree, cancellationToken);
            var annotatedRoot = tree.GetRoot(cancellationToken).ReplaceToken(token, token.WithAdditionalAnnotations(_otherAnnotation));

            document = document.WithSyntaxRoot(annotatedRoot);

            var memberContainingDocument = await GenerateMemberAndUsingsAsync(document, completionItem, line, cancellationToken).ConfigureAwait(false);

            var insertionRoot = PrepareTreeForMemberInsertion(memberContainingDocument, cancellationToken);
            var insertionText = GenerateInsertionText(memberContainingDocument, cancellationToken);

            var destinationSpan = ComputeDestinationSpan(insertionRoot, insertionText);

            var finalText = insertionRoot.GetText(sourceText.Encoding).Replace(destinationSpan, insertionText.Trim());

            document = document.WithText(finalText);
            var newRoot     = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var declaration = GetSyntax(newRoot.FindToken(destinationSpan.End));

            document = document.WithSyntaxRoot(newRoot.ReplaceNode(declaration, declaration.WithAdditionalAnnotations(_annotation)));
            return(Formatter.FormatAsync(document, _annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken));
        }
Beispiel #2
0
        /// <summary>
        /// Tries to get the document corresponding to the text from the current partial solution
        /// associated with the text's container. If the document does not contain the exact text a document
        /// from a new solution containing the specified text is constructed. If no document is associated
        /// with the specified text's container, or the text's container isn't associated with a workspace,
        /// then the method returns false.
        /// </summary>
        internal static async Task <Document> GetDocumentWithFrozenPartialSemanticsAsync(this SourceText text, CancellationToken cancellationToken)
        {
            var document = text.GetOpenDocumentInCurrentContextWithChanges();

            if (document != null)
            {
                return(await document.WithFrozenPartialSemanticsAsync(cancellationToken).ConfigureAwait(false));
            }

            return(null);
        }
Beispiel #3
0
            public IEnumerable <ActiveStatementTextSpan> GetSpans(SourceText source)
            {
                var document = source.GetOpenDocumentInCurrentContextWithChanges();

                if (document == null)
                {
                    return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                }

                // We might be asked for spans in a different workspace than
                // the one we maintain tracking spans for (for example, a preview).
                if (document.Project.Solution.Workspace != _editSession.BaseSolution.Workspace)
                {
                    return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                }

                ITrackingSpan[] documentTrackingSpans;
                lock (_trackingSpans)
                {
                    if (!_trackingSpans.TryGetValue(document.Id, out documentTrackingSpans) || documentTrackingSpans == null)
                    {
                        return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                    }
                }

                Debug.Assert(documentTrackingSpans.Length > 0);
                var snapshot = source.FindCorrespondingEditorTextSnapshot();

                // The document might have been reopened with a new text buffer
                // and we haven't created tracking spans for the new text buffer yet.
                if (snapshot == null || snapshot.TextBuffer != documentTrackingSpans[0].TextBuffer)
                {
                    return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                }

                var baseStatements = _editSession.BaseActiveStatements[document.Id];

                Debug.Assert(documentTrackingSpans.Length == baseStatements.Length);

                var result = new ActiveStatementTextSpan[documentTrackingSpans.Length];

                for (int i = 0; i < documentTrackingSpans.Length; i++)
                {
                    Debug.Assert(documentTrackingSpans[i].TextBuffer == snapshot.TextBuffer);

                    result[i] = new ActiveStatementTextSpan(
                        baseStatements[i].Flags,
                        documentTrackingSpans[i].GetSpan(snapshot).Span.ToTextSpan());
                }

                return(result);
            }
        /// <summary>
        /// Returns true if the character recently inserted or deleted in the text should trigger completion.
        /// </summary>
        /// <param name="text">The document text to trigger completion within </param>
        /// <param name="caretPosition">The position of the caret after the triggering action.</param>
        /// <param name="trigger">The potential triggering action.</param>
        /// <param name="roles">Optional set of roles associated with the editor state.</param>
        /// <param name="options">Optional options that override the default options.</param>
        /// <remarks>
        /// This API uses SourceText instead of Document so implementations can only be based on text, not syntax or semantics.
        /// </remarks>
        public bool ShouldTriggerCompletion(
            SourceText text,
            int caretPosition,
            CompletionTrigger trigger,
            ImmutableHashSet <string>?roles = null,
            OptionSet?options = null)
        {
            var document         = text.GetOpenDocumentInCurrentContextWithChanges();
            var languageServices = document?.Project.LanguageServices ?? _services.GetLanguageServices(Language);

            // Publicly available options do not affect this API.
            var completionOptions  = CompletionOptions.Default;
            var passThroughOptions = options ?? document?.Project.Solution.Options ?? OptionValueSet.Empty;

            return(ShouldTriggerCompletion(document?.Project, languageServices, text, caretPosition, trigger, completionOptions, passThroughOptions, roles));
        }
Beispiel #5
0
        public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
        {
            foreach (var language in GetLanguageProviders(text => text.GetOpenDocumentInCurrentContextWithChanges(), text))
            {
                var completionProvider = (language as IEmbeddedLanguageFeatures)?.CompletionProvider;
                if (completionProvider != null)
                {
                    if (completionProvider.ShouldTriggerCompletion(
                            text, caretPosition, trigger, options))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        public override bool ShouldTriggerCompletion(
            SourceText text, int caretPosition, CompletionTrigger trigger, ImmutableHashSet <string> roles = null, OptionSet options = null)
        {
            options ??= _workspace.Options;
            if (!options.GetOption(CompletionOptions.TriggerOnTyping, Language))
            {
                return(false);
            }

            if (trigger.Kind == CompletionTriggerKind.Deletion && SupportsTriggerOnDeletion(options))
            {
                return(Char.IsLetterOrDigit(trigger.Character) || trigger.Character == '.');
            }

            var document  = text.GetOpenDocumentInCurrentContextWithChanges();
            var providers = GetFilteredProviders(document, roles, trigger, options);

            return(providers.Any(p => p.ShouldTriggerCompletion(text, caretPosition, trigger, options)));
        }
Beispiel #7
0
        /// <summary>
        /// Tries to get the document corresponding to the text from the current partial solution
        /// associated with the text's container. If the document does not contain the exact text a document
        /// from a new solution containing the specified text is constructed. If no document is associated
        /// with the specified text's container, or the text's container isn't associated with a workspace,
        /// then the method returns false.
        /// </summary>
        internal static Document GetDocumentWithFrozenPartialSemantics(this SourceText text, CancellationToken cancellationToken)
        {
            var document = text.GetOpenDocumentInCurrentContextWithChanges();

            return(document?.WithFrozenPartialSemantics(cancellationToken));
        }