Include currently selected attribute in TagHelper completion results

This commit is contained in:
Ajay Bhargav Baaskaran 2017-08-22 16:55:03 -07:00
parent 0c3fff3137
commit 9b6420dbfc
3 changed files with 113 additions and 2 deletions

View File

@ -13,6 +13,7 @@ namespace Microsoft.CodeAnalysis.Razor
TagHelperDocumentContext documentContext,
IEnumerable<string> existingCompletions,
string currentTagName,
string currentAttributeName,
IEnumerable<KeyValuePair<string, string>> attributes,
string currentParentTagName,
Func<string, bool> inHTMLSchema)
@ -45,6 +46,7 @@ namespace Microsoft.CodeAnalysis.Razor
DocumentContext = documentContext;
ExistingCompletions = existingCompletions;
CurrentTagName = currentTagName;
CurrentAttributeName = currentAttributeName;
Attributes = attributes;
CurrentParentTagName = currentParentTagName;
InHTMLSchema = inHTMLSchema;
@ -56,6 +58,8 @@ namespace Microsoft.CodeAnalysis.Razor
public string CurrentTagName { get; }
public string CurrentAttributeName { get; }
public IEnumerable<KeyValuePair<string, string>> Attributes { get; }
public string CurrentParentTagName { get; }

View File

@ -109,9 +109,12 @@ namespace Microsoft.CodeAnalysis.Razor
void UpdateCompletions(string attributeName, BoundAttributeDescriptor possibleDescriptor)
{
if (completionContext.Attributes.Any(attribute => string.Equals(attribute.Key, attributeName, StringComparison.OrdinalIgnoreCase)))
if (completionContext.Attributes.Any(attribute => string.Equals(attribute.Key, attributeName, StringComparison.OrdinalIgnoreCase)) &&
(completionContext.CurrentAttributeName == null ||
!string.Equals(attributeName, completionContext.CurrentAttributeName, StringComparison.OrdinalIgnoreCase)))
{
// Attribute is already present on this element it shouldn't exist in the completion list.
// Attribute is already present on this element and it is not the attribute in focus.
// It shouldn't exist in the completion list.
return;
}

View File

@ -61,6 +61,108 @@ namespace Microsoft.CodeAnalysis.Razor
AssertCompletionsAreEquivalent(expectedCompletions, completions);
}
[Fact]
public void GetAttributeCompletions_ReturnsCompletionForAlreadySuppliedAttribute_IfCurrentAttributeMatches()
{
// Arrange
var documentDescriptors = new[]
{
TagHelperDescriptorBuilder.Create("DivTagHelper", "TestAssembly")
.TagMatchingRuleDescriptor(rule => rule
.RequireTagName("div")
.RequireAttributeDescriptor(attribute => attribute.Name("repeat")))
.BoundAttributeDescriptor(attribute => attribute
.Name("visible")
.TypeName(typeof(bool).FullName)
.PropertyName("Visible"))
.Build(),
TagHelperDescriptorBuilder.Create("StyleTagHelper", "TestAssembly")
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("*"))
.BoundAttributeDescriptor(attribute => attribute
.Name("class")
.TypeName(typeof(string).FullName)
.PropertyName("Class"))
.Build(),
};
var expectedCompletions = AttributeCompletionResult.Create(new Dictionary<string, HashSet<BoundAttributeDescriptor>>()
{
["onclick"] = new HashSet<BoundAttributeDescriptor>(),
["visible"] = new HashSet<BoundAttributeDescriptor>()
{
documentDescriptors[0].BoundAttributes.Last()
}
});
var existingCompletions = new[] { "onclick" };
var completionContext = BuildAttributeCompletionContext(
documentDescriptors,
existingCompletions,
attributes: new Dictionary<string, string>()
{
["class"] = "something",
["repeat"] = "4",
["visible"] = "false",
},
currentTagName: "div",
currentAttributeName: "visible");
var service = CreateTagHelperCompletionFactsService();
// Act
var completions = service.GetAttributeCompletions(completionContext);
// Assert
AssertCompletionsAreEquivalent(expectedCompletions, completions);
}
[Fact]
public void GetAttributeCompletions_DoesNotReturnAlreadySuppliedAttribute_IfCurrentAttributeDoesNotMatch()
{
// Arrange
var documentDescriptors = new[]
{
TagHelperDescriptorBuilder.Create("DivTagHelper", "TestAssembly")
.TagMatchingRuleDescriptor(rule => rule
.RequireTagName("div")
.RequireAttributeDescriptor(attribute => attribute.Name("repeat")))
.BoundAttributeDescriptor(attribute => attribute
.Name("visible")
.TypeName(typeof(bool).FullName)
.PropertyName("Visible"))
.Build(),
TagHelperDescriptorBuilder.Create("StyleTagHelper", "TestAssembly")
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("*"))
.BoundAttributeDescriptor(attribute => attribute
.Name("class")
.TypeName(typeof(string).FullName)
.PropertyName("Class"))
.Build(),
};
var expectedCompletions = AttributeCompletionResult.Create(new Dictionary<string, HashSet<BoundAttributeDescriptor>>()
{
["onclick"] = new HashSet<BoundAttributeDescriptor>()
});
var existingCompletions = new[] { "onclick" };
var completionContext = BuildAttributeCompletionContext(
documentDescriptors,
existingCompletions,
attributes: new Dictionary<string, string>()
{
["class"] = "something",
["repeat"] = "4",
["visible"] = "false",
},
currentTagName: "div",
currentAttributeName: "repeat");
var service = CreateTagHelperCompletionFactsService();
// Act
var completions = service.GetAttributeCompletions(completionContext);
// Assert
AssertCompletionsAreEquivalent(expectedCompletions, completions);
}
[Fact]
public void GetAttributeCompletions_PossibleDescriptorsReturnUnboundRequiredAttributesWithExistingCompletions()
{
@ -947,6 +1049,7 @@ namespace Microsoft.CodeAnalysis.Razor
IEnumerable<TagHelperDescriptor> descriptors,
IEnumerable<string> existingCompletions,
string currentTagName,
string currentAttributeName = null,
IEnumerable<KeyValuePair<string, string>> attributes = null,
string tagHelperPrefix = "")
{
@ -956,6 +1059,7 @@ namespace Microsoft.CodeAnalysis.Razor
documentContext,
existingCompletions,
currentTagName,
currentAttributeName,
attributes,
currentParentTagName: "body",
inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div");