public async Task <object> HandleAsync(LSP.TextDocumentPositionParams request, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var document = _solutionProvider.GetDocument(request.TextDocument);

            if (document == null)
            {
                return(Array.Empty <LSP.Location>());
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var locations = await GetDefinitionsWithFindUsagesServiceAsync(document, position, cancellationToken).ConfigureAwait(false);

            // No definition found - see if we can get metadata as source but that's only applicable for C#\VB.
            if ((locations.Length == 0) && document.SupportsSemanticModel && this._metadataAsSourceService != null)
            {
                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (symbol?.Locations.FirstOrDefault().IsInMetadata == true)
                {
                    var declarationFile = await this._metadataAsSourceService.GetGeneratedFileAsync(document.Project, symbol, false, cancellationToken).ConfigureAwait(false);

                    var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
                    return(new LSP.Location[]
                    {
                        new LSP.Location {
                            Uri = new Uri(declarationFile.FilePath), Range = ProtocolConversions.LinePositionToRange(linePosSpan)
                        }
                    });
                }
            }

            return(locations.ToArray());
        }
示例#2
0
        public override async Task <CompletionList?> HandleRequestAsync(CompletionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            if (request.Context is VSInternalCompletionContext completionContext && completionContext.InvokeKind == VSInternalCompletionInvokeKind.Deletion)
            {
                // Don't trigger completions on backspace.
                return(null);
            }

            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var completionService = document.Project.LanguageServices.GetRequiredService <IXamlCompletionService>();
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var offset           = text.Lines.GetPosition(ProtocolConversions.PositionToLinePosition(request.Position));
            var completionResult = await completionService.GetCompletionsAsync(new XamlCompletionContext(document, offset, request.Context?.TriggerCharacter?.FirstOrDefault() ?? '\0'), cancellationToken : cancellationToken).ConfigureAwait(false);

            if (completionResult?.Completions == null)
            {
                return(null);
            }

            var commitCharactersCache = new Dictionary <XamlCompletionKind, ImmutableArray <VSInternalCommitCharacter> >();

            return(new VSInternalCompletionList
            {
                Items = completionResult.Completions.Select(c => CreateCompletionItem(c, document.Id, text, request.Position, request.TextDocument, commitCharactersCache)).ToArray(),
                SuggestionMode = false,
            });
        }
示例#3
0
        public override async Task <Hover?> HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var quickInfoService = document.Project.LanguageServices.GetRequiredService <QuickInfoService>();
            var info             = await quickInfoService.GetQuickInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (info == null)
            {
                return(null);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            // TODO - Switch to markup content once it supports classifications.
            // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/918138
            return(new VSHover
            {
                Range = ProtocolConversions.TextSpanToRange(info.Span, text),
                Contents = new SumType <SumType <string, MarkedString>, SumType <string, MarkedString>[], MarkupContent>(string.Empty),
                // Build the classified text without navigation actions - they are not serializable.
                RawContent = await IntellisenseQuickInfoBuilder.BuildContentWithoutNavigationActionsAsync(info, document, cancellationToken).ConfigureAwait(false)
            });
        }
示例#4
0
        public override async Task <LSP.ReferenceItem[]?> HandleRequestAsync(ReferenceParams referenceParams, RequestContext context, CancellationToken cancellationToken)
        {
            Debug.Assert(context.ClientCapabilities.HasVisualStudioLspCapability());

            var document = context.Document;

            if (document == null)
            {
                return(Array.Empty <LSP.VSReferenceItem>());
            }

            using var progress = BufferedProgress.Create <VSReferenceItem>(referenceParams.PartialResultToken);

            var findUsagesService = document.GetRequiredLanguageService <IFindUsagesLSPService>();
            var position          = await document.GetPositionFromLinePositionAsync(
                ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false);

            var findUsagesContext = new FindUsagesLSPContext(
                progress, document, position, _metadataAsSourceFileService, cancellationToken);

            // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client.
            await findUsagesService.FindReferencesAsync(document, position, findUsagesContext).ConfigureAwait(false);

            await findUsagesContext.OnCompletedAsync().ConfigureAwait(false);

            return(progress.GetValues());
        }
        public override async Task <LSP.VSReferenceItem[]> HandleRequestAsync(
            ReferenceParams referenceParams,
            ClientCapabilities clientCapabilities,
            string?clientName,
            CancellationToken cancellationToken)
        {
            Debug.Assert(clientCapabilities.HasVisualStudioLspCapability());

            var document = SolutionProvider.GetDocument(referenceParams.TextDocument, clientName);

            if (document == null)
            {
                return(Array.Empty <LSP.VSReferenceItem>());
            }

            var findUsagesService = document.GetRequiredLanguageService <IFindUsagesLSPService>();
            var position          = await document.GetPositionFromLinePositionAsync(
                ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false);

            var context = new FindUsagesLSPContext(document, position, _metadataAsSourceFileService, cancellationToken);

            // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client.
            // TODO: Change back FAR to use streaming once the following LSP bug is fixed:
            // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1094786/
            await findUsagesService.FindReferencesAsync(document, position, context).ConfigureAwait(false);

            return(context.GetReferences().ToArray());
        }
    public override async Task <VSInternalInlineCompletionList?> HandleRequestAsync(VSInternalInlineCompletionRequest request, RequestContext context, CancellationToken cancellationToken)
    {
        Contract.ThrowIfNull(context.Document);

        // First get available snippets if any.
        var snippetInfoService = context.Document.Project.GetRequiredLanguageService <ISnippetInfoService>();
        var snippetInfo        = snippetInfoService.GetSnippetsIfAvailable();

        if (!snippetInfo.Any())
        {
            return(null);
        }

        // Then attempt to get the word at the requested position.
        var sourceText = await context.Document.GetTextAsync(cancellationToken).ConfigureAwait(false);

        var syntaxFactsService = context.Document.Project.GetRequiredLanguageService <ISyntaxFactsService>();
        var linePosition       = ProtocolConversions.PositionToLinePosition(request.Position);
        var position           = sourceText.Lines.GetPosition(linePosition);

        if (!SnippetUtilities.TryGetWordOnLeft(position, sourceText, syntaxFactsService, out var wordOnLeft))
        {
            return(null);
        }

        // Find the snippet with shortcut text that matches the typed word.
        var wordText = sourceText.GetSubText(wordOnLeft.Value).ToString();

        if (!BuiltInSnippets.Contains(wordText, StringComparer.OrdinalIgnoreCase))
        {
            return(null);
        }

        var matchingSnippetInfo = snippetInfo.First(s => wordText.Equals(s.Shortcut, StringComparison.OrdinalIgnoreCase));

        var parsedSnippet = _xmlSnippetParser.GetParsedXmlSnippet(matchingSnippetInfo, context);

        if (parsedSnippet == null)
        {
            return(null);
        }

        // Use the formatting options specified by the client to format the snippet.
        var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, context.Document, cancellationToken).ConfigureAwait(false);

        var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, formattingOptions, cancellationToken).ConfigureAwait(false);

        return(new VSInternalInlineCompletionList
        {
            Items = new VSInternalInlineCompletionItem[]
            {
                new VSInternalInlineCompletionItem
                {
                    Range = ProtocolConversions.TextSpanToRange(wordOnLeft.Value, sourceText),
                    Text = formattedLspSnippet,
                    TextFormat = InsertTextFormat.Snippet,
                }
            }
        });
    }
示例#7
0
        public override async Task <CompletionList?> HandleRequestAsync(CompletionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var completionService = document.Project.LanguageServices.GetRequiredService <IXamlCompletionService>();
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var offset           = text.Lines.GetPosition(ProtocolConversions.PositionToLinePosition(request.Position));
            var completionResult = await completionService.GetCompletionsAsync(new XamlCompletionContext(document, offset, request.Context?.TriggerCharacter?.FirstOrDefault() ?? '\0'), cancellationToken : cancellationToken).ConfigureAwait(false);

            if (completionResult?.Completions == null)
            {
                return(null);
            }

            return(new VSCompletionList
            {
                Items = completionResult.Completions.Select(c => CreateCompletionItem(c, document.Id, text, request.Position)).ToArray(),
                SuggestionMode = false,
            });
        }
        public async Task <DocumentHighlight[]> HandleRequestAsync(Solution solution, TextDocumentPositionParams request,
                                                                   ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            var document = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document == null)
            {
                return(Array.Empty <DocumentHighlight>());
            }

            var documentHighlightService = document.Project.LanguageServices.GetService <IDocumentHighlightsService>();
            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var highlights = await documentHighlightService.GetDocumentHighlightsAsync(
                document,
                position,
                ImmutableHashSet.Create(document),
                cancellationToken).ConfigureAwait(false);

            if (!highlights.IsDefaultOrEmpty)
            {
                // LSP requests are only for a single document. So just get the highlights for the requested document.
                var highlightsForDocument = highlights.FirstOrDefault(h => h.Document.Id == document.Id);
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                return(highlightsForDocument.HighlightSpans.Select(h => new DocumentHighlight
                {
                    Range = ProtocolConversions.TextSpanToRange(h.TextSpan, text),
                    Kind = ProtocolConversions.HighlightSpanKindToDocumentHighlightKind(h.Kind),
                }).ToArray());
            }

            return(Array.Empty <DocumentHighlight>());
        }
        public override async Task <DocumentHighlight[]?> HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            // First check if this is a keyword that needs highlighting.
            var keywordHighlights = await GetKeywordHighlightsAsync(document, text, position, cancellationToken).ConfigureAwait(false);

            if (keywordHighlights.Any())
            {
                return(keywordHighlights.ToArray());
            }

            // Not a keyword, check if it is a reference that needs highlighting.
            var referenceHighlights = await GetReferenceHighlightsAsync(document, text, position, cancellationToken).ConfigureAwait(false);

            if (referenceHighlights.Any())
            {
                return(referenceHighlights.ToArray());
            }

            // No keyword or references to highlight at this location.
            return(Array.Empty <DocumentHighlight>());
        }
示例#10
0
        public async Task <Hover> HandleRequestAsync(Solution solution, TextDocumentPositionParams request,
                                                     ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            var document = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document == null)
            {
                return(null);
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var quickInfoService = document.Project.LanguageServices.GetService <QuickInfoService>();
            var info             = await quickInfoService.GetQuickInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (info == null)
            {
                return(null);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            return(new Hover
            {
                Range = ProtocolConversions.TextSpanToRange(info.Span, text),
                Contents = new MarkupContent
                {
                    Kind = MarkupKind.Markdown,
                    Value = GetMarkdownString(info)
                }
            });
示例#11
0
        public override async Task <TextEdit[]> HandleRequestAsync(DocumentOnTypeFormattingParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var edits = new ArrayBuilder <TextEdit>();

            if (string.IsNullOrEmpty(request.Character))
            {
                return(edits.ToArrayAndFree());
            }

            var document          = context.Document;
            var formattingService = document?.Project.LanguageServices.GetService <IXamlFormattingService>();

            if (document != null && formattingService != null)
            {
                var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                var options = new XamlFormattingOptions {
                    InsertSpaces = request.Options.InsertSpaces, TabSize = request.Options.TabSize, OtherOptions = request.Options.OtherOptions
                };
                var textChanges = await formattingService.GetFormattingChangesAsync(document, options, request.Character[0], position, cancellationToken).ConfigureAwait(false);

                if (textChanges != null)
                {
                    var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
                }
            }

            return(edits.ToArrayAndFree());
        }
示例#12
0
        public override async Task <LSP.CompletionItem[]> HandleRequestAsync(LSP.CompletionParams request, LSP.ClientCapabilities clientCapabilities, string?clientName,
                                                                             CancellationToken cancellationToken)
        {
            var document = SolutionProvider.GetDocument(request.TextDocument, clientName);

            if (document == null)
            {
                return(Array.Empty <LSP.CompletionItem>());
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            // Filter out unimported types for now as there are two issues with providing them:
            // 1.  LSP client does not currently provide a way to provide detail text on the completion item to show the namespace.
            //     https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1076759
            // 2.  We need to figure out how to provide the text edits along with the completion item or provide them in the resolve request.
            //     https://devdiv.visualstudio.com/DevDiv/_workitems/edit/985860/
            // 3.  LSP client should support completion filters / expanders
            var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var completionOptions = documentOptions
                                    .WithChangedOption(CompletionOptions.ShowItemsFromUnimportedNamespaces, false)
                                    .WithChangedOption(CompletionServiceOptions.IsExpandedCompletion, false);

            var completionService = document.Project.LanguageServices.GetRequiredService <CompletionService>();
            var list = await completionService.GetCompletionsAsync(document, position, options : completionOptions, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (list == null)
            {
                return(Array.Empty <LSP.CompletionItem>());
            }

            var lspVSClientCapability = clientCapabilities?.HasVisualStudioLspCapability() == true;

            return(list.Items.Select(item => CreateLSPCompletionItem(request, item, lspVSClientCapability)).ToArray());
        public override async Task <LSP.VSReferenceItem[]> HandleRequestAsync(ReferenceParams referenceParams, RequestContext context, CancellationToken cancellationToken)
        {
            Debug.Assert(context.ClientCapabilities.HasVisualStudioLspCapability());

            var document = SolutionProvider.GetDocument(referenceParams.TextDocument, context.ClientName);

            if (document == null)
            {
                return(Array.Empty <LSP.VSReferenceItem>());
            }

            var findUsagesService = document.GetRequiredLanguageService <IFindUsagesLSPService>();
            var position          = await document.GetPositionFromLinePositionAsync(
                ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false);

            var findUsagesContext = new FindUsagesLSPContext(
                referenceParams.PartialResultToken, document, position, _metadataAsSourceFileService, cancellationToken);

            // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client.
            await findUsagesService.FindReferencesAsync(document, position, findUsagesContext).ConfigureAwait(false);

            await findUsagesContext.OnCompletedAsync().ConfigureAwait(false);

            // The results have already been reported to the client, so we don't need to return anything here.
            return(Array.Empty <LSP.VSReferenceItem>());
        }
示例#14
0
        public override async Task <LSP.Location[]> HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            Contract.ThrowIfNull(document);

            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var findUsagesService = document.GetRequiredLanguageService <IFindUsagesService>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var findUsagesContext = new SimpleFindUsagesContext();

            await FindImplementationsAsync(findUsagesService, document, position, findUsagesContext, cancellationToken).ConfigureAwait(false);

            foreach (var definition in findUsagesContext.GetDefinitions())
            {
                var text = definition.GetClassifiedText();
                foreach (var sourceSpan in definition.SourceSpans)
                {
                    if (context.ClientCapabilities?.HasVisualStudioLspCapability() == true)
                    {
                        locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false));
                    }
                    else
                    {
                        locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationAsync(sourceSpan, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            return(locations.ToArrayAndFree());
        }
示例#15
0
        public async Task <object[]> HandleAsync(LSP.ReferenceParams request, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var solution = requestContext.Context;
            var document = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document == null)
            {
                return(locations.ToArrayAndFree());
            }

            var findUsagesService = document.Project.LanguageServices.GetService <IFindUsagesService>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var context = new SimpleFindUsagesContext(cancellationToken);

            // Roslyn calls into third party extensions to compute reference results and needs to be on the UI thread to compute results.
            // This is not great for us and ideally we should ask for a Roslyn API where we can make this call without blocking the UI.
            if (VsTaskLibraryHelper.ServiceInstance != null)
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
            }

            await findUsagesService.FindReferencesAsync(document, position, context).ConfigureAwait(false);

            if (requestContext?.ClientCapabilities?.HasVisualStudioLspCapability() == true)
            {
                return(await GetReferenceGroupsAsync(request, context, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                return(await GetLocationsAsync(request, context, cancellationToken).ConfigureAwait(false));
            }
        }
示例#16
0
        public override async Task <LSP.CompletionItem> HandleRequestAsync(LSP.CompletionItem completionItem, RequestContext context, CancellationToken cancellationToken)
        {
            CompletionResolveData data;

            if (completionItem.Data is CompletionResolveData)
            {
                data = (CompletionResolveData)completionItem.Data;
            }
            else
            {
                data = ((JToken)completionItem.Data).ToObject <CompletionResolveData>();
            }

            var document = SolutionProvider.GetDocument(data.TextDocument, context.ClientName);

            if (document == null)
            {
                return(completionItem);
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(data.Position), cancellationToken).ConfigureAwait(false);

            var completionService = document.Project.LanguageServices.GetRequiredService <CompletionService>();
            var list = await completionService.GetCompletionsAsync(document, position, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (list == null)
            {
                return(completionItem);
            }

            var selectedItem = list.Items.FirstOrDefault(i => i.DisplayText == data.DisplayText);

            if (selectedItem == null)
            {
                return(completionItem);
            }

            var description = await completionService.GetDescriptionAsync(document, selectedItem, cancellationToken).ConfigureAwait(false);

            var lspVSClientCapability = context.ClientCapabilities?.HasVisualStudioLspCapability() == true;

            LSP.CompletionItem resolvedCompletionItem;
            if (lspVSClientCapability)
            {
                resolvedCompletionItem = CloneVSCompletionItem(completionItem);
                ((LSP.VSCompletionItem)resolvedCompletionItem).Description = new ClassifiedTextElement(description.TaggedParts
                                                                                                       .Select(tp => new ClassifiedTextRun(tp.Tag.ToClassificationTypeName(), tp.Text)));
            }
            else
            {
                resolvedCompletionItem = RoslynCompletionItem.From(completionItem);
                ((RoslynCompletionItem)resolvedCompletionItem).Description = description.TaggedParts.Select(
                    tp => new RoslynTaggedText {
                    Tag = tp.Tag, Text = tp.Text
                }).ToArray();
            }

            resolvedCompletionItem.Detail = description.TaggedParts.GetFullText();
            return(resolvedCompletionItem);
        }
        private static async Task <LSP.VSInternalDocumentOnAutoInsertResponseItem?> GetDocumentationCommentResponseAsync(
            LSP.VSInternalDocumentOnAutoInsertParams autoInsertParams,
            Document document,
            IDocumentationCommentSnippetService service,
            DocumentationCommentOptions options,
            CancellationToken cancellationToken)
        {
            var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var linePosition = ProtocolConversions.PositionToLinePosition(autoInsertParams.Position);
            var position     = sourceText.Lines.GetPosition(linePosition);

            var result = autoInsertParams.Character == "\n"
                ? service.GetDocumentationCommentSnippetOnEnterTyped(syntaxTree, sourceText, position, options, cancellationToken)
                : service.GetDocumentationCommentSnippetOnCharacterTyped(syntaxTree, sourceText, position, options, cancellationToken);

            if (result == null)
            {
                return(null);
            }

            return(new LSP.VSInternalDocumentOnAutoInsertResponseItem
            {
                TextEditFormat = LSP.InsertTextFormat.Snippet,
                TextEdit = new LSP.TextEdit
                {
                    NewText = result.SnippetText.Insert(result.CaretOffset, "$0"),
                    Range = ProtocolConversions.TextSpanToRange(result.SpanToReplace, sourceText)
                }
            });
        }
示例#18
0
        public async Task <LSP.CompletionItem> HandleRequestAsync(LSP.CompletionItem completionItem, RequestContext context, CancellationToken cancellationToken)
        {
            if (!(completionItem.Data is CompletionResolveData data))
            {
                data = ((JToken)completionItem.Data).ToObject <CompletionResolveData>();
            }

            var documentId = DocumentId.CreateFromSerialized(ProjectId.CreateFromSerialized(data.ProjectGuid), data.DocumentGuid);
            var document   = context.Solution.GetAdditionalDocument(documentId);

            if (document == null)
            {
                return(completionItem);
            }

            int offset = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(data.Position), cancellationToken).ConfigureAwait(false);

            var completionService = document.Project.LanguageServices.GetRequiredService <IXamlCompletionService>();
            var symbol            = await completionService.GetSymbolAsync(new XamlCompletionContext(document, offset), completionItem.Label, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (symbol == null)
            {
                return(completionItem);
            }

            var description = await symbol.GetDescriptionAsync(document, offset, cancellationToken).ConfigureAwait(false);

            var vsCompletionItem = CloneVSCompletionItem(completionItem);

            vsCompletionItem.Description = new ClassifiedTextElement(description.Select(tp => new ClassifiedTextRun(tp.Tag.ToClassificationTypeName(), tp.Text)));
            return(vsCompletionItem);
        }
示例#19
0
        public override async Task <LinkedEditingRanges?> HandleRequestAsync(LinkedEditingRangeParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var renameService = document.Project.LanguageServices.GetService <IXamlTypeRenameService>();

            if (renameService == null)
            {
                return(null);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var offset = text.Lines.GetPosition(ProtocolConversions.PositionToLinePosition(request.Position));

            var result = await renameService.GetTypeRenameAsync(document, offset, cancellationToken).ConfigureAwait(false);

            if (result == null)
            {
                return(null);
            }

            Contract.ThrowIfTrue(result.Ranges.IsDefault);

            return(new LinkedEditingRanges
            {
                Ranges = result.Ranges.Select(s => ProtocolConversions.TextSpanToRange(s, text)).ToArray(),
                WordPattern = result.WordPattern
            });
        }
示例#20
0
        protected static async Task <LSP.VSCompletionItem> CreateCompletionItemAsync(
            string label,
            LSP.CompletionItemKind kind,
            string[] tags,
            LSP.CompletionParams request,
            Document document,
            bool preselect = false,
            ImmutableArray <char>?commitCharacters = null,
            LSP.TextEdit?textEdit = null,
            string?insertText     = null,
            string?sortText       = null,
            string?filterText     = null,
            long resultId         = 0
            )
        {
            var position = await document
                           .GetPositionFromLinePositionAsync(
                ProtocolConversions.PositionToLinePosition(request.Position),
                CancellationToken.None
                )
                           .ConfigureAwait(false);

            var completionTrigger = await ProtocolConversions
                                    .LSPToRoslynCompletionTriggerAsync(
                request.Context,
                document,
                position,
                CancellationToken.None
                )
                                    .ConfigureAwait(false);

            var item = new LSP.VSCompletionItem()
            {
                TextEdit         = textEdit,
                InsertText       = insertText,
                FilterText       = filterText ?? label,
                Label            = label,
                SortText         = sortText ?? label,
                InsertTextFormat = LSP.InsertTextFormat.Plaintext,
                Kind             = kind,
                Data             = JObject.FromObject(new CompletionResolveData()
                {
                    ResultId = resultId,
                }),
                Preselect = preselect
            };

            if (tags != null)
            {
                item.Icon = tags.ToImmutableArray().GetFirstGlyph().GetImageElement();
            }

            if (commitCharacters != null)
            {
                item.CommitCharacters = commitCharacters.Value.Select(c => c.ToString()).ToArray();
            }

            return(item);
        }
        protected async Task <LSP.Location[]> GetDefinitionAsync(Solution solution, LSP.TextDocumentPositionParams request, bool typeOnly, CancellationToken cancellationToken)
        {
            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var document = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document == null)
            {
                return(locations.ToArrayAndFree());
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var definitionService = document.Project.LanguageServices.GetService <IGoToDefinitionService>();
            var definitions       = await definitionService.FindDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (definitions != null && definitions.Count() > 0)
            {
                foreach (var definition in definitions)
                {
                    if (!ShouldInclude(definition, typeOnly))
                    {
                        continue;
                    }

                    var definitionText = await definition.Document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    locations.Add(new LSP.Location
                    {
                        Uri   = definition.Document.GetURI(),
                        Range = ProtocolConversions.TextSpanToRange(definition.SourceSpan, definitionText),
                    });
                }
            }
            else if (document.SupportsSemanticModel && _metadataAsSourceFileService != null)
            {
                // No definition found - see if we can get metadata as source but that's only applicable for C#\VB.
                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (symbol != null && symbol.Locations != null && !symbol.Locations.IsEmpty && symbol.Locations.First().IsInMetadata)
                {
                    if (!typeOnly || symbol is ITypeSymbol)
                    {
                        var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, false, cancellationToken).ConfigureAwait(false);

                        var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
                        locations.Add(new LSP.Location
                        {
                            Uri   = new Uri(declarationFile.FilePath),
                            Range = ProtocolConversions.LinePositionToRange(linePosSpan),
                        });
                    }
                }
            }

            return(locations.ToArrayAndFree());
示例#22
0
        public async Task <Hover?> HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var quickInfoService = document.Project.LanguageServices.GetService <IXamlQuickInfoService>();

            if (quickInfoService == null)
            {
                return(null);
            }

            var info = await quickInfoService.GetQuickInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (info == null)
            {
                return(null);
            }

            var descriptionBuilder = new List <TaggedText>(info.Description);

            if (info.Symbol != null)
            {
                var options     = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language);
                var description = await info.Symbol.GetDescriptionAsync(document, options, cancellationToken).ConfigureAwait(false);

                if (description.Any())
                {
                    if (descriptionBuilder.Any())
                    {
                        descriptionBuilder.AddLineBreak();
                    }

                    descriptionBuilder.AddRange(description);
                }
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            return(new VSInternalHover
            {
                Range = ProtocolConversions.TextSpanToRange(info.Span, text),
                Contents = new MarkupContent
                {
                    Kind = MarkupKind.Markdown,
                    Value = GetMarkdownString(descriptionBuilder)
                },
                RawContent = new ClassifiedTextElement(descriptionBuilder.Select(tp => new ClassifiedTextRun(tp.Tag.ToClassificationTypeName(), tp.Text)))
            });
        protected async Task <LSP.Location[]?> GetDefinitionAsync(LSP.TextDocumentPositionParams request, bool typeOnly, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var findDefinitionService = document.GetRequiredLanguageService <IFindDefinitionService>();

            var definitions = await findDefinitionService.FindDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (definitions.Any())
            {
                foreach (var definition in definitions)
                {
                    if (!ShouldInclude(definition, typeOnly))
                    {
                        continue;
                    }

                    var location = await ProtocolConversions.TextSpanToLocationAsync(
                        definition.Document, definition.SourceSpan, definition.IsStale, cancellationToken).ConfigureAwait(false);

                    locations.AddIfNotNull(location);
                }
            }
            else if (document.SupportsSemanticModel && _metadataAsSourceFileService != null)
            {
                // No definition found - see if we can get metadata as source but that's only applicable for C#\VB.
                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (symbol != null && _metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol))
                {
                    if (!typeOnly || symbol is ITypeSymbol)
                    {
                        var options         = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices);
                        var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly : false, options, cancellationToken).ConfigureAwait(false);

                        var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
                        locations.Add(new LSP.Location
                        {
                            Uri   = new Uri(declarationFile.FilePath),
                            Range = ProtocolConversions.LinePositionToRange(linePosSpan),
                        });
                    }
                }
            }

            return(locations.ToArrayAndFree());
示例#24
0
        public override async Task <DocumentOnAutoInsertResponseItem?> HandleRequestAsync(
            DocumentOnAutoInsertParams request,
            RequestContext context,
            CancellationToken cancellationToken
            )
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var insertService =
                document.Project.LanguageServices.GetService <IXamlAutoInsertService>();

            if (insertService == null)
            {
                return(null);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var offset = text.Lines.GetPosition(
                ProtocolConversions.PositionToLinePosition(request.Position)
                );
            var result = await insertService
                         .GetAutoInsertAsync(document, request.Character[0], offset, cancellationToken)
                         .ConfigureAwait(false);

            if (result == null)
            {
                return(null);
            }

            Contract.ThrowIfNull(result.TextChange.NewText);
            var insertText   = result.TextChange.NewText;
            var insertFormat = InsertTextFormat.Plaintext;

            if (result.CaretOffset.HasValue)
            {
                insertFormat = InsertTextFormat.Snippet;
                insertText   = insertText.Insert(result.CaretOffset.Value, "$0");
            }

            return(new DocumentOnAutoInsertResponseItem
            {
                TextEditFormat = insertFormat,
                TextEdit = new TextEdit
                {
                    NewText = insertText,
                    Range = ProtocolConversions.TextSpanToRange(result.TextChange.Span, text)
                }
            });
        }
示例#25
0
        public async Task <WorkspaceEdit> HandleRequestAsync(Solution solution, RenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            WorkspaceEdit workspaceEdit = null;
            var           document      = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document != null)
            {
                var renameService = document.Project.LanguageServices.GetService <IEditorInlineRenameService>();
                var position      = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (!renameInfo.CanRename)
                {
                    return(workspaceEdit);
                }

                var renameLocationSet = await renameInfo.FindRenameLocationsAsync(solution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, solution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var newSolution      = renameReplacementInfo.NewSolution;
                var solutionChanges  = newSolution.GetChanges(solution);
                var changedDocuments = solutionChanges
                                       .GetProjectChanges()
                                       .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true));

                var documentEdits = new ArrayBuilder <TextDocumentEdit>();
                foreach (var docId in changedDocuments)
                {
                    var oldDoc = solution.GetDocument(docId);
                    var newDoc = newSolution.GetDocument(docId);

                    var textChanges = await newDoc.GetTextChangesAsync(oldDoc, cancellationToken).ConfigureAwait(false);

                    var oldText = await oldDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var textDocumentEdit = new TextDocumentEdit
                    {
                        TextDocument = new VersionedTextDocumentIdentifier {
                            Uri = newDoc.GetURI()
                        },
                        Edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray()
                    };
                    documentEdits.Add(textDocumentEdit);
                }

                workspaceEdit = new WorkspaceEdit {
                    DocumentChanges = documentEdits.ToArrayAndFree()
                };
            }

            return(workspaceEdit);
        }
示例#26
0
        public async Task <LSP.DocumentOnAutoInsertResponseItem[]> HandleRequestAsync(LSP.DocumentOnAutoInsertParams autoInsertParams, RequestContext context, CancellationToken cancellationToken)
        {
            using var _ = ArrayBuilder <LSP.DocumentOnAutoInsertResponseItem> .GetInstance(out var response);

            var document = context.Document;

            if (document == null)
            {
                return(response.ToArray());
            }

            var insertService = document.Project.LanguageServices.GetService <IXamlAutoInsertService>();

            if (insertService == null)
            {
                return(response.ToArray());
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var offset = text.Lines.GetPosition(ProtocolConversions.PositionToLinePosition(autoInsertParams.Position));
            var result = await insertService.GetAutoInsertAsync(document, autoInsertParams.Character[0], offset, cancellationToken).ConfigureAwait(false);

            if (result == null)
            {
                return(response.ToArray());
            }

            Contract.ThrowIfNull(result.TextChange.NewText);
            var insertText   = result.TextChange.NewText;
            var insertFormat = LSP.InsertTextFormat.Plaintext;

            if (result.CaretOffset.HasValue)
            {
                insertFormat = LSP.InsertTextFormat.Snippet;
                insertText   = insertText.Insert(result.CaretOffset.Value, "$0");
            }

            response.Add(new LSP.DocumentOnAutoInsertResponseItem
            {
                TextEditFormat = insertFormat,
                TextEdit       = new LSP.TextEdit
                {
                    NewText = insertText,
                    Range   = ProtocolConversions.TextSpanToRange(result.TextChange.Span, text)
                }
            });

            return(response.ToArray());
        }
示例#27
0
        public override async Task <LSP.DocumentOnAutoInsertResponseItem[]> HandleRequestAsync(LSP.DocumentOnAutoInsertParams autoInsertParams, RequestContext context, CancellationToken cancellationToken)
        {
            using var _ = ArrayBuilder <LSP.DocumentOnAutoInsertResponseItem> .GetInstance(out var response);

            var document = SolutionProvider.GetDocument(autoInsertParams.TextDocument, context.ClientName);

            if (document == null)
            {
                return(response.ToArray());
            }

            var service = document.GetRequiredLanguageService <IDocumentationCommentSnippetService>();

            // The editor calls this handler for C# and VB comment characters, but we only need to process the one for the language that matches the document
            if (autoInsertParams.Character != "\n" && autoInsertParams.Character != service.DocumentationCommentCharacter)
            {
                return(response.ToArray());
            }

            var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var linePosition = ProtocolConversions.PositionToLinePosition(autoInsertParams.Position);
            var position     = sourceText.Lines.GetPosition(linePosition);

            var result = autoInsertParams.Character == "\n"
                ? service.GetDocumentationCommentSnippetOnEnterTyped(syntaxTree, sourceText, position, options, cancellationToken)
                : service.GetDocumentationCommentSnippetOnCharacterTyped(syntaxTree, sourceText, position, options, cancellationToken);

            if (result == null)
            {
                return(response.ToArray());
            }

            response.Add(new LSP.DocumentOnAutoInsertResponseItem
            {
                TextEditFormat = LSP.InsertTextFormat.Snippet,
                TextEdit       = new LSP.TextEdit
                {
                    NewText = result.SnippetText.Insert(result.CaretOffset, "$0"),
                    Range   = ProtocolConversions.TextSpanToRange(result.SpanToReplace, sourceText)
                }
            });

            return(response.ToArray());
        }
示例#28
0
        public async Task <WorkspaceEdit?> HandleRequestAsync(RenameParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            Contract.ThrowIfNull(document);

            var oldSolution   = document.Project.Solution;
            var renameService = document.Project.LanguageServices.GetRequiredService <IEditorInlineRenameService>();
            var position      = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (!renameInfo.CanRename)
            {
                return(null);
            }

            var options = new SymbolRenameOptions(
                RenameOverloads: false,
                RenameInStrings: false,
                RenameInComments: false,
                RenameFile: false);

            var renameLocationSet = await renameInfo.FindRenameLocationsAsync(options, cancellationToken).ConfigureAwait(false);

            var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, options, cancellationToken).ConfigureAwait(false);

            var renamedSolution = renameReplacementInfo.NewSolution;
            var solutionChanges = renamedSolution.GetChanges(oldSolution);

            // Linked files can correspond to multiple roslyn documents each with changes.  Merge the changes in the linked files so that all linked documents have the same text.
            // Then we can just take the text changes from the first document to avoid returning duplicate edits.
            renamedSolution = await renamedSolution.WithMergedLinkedFileChangesAsync(oldSolution, solutionChanges, cancellationToken : cancellationToken).ConfigureAwait(false);

            solutionChanges = renamedSolution.GetChanges(oldSolution);
            var changedDocuments = solutionChanges
                                   .GetProjectChanges()
                                   .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true))
                                   .GroupBy(docId => renamedSolution.GetRequiredDocument(docId).FilePath, StringComparer.OrdinalIgnoreCase).Select(group => group.First());

            var textDiffService = renamedSolution.Services.GetRequiredService <IDocumentTextDifferencingService>();

            var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution.GetRequiredDocument, oldSolution.GetRequiredDocument,
                                                                                                   textDiffService, cancellationToken).ConfigureAwait(false);

            return(new WorkspaceEdit {
                DocumentChanges = documentEdits
            });
        }
示例#29
0
        protected static string ApplyTextEdits(LSP.TextEdit[] edits, SourceText originalMarkup)
        {
            var text = originalMarkup;

            foreach (var edit in edits)
            {
                var lines         = text.Lines;
                var startPosition = ProtocolConversions.PositionToLinePosition(edit.Range.Start);
                var endPosition   = ProtocolConversions.PositionToLinePosition(edit.Range.End);
                var textSpan      = lines.GetTextSpan(new LinePositionSpan(startPosition, endPosition));
                text = text.Replace(textSpan, edit.NewText);
            }

            return(text.ToString());
        }
示例#30
0
        public override async Task <TextEdit[]?> HandleRequestAsync(
            DocumentOnTypeFormattingParams request,
            RequestContext context,
            CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var edits = new ArrayBuilder <TextEdit>();

            var formattingService = document.Project.LanguageServices.GetRequiredService <IFormattingInteractionService>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            if (string.IsNullOrEmpty(request.Character))
            {
                return(edits.ToArrayAndFree());
            }

            // We should use the options passed in by LSP instead of the document's options.
            var documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync(
                request.Options, document, cancellationToken).ConfigureAwait(false);

            IList <TextChange>?textChanges;

            if (SyntaxFacts.IsNewLine(request.Character[0]))
            {
                textChanges = await GetFormattingChangesOnReturnAsync(
                    formattingService, document, position, documentOptions, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                textChanges = await GetFormattingChangesAsync(
                    formattingService, document, request.Character[0], position, documentOptions, cancellationToken).ConfigureAwait(false);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            if (textChanges != null)
            {
                edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
            }

            return(edits.ToArrayAndFree());
        }