Example #1
0
            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();
            }
        }
Example #4
0
        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);
        }