Allow catch-all THDs to apply to all completions.
- Prior to this catch-alls were explicitly ignored not to populate the IntelliSense with an excess amount of `TagHelper`s. To maintain backwards compatible expectations this commit reverts that expectation. - Scoped an existing test to only test its primary scenario. - Added a new test to verify that catch-alls accurately apply to all completions (including dynamically added ones). #1219
This commit is contained in:
parent
cd486226d6
commit
46a5ca972f
|
|
@ -44,18 +44,20 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
_ => new HashSet<TagHelperDescriptor>(),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var catchAllDescriptors = new HashSet<TagHelperDescriptor>();
|
||||
var possibleChildDescriptors = _tagHelperFactsService.GetTagHelpersGivenParent(completionContext.DocumentContext, completionContext.ContainingTagName);
|
||||
foreach (var possibleDescriptor in possibleChildDescriptors)
|
||||
{
|
||||
var addRuleCompletions = false;
|
||||
var outputHint = possibleDescriptor.TagOutputHint;
|
||||
|
||||
// Filter out catch-all rules because TagHelpers that target attributes only would light up every child tag otherwise. Force those TagHelpers
|
||||
// to have additional requirements before showing them in the element completion list.
|
||||
var nonCatchAllRules = possibleDescriptor.TagMatchingRules.Where(rule => rule.TagName != TagHelperMatchingConventions.ElementCatchAllName);
|
||||
foreach (var rule in nonCatchAllRules)
|
||||
foreach (var rule in possibleDescriptor.TagMatchingRules)
|
||||
{
|
||||
if (elementCompletions.ContainsKey(rule.TagName))
|
||||
if (rule.TagName == TagHelperMatchingConventions.ElementCatchAllName)
|
||||
{
|
||||
catchAllDescriptors.Add(possibleDescriptor);
|
||||
}
|
||||
else if (elementCompletions.ContainsKey(rule.TagName))
|
||||
{
|
||||
addRuleCompletions = true;
|
||||
}
|
||||
|
|
@ -74,19 +76,35 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
|
||||
if (addRuleCompletions)
|
||||
{
|
||||
if (!elementCompletions.TryGetValue(rule.TagName, out var existingRuleDescriptors))
|
||||
{
|
||||
existingRuleDescriptors = new HashSet<TagHelperDescriptor>();
|
||||
elementCompletions[rule.TagName] = existingRuleDescriptors;
|
||||
}
|
||||
|
||||
existingRuleDescriptors.Add(possibleDescriptor);
|
||||
UpdateCompletions(rule.TagName, possibleDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We needed to track all catch-alls and update their completions after all other completions have been completed.
|
||||
// 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)
|
||||
{
|
||||
UpdateCompletions(completionTagNames, catchAllDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
var result = ElementCompletionResult.Create(elementCompletions);
|
||||
return result;
|
||||
|
||||
|
||||
void UpdateCompletions(string tagName, TagHelperDescriptor possibleDescriptor)
|
||||
{
|
||||
if (!elementCompletions.TryGetValue(tagName, out var existingRuleDescriptors))
|
||||
{
|
||||
existingRuleDescriptors = new HashSet<TagHelperDescriptor>();
|
||||
elementCompletions[tagName] = existingRuleDescriptors;
|
||||
}
|
||||
|
||||
existingRuleDescriptors.Add(possibleDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAllowedChildrenCompletions(
|
||||
|
|
|
|||
|
|
@ -10,6 +10,39 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
{
|
||||
public class DefaultTagHelperCompletionServiceTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetElementCompletions_CatchAllsApplyToAllCompletions()
|
||||
{
|
||||
// Arrange
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
TagHelperDescriptorBuilder.Create("SuperLiTagHelper", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("superli"))
|
||||
.Build(),
|
||||
TagHelperDescriptorBuilder.Create("CatchAll", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("*"))
|
||||
.Build(),
|
||||
};
|
||||
var expectedCompletions = ElementCompletionResult.Create(new Dictionary<string, HashSet<TagHelperDescriptor>>()
|
||||
{
|
||||
["superli"] = new HashSet<TagHelperDescriptor> { documentDescriptors[0], documentDescriptors[1] },
|
||||
["li"] = new HashSet<TagHelperDescriptor> { documentDescriptors[1] },
|
||||
});
|
||||
|
||||
var existingCompletions = new[] { "li" };
|
||||
var completionContext = BuildCompletionContext(
|
||||
documentDescriptors,
|
||||
existingCompletions,
|
||||
containingTagName: "ul");
|
||||
var service = CreateTagHelperCompletionFactsService();
|
||||
|
||||
// Act
|
||||
var completions = service.GetElementCompletions(completionContext);
|
||||
|
||||
// Assert
|
||||
AssertCompletionsAreEquivalent(expectedCompletions, completions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetElementCompletions_AllowsMultiTargetingTagHelpers()
|
||||
{
|
||||
|
|
@ -183,13 +216,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
.AllowChildTag("div")
|
||||
.Build(),
|
||||
};
|
||||
var expectedCompletions = ElementCompletionResult.Create(new Dictionary<string, HashSet<TagHelperDescriptor>>()
|
||||
{
|
||||
["p"] = new HashSet<TagHelperDescriptor>(),
|
||||
["em"] = new HashSet<TagHelperDescriptor>(),
|
||||
});
|
||||
var expectedCompletions = ElementCompletionResult.Create(new Dictionary<string, HashSet<TagHelperDescriptor>>());
|
||||
|
||||
var existingCompletions = new[] { "p", "em" };
|
||||
var existingCompletions = Enumerable.Empty<string>();
|
||||
var completionContext = BuildCompletionContext(
|
||||
documentDescriptors,
|
||||
existingCompletions,
|
||||
|
|
|
|||
Loading…
Reference in New Issue