public CompletionListUpdater( ITrackingSpan applicableToSpan, CompletionSessionData sessionData, AsyncCompletionSessionDataSnapshot snapshotData, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions) { _sessionData = sessionData; _snapshotData = snapshotData; _recentItemsManager = recentItemsManager; _applicableToSpan = applicableToSpan; _filterText = applicableToSpan.GetText(_snapshotData.Snapshot); _hasSuggestedItemOptions = _sessionData.HasSuggestionItemOptions || _snapshotData.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(_snapshotData, out var intialTriggerLocation) ? intialTriggerLocation.Snapshot : _snapshotData.Snapshot; _document = snapshotForDocument?.TextBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(); if (_document != null) { _completionService = _document.GetLanguageService <CompletionService>(); _completionRules = _completionService?.GetRules(globalOptions.GetCompletionOptions(_document.Project.Language)) ?? 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 <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 completionOptions = _globalOptions.GetCompletionOptions(document.Project.Language); var displayOptions = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language); var description = await completionService.GetDescriptionAsync(document, selectedItem, completionOptions, 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); }