public CompletionListUpdater( IAsyncCompletionSession session, AsyncCompletionSessionDataSnapshot data, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions) { _session = session; _data = data; _recentItemsManager = recentItemsManager; _filterText = _session.ApplicableToSpan.GetText(_data.Snapshot); if (!_session.Properties.TryGetProperty(CompletionSource.HasSuggestionItemOptions, out bool hasSuggestedItemOptions)) { // This is the scenario when the session is created out of Roslyn, in some other provider, e.g. in Debugger. // For now, the default hasSuggestedItemOptions is false. hasSuggestedItemOptions = false; } _hasSuggestedItemOptions = hasSuggestedItemOptions || _data.DisplaySuggestionItem; // We prefer using the original snapshot, which should always be available from items provided by Roslyn's CompletionSource. // Only use data.Snapshot in the theoretically possible but rare case when all items we are handling are from some non-Roslyn CompletionSource. var snapshotForDocument = TryGetInitialTriggerLocation(_data, out var intialTriggerLocation) ? intialTriggerLocation.Snapshot : _data.Snapshot; _document = snapshotForDocument?.TextBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(); if (_document != null) { _completionService = _document.GetLanguageService <CompletionService>(); _completionRules = _completionService?.GetRules(CompletionOptions.From(_document.Project)) ?? CompletionRules.Default; // Let us make the completion Helper used for non-Roslyn items case-sensitive. // We can change this if get requests from partner teams. _completionHelper = CompletionHelper.GetHelper(_document); _filterMethod = _completionService == null ? ((itemsWithPatternMatches, text) => CompletionService.FilterItems(_completionHelper, itemsWithPatternMatches, text)) : ((itemsWithPatternMatches, text) => _completionService.FilterItems(_document, itemsWithPatternMatches, text)); // Nothing to highlight if user hasn't typed anything yet. _highlightMatchingPortions = _filterText.Length > 0 && globalOptions.GetOption(CompletionViewOptions.HighlightMatchingPortionsOfCompletionListItems, _document.Project.Language); _showCompletionItemFilters = globalOptions.GetOption(CompletionViewOptions.ShowCompletionItemFilters, _document.Project.Language); } else { _completionService = null; _completionRules = CompletionRules.Default; // Let us make the completion Helper used for non-Roslyn items case-sensitive. // We can change this if get requests from partner teams. _completionHelper = new CompletionHelper(isCaseSensitive: true); _filterMethod = (itemsWithPatternMatches, text) => CompletionService.FilterItems(_completionHelper, itemsWithPatternMatches, text); _highlightMatchingPortions = false; _showCompletionItemFilters = true; } }
public async Task GettingCompletionListShoudNotRunSourceGenerator(bool forkBeforeFreeze) { var sourceMarkup = @" using System; namespace N { public class C1 { $$ } }"; MarkupTestFile.GetPosition(sourceMarkup.NormalizeLineEndings(), out var source, out int?position); var generatorRanCount = 0; var generator = new CallbackGenerator(onInit: _ => { }, onExecute: _ => Interlocked.Increment(ref generatorRanCount)); using var workspace = WorkspaceTestUtilities.CreateWorkspaceWithPartialSemantics(); var analyzerReference = new TestGeneratorReference(generator); var project = SolutionUtilities.AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddDocument("Document1.cs", sourceMarkup, filePath: "Document1.cs").Project; Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); var compeltionService = document.GetLanguageService <CompletionService>(); Assert.Equal(0, generatorRanCount); if (forkBeforeFreeze) { // Forking before freezing means we'll have to do extra work to produce the final compilation, // but we should still not be running generators. document = document.WithText(SourceText.From(sourceMarkup.Replace("C1", "C2"))); } // We want to make sure import completion providers are also participating. var options = CompletionOptions.From(document.Project.Solution.Options, document.Project.Language); var newOptions = options with { ShowItemsFromUnimportedNamespaces = true }; var(completionList, _) = await compeltionService.GetCompletionsInternalAsync(document, position.Value, options : newOptions); // We expect completion to run on frozen partial semantic, which won't run source generator. Assert.Equal(0, generatorRanCount); var expectedItem = forkBeforeFreeze ? "C2" : "C1"; Assert.True(completionList.Items.Select(item => item.DisplayText).Contains(expectedItem)); } }
private async Task CreateSpellCheckCodeIssueAsync( CodeFixContext context, SyntaxToken nameToken, bool isGeneric, CancellationToken cancellationToken) { var document = context.Document; var service = CompletionService.GetService(document); // Disable snippets and unimported types from ever appearing in the completion items. // - It's very unlikely the user would ever misspell a snippet, then use spell-checking to fix it, // then try to invoke the snippet. // - We believe spell-check should only compare what you have typed to what symbol would be offered here. var options = CompletionOptions.From(document.Project.Solution.Options, document.Project.Language) with { SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, IsExpandedCompletion = false, TargetTypedCompletionFilter = false }; var(completionList, _) = await service.GetCompletionsInternalAsync( document, nameToken.SpanStart, options, cancellationToken : cancellationToken).ConfigureAwait(false); if (completionList == null) { return; } var nameText = nameToken.ValueText; var similarityChecker = WordSimilarityChecker.Allocate(nameText, substringsAreSimilar: true); try { await CheckItemsAsync( context, nameToken, isGeneric, completionList, similarityChecker).ConfigureAwait(false); } finally { similarityChecker.Free(); } }
public async Task <LSP.CompletionItem> HandleRequestAsync(LSP.CompletionItem completionItem, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; Contract.ThrowIfNull(document); var completionService = document.Project.LanguageServices.GetRequiredService <CompletionService>(); var cacheEntry = GetCompletionListCacheEntry(completionItem); if (cacheEntry == null) { // Don't have a cache associated with this completion item, cannot resolve. context.TraceInformation("No cache entry found for the provided completion item at resolve time."); return(completionItem); } var list = cacheEntry.CompletionList; // Find the matching completion item in the completion list var selectedItem = list.Items.FirstOrDefault(cachedCompletionItem => MatchesLSPCompletionItem(completionItem, cachedCompletionItem)); if (selectedItem == null) { return(completionItem); } var options = CompletionOptions.From(document.Project); var displayOptions = SymbolDescriptionOptions.From(document.Project); var description = await completionService.GetDescriptionAsync(document, selectedItem, options, displayOptions, cancellationToken).ConfigureAwait(false) !; if (description != null) { var supportsVSExtensions = context.ClientCapabilities.HasVisualStudioLspCapability(); if (supportsVSExtensions) { var vsCompletionItem = (LSP.VSInternalCompletionItem)completionItem; vsCompletionItem.Description = new ClassifiedTextElement(description.TaggedParts .Select(tp => new ClassifiedTextRun(tp.Tag.ToClassificationTypeName(), tp.Text))); } else { var clientSupportsMarkdown = context.ClientCapabilities.TextDocument?.Completion?.CompletionItem?.DocumentationFormat.Contains(LSP.MarkupKind.Markdown) == true; completionItem.Documentation = ProtocolConversions.GetDocumentationMarkupContent(description.TaggedParts, document, clientSupportsMarkdown); } } // We compute the TextEdit resolves for complex text edits (e.g. override and partial // method completions) here. Lazily resolving TextEdits is technically a violation of // the LSP spec, but is currently supported by the VS client anyway. Once the VS client // adheres to the spec, this logic will need to change and VS will need to provide // official support for TextEdit resolution in some form. if (selectedItem.IsComplexTextEdit) { Contract.ThrowIfTrue(completionItem.InsertText != null); Contract.ThrowIfTrue(completionItem.TextEdit != null); var snippetsSupported = context.ClientCapabilities.TextDocument?.Completion?.CompletionItem?.SnippetSupport ?? false; completionItem.TextEdit = await GenerateTextEditAsync( document, completionService, selectedItem, snippetsSupported, cancellationToken).ConfigureAwait(false); } return(completionItem); }