diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs index 01c43fdfb4..a2d7941879 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs @@ -45,6 +45,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor StringComparer.OrdinalIgnoreCase); var catchAllDescriptors = new HashSet(); + var prefix = completionContext.DocumentContext.Prefix ?? string.Empty; var possibleChildDescriptors = _tagHelperFactsService.GetTagHelpersGivenParent(completionContext.DocumentContext, completionContext.ContainingTagName); foreach (var possibleDescriptor in possibleChildDescriptors) { @@ -76,7 +77,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor if (addRuleCompletions) { - UpdateCompletions(rule.TagName, possibleDescriptor); + UpdateCompletions(prefix + rule.TagName, possibleDescriptor); } } } @@ -85,16 +86,18 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor // This way, any TagHelper added completions will also have catch-alls listed under their entries. foreach (var catchAllDescriptor in catchAllDescriptors) { - foreach (var completionTagNames in elementCompletions.Keys) + foreach (var completionTagName in elementCompletions.Keys) { - UpdateCompletions(completionTagNames, catchAllDescriptor); + if (completionTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + UpdateCompletions(completionTagName, catchAllDescriptor); + } } } var result = ElementCompletionResult.Create(elementCompletions); return result; - void UpdateCompletions(string tagName, TagHelperDescriptor possibleDescriptor) { if (!elementCompletions.TryGetValue(tagName, out var existingRuleDescriptors)) diff --git a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs index 0ec524fa09..0dbc538240 100644 --- a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs +++ b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs @@ -10,6 +10,75 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor { public class DefaultTagHelperCompletionServiceTest { + [Fact] + public void GetElementCompletions_CatchAllsOnlyApplyToCompletionsStartingWithPrefix() + { + // Arrange + var documentDescriptors = new[] + { + TagHelperDescriptorBuilder.Create("CatchAllTagHelper", "TestAssembly") + .TagMatchingRule(rule => rule.RequireTagName("*")) + .Build(), + TagHelperDescriptorBuilder.Create("LiTagHelper", "TestAssembly") + .TagMatchingRule(rule => rule.RequireTagName("li")) + .Build(), + }; + var expectedCompletions = ElementCompletionResult.Create(new Dictionary>() + { + ["th:li"] = new HashSet { documentDescriptors[1], documentDescriptors[0] }, + ["li"] = new HashSet(), + }); + + var existingCompletions = new[] { "li" }; + var completionContext = BuildCompletionContext( + documentDescriptors, + existingCompletions, + containingTagName: "ul", + tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); + + // Act + var completions = service.GetElementCompletions(completionContext); + + // Assert + AssertCompletionsAreEquivalent(expectedCompletions, completions); + } + + [Fact] + public void GetElementCompletions_TagHelperPrefixIsPrependedToTagHelperCompletions() + { + // Arrange + var documentDescriptors = new[] + { + TagHelperDescriptorBuilder.Create("SuperLiTagHelper", "TestAssembly") + .TagMatchingRule(rule => rule.RequireTagName("superli")) + .Build(), + TagHelperDescriptorBuilder.Create("LiTagHelper", "TestAssembly") + .TagMatchingRule(rule => rule.RequireTagName("li")) + .Build(), + }; + var expectedCompletions = ElementCompletionResult.Create(new Dictionary>() + { + ["th:superli"] = new HashSet { documentDescriptors[0] }, + ["th:li"] = new HashSet { documentDescriptors[1] }, + ["li"] = new HashSet(), + }); + + var existingCompletions = new[] { "li" }; + var completionContext = BuildCompletionContext( + documentDescriptors, + existingCompletions, + containingTagName: "ul", + tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); + + // Act + var completions = service.GetElementCompletions(completionContext); + + // Assert + AssertCompletionsAreEquivalent(expectedCompletions, completions); + } + [Fact] public void GetElementCompletions_CatchAllsApplyToAllCompletions() { @@ -382,9 +451,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor IEnumerable descriptors, IEnumerable existingCompletions, string containingTagName, - string containingParentTagName = "body") + string containingParentTagName = "body", + string tagHelperPrefix = "") { - var documentContext = TagHelperDocumentContext.Create(string.Empty, descriptors); + var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); var completionContext = new ElementCompletionContext( documentContext, existingCompletions,