Exemplo n.º 1
0
        public async Task Handle_Resolve_TagHelperAttribute_ReturnsCompletionItemWithDocumentation()
        {
            // Arrange
            var lspDescriptionFactory = new Mock <LSPTagHelperTooltipFactory>(MockBehavior.Strict);
            var markdown = new MarkupContent
            {
                Kind  = MarkupKind.Markdown,
                Value = "Some Markdown"
            };

            lspDescriptionFactory.Setup(factory => factory.TryCreateTooltip(It.IsAny <AggregateBoundAttributeDescription>(), out markdown))
            .Returns(true);
            var languageServer = new Mock <ClientNotifierServiceBase>(MockBehavior.Strict);

            languageServer.Setup(ls => ls.ClientSettings).Returns(new InitializeParams());
            var completionEndpoint = new RazorCompletionEndpoint(
                Dispatcher, EmptyDocumentResolver, CompletionFactsService, lspDescriptionFactory.Object, VSLSPTagHelperTooltipFactory, languageServer.Object, LoggerFactory);
            var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute);

            razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty <BoundAttributeDescriptionInfo>()));
            var completionList = completionEndpoint.CreateLSPCompletionList(new[] { razorCompletionItem });
            var completionItem = completionList.Items.Single();

            // Act
            var newCompletionItem = await completionEndpoint.Handle(completionItem, default);

            // Assert
            Assert.NotNull(newCompletionItem.Documentation);
        }
        public void TryConvert_DirectiveAttribute_Snippet_ReturnsTrue()
        {
            // Arrange
            var completionItem = new RazorCompletionItem("@testDisplay...", "testInsert", RazorCompletionItemKind.DirectiveAttribute);

            completionItem.SetAttributeCompletionDescription(new AttributeCompletionDescription(new CodeAnalysis.Razor.Completion.AttributeDescriptionInfo[] {
                new CodeAnalysis.Razor.Completion.AttributeDescriptionInfo("System.String", "System.String", "@testDisplay", "This is docs")
            }));
            var descriptionFactory = new Mock <TagHelperDescriptionFactory>();
            var completionEndpoint = new RazorCompletionEndpoint(Dispatcher, EmptyDocumentResolver, CompletionFactsService, TagHelperCompletionService, descriptionFactory.Object, LoggerFactory);
            var capability         = new CompletionCapability {
                CompletionItem = new CompletionItemCapability {
                    SnippetSupport = true
                }
            };

            completionEndpoint.SetCapability(capability);
            var expectedInsert = "testInsert$1=\"$2\"$0";

            // Act
            var result = completionEndpoint.TryConvert(completionItem, out var converted);

            // Assert
            Assert.True(result);
            Assert.Equal(completionItem.DisplayText, converted.Label);
            Assert.Equal(expectedInsert, converted.InsertText);
            Assert.Equal(completionItem.InsertText, converted.FilterText);
            Assert.Equal(completionItem.InsertText, converted.SortText);
            Assert.Null(converted.Detail);
            Assert.Null(converted.Documentation);
            Assert.Null(converted.Command);
            Assert.True(converted.TryGetRazorCompletionKind(out var convertedKind));
            Assert.Equal(RazorCompletionItemKind.DirectiveAttribute, convertedKind);
        }
        public void TryConvert_DirectiveAttribute_ReturnsTrue()
        {
            // Arrange
            var completionItem = new RazorCompletionItem("@testDisplay", "testInsert", RazorCompletionItemKind.DirectiveAttribute, new [] { "=", ":" });

            completionItem.SetAttributeCompletionDescription(new AttributeCompletionDescription(Array.Empty <CodeAnalysis.Razor.Completion.AttributeDescriptionInfo>()));
            var descriptionFactory = new Mock <TagHelperDescriptionFactory>();
            var completionEndpoint = new RazorCompletionEndpoint(Dispatcher, EmptyDocumentResolver, CompletionFactsService, TagHelperCompletionService, descriptionFactory.Object, LoggerFactory);

            // Act
            var result = completionEndpoint.TryConvert(completionItem, out var converted);

            // Assert
            Assert.True(result);
            Assert.Equal(completionItem.DisplayText, converted.Label);
            Assert.Equal(completionItem.InsertText, converted.InsertText);
            Assert.Equal(completionItem.InsertText, converted.FilterText);
            Assert.Equal(completionItem.InsertText, converted.SortText);
            Assert.Equal(completionItem.CommitCharacters, converted.CommitCharacters);
            Assert.Null(converted.Detail);
            Assert.Null(converted.Documentation);
            Assert.Null(converted.Command);
            Assert.True(converted.TryGetRazorCompletionKind(out var convertedKind));
            Assert.Equal(RazorCompletionItemKind.DirectiveAttribute, convertedKind);
        }
        public async Task Handle_Resolve_TagHelperAttribute_ReturnsCompletionItemWithDocumentation()
        {
            // Arrange
            var lspDescriptionFactory = new Mock <LSPTagHelperTooltipFactory>(MockBehavior.Strict);
            var markdown = new MarkupContent
            {
                Kind  = MarkupKind.Markdown,
                Value = "Some Markdown"
            };

            lspDescriptionFactory.Setup(factory => factory.TryCreateTooltip(It.IsAny <AggregateBoundAttributeDescription>(), MarkupKind.Markdown, out markdown))
            .Returns(true);
            var endpoint = new RazorCompletionResolveEndpoint(lspDescriptionFactory.Object, VSLSPTagHelperTooltipFactory, CompletionListCache, LoggerFactory);

            endpoint.GetRegistration(DefaultClientCapability);
            var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute);

            razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty <BoundAttributeDescriptionInfo>()));
            var completionList = CreateLSPCompletionList(new[] { razorCompletionItem });
            var completionItem = completionList.Items.Single();
            var parameters     = ConvertToBridgedItem(completionItem);

            // Act
            var newCompletionItem = await endpoint.Handle(parameters, default);

            // Assert
            Assert.NotNull(newCompletionItem.Documentation);
        }
        public async Task Handle_Resolve_DirectiveAttributeParameterCompletion_ReturnsCompletionItemWithDocumentation()
        {
            // Arrange
            var descriptionFactory = new Mock <TagHelperTooltipFactory>(MockBehavior.Strict);
            var markdown           = new MarkupContent
            {
                Kind  = MarkupKind.Markdown,
                Value = "Some Markdown"
            };

            descriptionFactory.Setup(factory => factory.TryCreateTooltip(It.IsAny <AggregateBoundAttributeDescription>(), out markdown))
            .Returns(true);
            var completionEndpoint  = new RazorCompletionEndpoint(Dispatcher, EmptyDocumentResolver, CompletionFactsService, descriptionFactory.Object, LoggerFactory);
            var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter);

            razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty <BoundAttributeDescriptionInfo>()));
            var completionList = completionEndpoint.CreateLSPCompletionList(new[] { razorCompletionItem });
            var completionItem = completionList.Items.Single();

            // Act
            var newCompletionItem = await completionEndpoint.Handle(completionItem, default);

            // Assert
            Assert.NotNull(newCompletionItem.Documentation);
        }
        public void TryConvert_DirectiveAttributeParameter_ReturnsTrue()
        {
            // Arrange
            var completionItem = new RazorCompletionItem("format", "format", RazorCompletionItemKind.DirectiveAttributeParameter);

            completionItem.SetAttributeCompletionDescription(new AttributeCompletionDescription(Array.Empty <CodeAnalysis.Razor.Completion.AttributeDescriptionInfo>()));

            // Act
            var result = RazorCompletionEndpoint.TryConvert(completionItem, out var converted);

            // Assert
            Assert.True(result);
            Assert.Equal(completionItem.DisplayText, converted.Label);
            Assert.Equal(completionItem.InsertText, converted.InsertText);
            Assert.Equal(completionItem.InsertText, converted.FilterText);
            Assert.Equal(completionItem.InsertText, converted.SortText);
            Assert.Null(converted.Detail);
            Assert.Null(converted.Documentation);
            Assert.Null(converted.Command);
            Assert.True(converted.TryGetRazorCompletionKind(out var convertedKind));
            Assert.Equal(RazorCompletionItemKind.DirectiveAttributeParameter, convertedKind);
        }
Exemplo n.º 7
0
        public void TryConvert_TagHelperAttribute_ForHtml_ReturnsTrue()
        {
            // Arrange
            var completionItem = new RazorCompletionItem("format", "format=\"$0\"", RazorCompletionItemKind.TagHelperAttribute, isSnippet: true);
            var attributeCompletionDescription = new AggregateBoundAttributeDescription(new BoundAttributeDescriptionInfo[] { });

            completionItem.SetAttributeCompletionDescription(attributeCompletionDescription);

            // Act
            var result = RazorCompletionEndpoint.TryConvert(completionItem, ClientCapabilities, out var converted);

            // Assert
            Assert.True(result);
            Assert.Equal(completionItem.DisplayText, converted.Label);
            Assert.Equal("format=\"$0\"", converted.InsertText);
            Assert.Equal(InsertTextFormat.Snippet, converted.InsertTextFormat);
            Assert.Equal(completionItem.DisplayText, converted.FilterText);
            Assert.Equal(completionItem.DisplayText, converted.SortText);
            Assert.Null(converted.Detail);
            Assert.Null(converted.Documentation);
            Assert.Null(converted.Command);
        }
Exemplo n.º 8
0
        public void TryConvert_TagHelperAttribute_ForBool_ReturnsTrue()
        {
            // Arrange
            var completionItem = new RazorCompletionItem("format", "format", RazorCompletionItemKind.TagHelperAttribute);
            var attributeCompletionDescription = new AggregateBoundAttributeDescription(new[] {
                new BoundAttributeDescriptionInfo("System.Boolean", "Stuff", "format", "SomeDocs")
            });

            completionItem.SetAttributeCompletionDescription(attributeCompletionDescription);

            // Act
            var result = RazorCompletionEndpoint.TryConvert(completionItem, ClientCapabilities, out var converted);

            // Assert
            Assert.True(result);
            Assert.Equal(completionItem.DisplayText, converted.Label);
            Assert.Equal("format", converted.InsertText);
            Assert.Equal(InsertTextFormat.Plaintext, converted.InsertTextFormat);
            Assert.Equal(completionItem.InsertText, converted.FilterText);
            Assert.Equal(completionItem.InsertText, converted.SortText);
            Assert.Null(converted.Detail);
            Assert.Null(converted.Documentation);
            Assert.Null(converted.Command);
        }
        private IReadOnlyList <RazorCompletionItem> GetAttributeCompletions(
            SyntaxNode containingAttribute,
            string containingTagName,
            string?selectedAttributeName,
            IEnumerable <KeyValuePair <string, string> > attributes,
            TagHelperDocumentContext tagHelperDocumentContext)
        {
            var ancestors = containingAttribute.Parent.Ancestors();
            var nonDirectiveAttributeTagHelpers = tagHelperDocumentContext.TagHelpers.Where(tagHelper => !tagHelper.BoundAttributes.Any(attribute => attribute.IsDirectiveAttribute()));
            var filteredContext = TagHelperDocumentContext.Create(tagHelperDocumentContext.Prefix, nonDirectiveAttributeTagHelpers);

            var(ancestorTagName, ancestorIsTagHelper) = _tagHelperFactsService.GetNearestAncestorTagInfo(ancestors);
            var attributeCompletionContext = new AttributeCompletionContext(
                filteredContext,
                existingCompletions: Enumerable.Empty <string>(),
                containingTagName,
                selectedAttributeName,
                attributes,
                ancestorTagName,
                ancestorIsTagHelper,
                HtmlFactsService.IsHtmlTagName);

            var completionItems  = new List <RazorCompletionItem>();
            var completionResult = _tagHelperCompletionService.GetAttributeCompletions(attributeCompletionContext);

            foreach (var completion in completionResult.Completions)
            {
                var filterText = completion.Key;

                // This is a little bit of a hack because the information returned by _razorTagHelperCompletionService.GetAttributeCompletions
                // does not have enough information for us to determine if a completion is an indexer completion or not. Therefore we have to
                // jump through a few hoops below to:
                //   1. Determine if this specific completion is an indexer based completion
                //   2. Resolve an appropriate snippet if it is. This is more troublesome because we need to remove the ... suffix to accurately
                //      build a snippet that makes sense for the user to type.
                var indexerCompletion = filterText.EndsWith("...", StringComparison.Ordinal);
                if (indexerCompletion)
                {
                    filterText = filterText.Substring(0, filterText.Length - 3);
                }

                var attributeCommitCharacters = ResolveAttributeCommitCharacters(completion.Value, indexerCompletion);

                var razorCompletionItem = new RazorCompletionItem(
                    displayText: completion.Key,
                    insertText: filterText,
                    RazorCompletionItemKind.TagHelperAttribute,
                    attributeCommitCharacters);

                var attributeDescriptions = completion.Value.Select(boundAttribute =>
                {
                    var descriptionInfo = BoundAttributeDescriptionInfo.From(boundAttribute, indexerCompletion);

                    return(descriptionInfo);
                });
                var attributeDescriptionInfo = new AggregateBoundAttributeDescription(attributeDescriptions.ToList());
                razorCompletionItem.SetAttributeCompletionDescription(attributeDescriptionInfo);

                completionItems.Add(razorCompletionItem);
            }

            return(completionItems);
        }
Exemplo n.º 10
0
        private IReadOnlyList <RazorCompletionItem> GetAttributeCompletions(
            SyntaxNode containingAttribute,
            string containingTagName,
            string?selectedAttributeName,
            IEnumerable <KeyValuePair <string, string> > attributes,
            TagHelperDocumentContext tagHelperDocumentContext,
            RazorCompletionOptions options)
        {
            var ancestors = containingAttribute.Parent.Ancestors();
            var nonDirectiveAttributeTagHelpers = tagHelperDocumentContext.TagHelpers.Where(tagHelper => !tagHelper.BoundAttributes.Any(attribute => attribute.IsDirectiveAttribute()));
            var filteredContext = TagHelperDocumentContext.Create(tagHelperDocumentContext.Prefix, nonDirectiveAttributeTagHelpers);

            var(ancestorTagName, ancestorIsTagHelper) = _tagHelperFactsService.GetNearestAncestorTagInfo(ancestors);
            var attributeCompletionContext = new AttributeCompletionContext(
                filteredContext,
                existingCompletions: Enumerable.Empty <string>(),
                containingTagName,
                selectedAttributeName,
                attributes,
                ancestorTagName,
                ancestorIsTagHelper,
                HtmlFactsService.IsHtmlTagName);

            var completionItems  = new List <RazorCompletionItem>();
            var completionResult = _tagHelperCompletionService.GetAttributeCompletions(attributeCompletionContext);

            foreach (var completion in completionResult.Completions)
            {
                var filterText = completion.Key;

                // This is a little bit of a hack because the information returned by _razorTagHelperCompletionService.GetAttributeCompletions
                // does not have enough information for us to determine if a completion is an indexer completion or not. Therefore we have to
                // jump through a few hoops below to:
                //   1. Determine if this specific completion is an indexer based completion
                //   2. Resolve an appropriate snippet if it is. This is more troublesome because we need to remove the ... suffix to accurately
                //      build a snippet that makes sense for the user to type.
                var indexerCompletion = filterText.EndsWith("...", StringComparison.Ordinal);
                if (indexerCompletion)
                {
                    filterText = filterText.Substring(0, filterText.Length - 3);
                }

                var attributeContext          = ResolveAttributeContext(completion.Value, indexerCompletion, options.SnippetsSupported);
                var attributeCommitCharacters = ResolveAttributeCommitCharacters(attributeContext);
                var isSnippet  = false;
                var insertText = filterText;
                if (TryResolveInsertText(insertText, attributeContext, out var snippetText))
                {
                    isSnippet  = true;
                    insertText = snippetText;
                }

                // We change the sort text depending on the tag name due to TagHelper/non-TagHelper concerns. For instance lets say you have a TagHelper that binds to `input`.
                // Chances are you're expecting to get every other `input` completion item in addition to the TagHelper completion items and the sort order should be the default
                // because HTML completion items are 100% as applicable as other items.
                //
                // Next assume that we have a TagHelper that binds `custom` (or even `Custom`); this is a special scenario where the user has effectively created a new HTML tag
                // meaning they're probably expecting to provide all of the attributes necessary for that tag to operate. Meaning, HTML attribute completions are less important.
                // To make sure we prioritize our attribute completions above all other types of completions we set the priority to high so they're showed in the completion list
                // above all other completion items.
                var sortText            = HtmlFactsService.IsHtmlTagName(containingTagName) ? CompletionSortTextHelper.DefaultSortPriority : CompletionSortTextHelper.HighSortPriority;
                var razorCompletionItem = new RazorCompletionItem(
                    displayText: completion.Key,
                    insertText: insertText,
                    sortText: sortText,
                    kind: RazorCompletionItemKind.TagHelperAttribute,
                    commitCharacters: attributeCommitCharacters,
                    isSnippet: isSnippet);

                var attributeDescriptions = completion.Value.Select(boundAttribute =>
                {
                    var descriptionInfo = BoundAttributeDescriptionInfo.From(boundAttribute, indexerCompletion);

                    return(descriptionInfo);
                });
                var attributeDescriptionInfo = new AggregateBoundAttributeDescription(attributeDescriptions.ToList());
                razorCompletionItem.SetAttributeCompletionDescription(attributeDescriptionInfo);

                completionItems.Add(razorCompletionItem);
            }

            return(completionItems);
        }