Add line mappings to project TagHelper attribute values.
- We now create LineMappings for instances where a TagHelper's attribute value is not of a string type. - This will enable the Razor editor to create projections from .cshtml => .cs for TagHelper attributes. - Modified the TagHelperCodeGenerator and TagHelperBlockBuiler to accurately track the attribute values start locations so it could flow into code generation. - Modified existing tests to account for the new line mappings. #207
This commit is contained in:
parent
ceaf257cd5
commit
a86b0dca3e
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||
{
|
||||
|
|
@ -265,7 +266,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
|
||||
// We aren't a bufferable attribute which means we have no Razor code in our value.
|
||||
// Therefore we can just use the "textValue" as the attribute value.
|
||||
RenderRawAttributeValue(textValue, attributeDescriptor);
|
||||
RenderRawAttributeValue(textValue, attributeValueChunk.Start, attributeDescriptor);
|
||||
}
|
||||
|
||||
// End the assignment to the attribute.
|
||||
|
|
@ -421,13 +422,25 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
});
|
||||
}
|
||||
|
||||
private void RenderRawAttributeValue(string value, TagHelperAttributeDescriptor attributeDescriptor)
|
||||
private void RenderRawAttributeValue(string value,
|
||||
SourceLocation documentLocation,
|
||||
TagHelperAttributeDescriptor attributeDescriptor)
|
||||
{
|
||||
RenderAttributeValue(
|
||||
attributeDescriptor,
|
||||
valueRenderer: (writer) =>
|
||||
{
|
||||
writer.Write(value);
|
||||
if (_context.Host.DesignTimeMode)
|
||||
{
|
||||
using (new CSharpLineMappingWriter(writer, documentLocation, value.Length))
|
||||
{
|
||||
writer.Write(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Razor.Generator.Compiler;
|
||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNet.Razor.Parser.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Generator
|
||||
{
|
||||
|
|
@ -60,10 +62,12 @@ namespace Microsoft.AspNet.Razor.Generator
|
|||
attribute.Value.Accept(codeGenerator);
|
||||
|
||||
var chunks = codeGenerator.Context.CodeTreeBuilder.CodeTree.Chunks;
|
||||
var first = chunks.FirstOrDefault();
|
||||
|
||||
attributes[attribute.Key] = new ChunkBlock
|
||||
{
|
||||
Children = chunks
|
||||
Children = chunks,
|
||||
Start = first == null ? SourceLocation.Zero : first.Start
|
||||
};
|
||||
|
||||
// Reset the code tree builder so we can build a new one for the next attribute
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
|
|||
Kind = span.Kind
|
||||
};
|
||||
var htmlSymbols = span.Symbols.OfType<HtmlSymbol>().ToArray();
|
||||
var capturedAttributeValueStart = false;
|
||||
var attributeValueStartLocation = span.Start;
|
||||
var symbolOffset = 1;
|
||||
string name = null;
|
||||
|
||||
|
|
@ -175,13 +177,24 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
|
|||
{
|
||||
var symbol = htmlSymbols[i];
|
||||
|
||||
if (name == null && symbol.Type == HtmlSymbolType.Text)
|
||||
if (afterEquals)
|
||||
{
|
||||
// When symbols are accepted into SpanBuilders, their locations get altered to be offset by the
|
||||
// parent which is why we need to mark our start location prior to adding the symbol.
|
||||
// This is needed to know the location of the attribute value start within the document.
|
||||
if (!capturedAttributeValueStart)
|
||||
{
|
||||
capturedAttributeValueStart = true;
|
||||
|
||||
attributeValueStartLocation = span.Start + symbol.Start;
|
||||
}
|
||||
|
||||
builder.Accept(symbol);
|
||||
}
|
||||
else if (name == null && symbol.Type == HtmlSymbolType.Text)
|
||||
{
|
||||
name = symbol.Content;
|
||||
}
|
||||
else if (afterEquals)
|
||||
{
|
||||
builder.Accept(symbol);
|
||||
attributeValueStartLocation = SourceLocation.Advance(span.Start, name);
|
||||
}
|
||||
else if (symbol.Type == HtmlSymbolType.Equals)
|
||||
{
|
||||
|
|
@ -193,22 +206,36 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
|
|||
// TODO: Handle malformed tags, if there's an '=' then there MUST be a value.
|
||||
// https://github.com/aspnet/Razor/issues/104
|
||||
|
||||
SourceLocation symbolStartLocation;
|
||||
|
||||
// Check for attribute start values, aka single or double quote
|
||||
if (IsQuote(htmlSymbols[i + 1]))
|
||||
{
|
||||
// Move past the attribute start so we can accept the true value.
|
||||
i++;
|
||||
symbolStartLocation = htmlSymbols[i + 1].Start;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbolStartLocation = symbol.Start;
|
||||
|
||||
// Set the symbol offset to 0 so we don't attempt to skip an end quote that doesn't exist.
|
||||
symbolOffset = 0;
|
||||
}
|
||||
|
||||
attributeValueStartLocation = symbolStartLocation +
|
||||
span.Start +
|
||||
new SourceLocation(absoluteIndex: 1,
|
||||
lineIndex: 0,
|
||||
characterIndex: 1);
|
||||
afterEquals = true;
|
||||
}
|
||||
}
|
||||
|
||||
// After all symbols have been added we need to set the builders start position so we do not indirectly
|
||||
// modify each symbol's Start location.
|
||||
builder.Start = attributeValueStartLocation;
|
||||
|
||||
return CreateMarkupAttribute(name, builder, attributeValueTypes);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,14 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
|||
generatedAbsoluteIndex: 475,
|
||||
generatedLineIndex: 15,
|
||||
characterOffsetIndex: 14,
|
||||
contentLength: 11)
|
||||
contentLength: 11),
|
||||
BuildLineMapping(documentAbsoluteIndex: 57,
|
||||
documentLineIndex: 2,
|
||||
documentCharacterOffsetIndex: 28,
|
||||
generatedAbsoluteIndex: 927,
|
||||
generatedLineIndex: 33,
|
||||
generatedCharacterOffsetIndex: 31,
|
||||
contentLength: 4)
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -188,7 +195,14 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
|||
generatedAbsoluteIndex: 475,
|
||||
generatedLineIndex: 15,
|
||||
characterOffsetIndex: 14,
|
||||
contentLength: 11)
|
||||
contentLength: 11),
|
||||
BuildLineMapping(documentAbsoluteIndex: 189,
|
||||
documentLineIndex: 6,
|
||||
documentCharacterOffsetIndex: 40,
|
||||
generatedAbsoluteIndex: 1599,
|
||||
generatedLineIndex: 44,
|
||||
generatedCharacterOffsetIndex: 40,
|
||||
contentLength: 4)
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -218,6 +232,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
|||
BuildLineMapping(218, 9, 13, 1356, 56, 12, 27),
|
||||
BuildLineMapping(346, 12, 1754, 68, 0, 48),
|
||||
BuildLineMapping(440, 15, 46, 2004, 78, 6, 8),
|
||||
BuildLineMapping(457, 15, 63, 2267, 85, 40, 4),
|
||||
BuildLineMapping(501, 16, 31, 2384, 88, 6, 30),
|
||||
BuildLineMapping(568, 17, 30, 2733, 97, 0, 10),
|
||||
BuildLineMapping(601, 17, 63, 2815, 103, 0, 8),
|
||||
|
|
|
|||
Loading…
Reference in New Issue