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)); }
/// <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); }
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)); }
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))); }
/// <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)); }