diff --git a/src/Microsoft.AspNet.Razor/Chunks/Generators/AddOrRemoveTagHelperChunkGenerator.cs b/src/Microsoft.AspNet.Razor/Chunks/Generators/AddOrRemoveTagHelperChunkGenerator.cs deleted file mode 100644 index bfc64a4ebf..0000000000 --- a/src/Microsoft.AspNet.Razor/Chunks/Generators/AddOrRemoveTagHelperChunkGenerator.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNet.Razor.Parser.SyntaxTree; - -namespace Microsoft.AspNet.Razor.Chunks.Generators -{ - /// - /// A responsible for generating s and - /// s. - /// - public class AddOrRemoveTagHelperChunkGenerator : SpanChunkGenerator - { - /// - /// Instantiates a new . - /// - /// - /// Text used to look up s that should be added or removed. - /// - public AddOrRemoveTagHelperChunkGenerator(bool removeTagHelperDescriptors, string lookupText) - { - RemoveTagHelperDescriptors = removeTagHelperDescriptors; - LookupText = lookupText; - } - - /// - /// Gets the text used to look up s that should be added to or - /// removed from the Razor page. - /// - public string LookupText { get; } - - /// - /// Whether we want to remove s from the Razor page. - /// - /// If true generates s, - /// s otherwise. - public bool RemoveTagHelperDescriptors { get; } - - /// - /// Generates s if is - /// true, otherwise s are generated. - /// - /// - /// The responsible for this . - /// - /// A instance that contains information about - /// the current chunk generation process. - public override void GenerateChunk(Span target, ChunkGeneratorContext context) - { - if (RemoveTagHelperDescriptors) - { - context.ChunkTreeBuilder.AddRemoveTagHelperChunk(LookupText, target); - } - else - { - context.ChunkTreeBuilder.AddAddTagHelperChunk(LookupText, target); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs b/src/Microsoft.AspNet.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs new file mode 100644 index 0000000000..51b2f98b9b --- /dev/null +++ b/src/Microsoft.AspNet.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Razor.Parser.SyntaxTree; + +namespace Microsoft.AspNet.Razor.Chunks.Generators +{ + /// + /// A responsible for generating s. + /// + public class AddTagHelperChunkGenerator : SpanChunkGenerator + { + /// + /// Generates s. + /// + /// + /// The responsible for this . + /// + /// A instance that contains information about + /// the current chunk generation process. + public override void GenerateChunk(Span target, ChunkGeneratorContext context) + { + var lookupText = target.Content.Trim(); + + context.ChunkTreeBuilder.AddAddTagHelperChunk(lookupText, target); + } + } +} diff --git a/src/Microsoft.AspNet.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs b/src/Microsoft.AspNet.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs new file mode 100644 index 0000000000..280bb55747 --- /dev/null +++ b/src/Microsoft.AspNet.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Razor.Parser.SyntaxTree; + +namespace Microsoft.AspNet.Razor.Chunks.Generators +{ + /// + /// A responsible for generating s. + /// + public class RemoveTagHelperChunkGenerator : SpanChunkGenerator + { + /// + /// Generates s. + /// + /// + /// The responsible for this . + /// + /// A instance that contains information about + /// the current chunk generation process. + public override void GenerateChunk(Span target, ChunkGeneratorContext context) + { + var lookupText = target.Content.Trim(); + + context.ChunkTreeBuilder.AddRemoveTagHelperChunk(lookupText, target); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs b/src/Microsoft.AspNet.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs index dd00b86540..32b98188f4 100644 --- a/src/Microsoft.AspNet.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs +++ b/src/Microsoft.AspNet.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs @@ -11,22 +11,6 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators /// public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator { - /// - /// Instantiates a new . - /// - /// - /// Text used as a required prefix when matching HTML. - /// - public TagHelperPrefixDirectiveChunkGenerator(string prefix) - { - Prefix = prefix; - } - - /// - /// Text used as a required prefix when matching HTML. - /// - public string Prefix { get; } - /// /// Generates s. /// @@ -37,7 +21,9 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators /// the current chunk generation process. public override void GenerateChunk(Span target, ChunkGeneratorContext context) { - context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(Prefix, target); + var prefix = target.Content.Trim(); + + context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(prefix, target); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpDesignTimeCodeVisitor.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpDesignTimeCodeVisitor.cs index 3b05fdbc0d..3d533dc097 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpDesignTimeCodeVisitor.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpDesignTimeCodeVisitor.cs @@ -98,15 +98,16 @@ namespace Microsoft.AspNet.Razor.CodeGenerators.Visitors Writer.WriteVariableDeclaration("string", TagHelperDirectiveSyntaxHelper, "null"); } - Writer.WriteStartAssignment(TagHelperDirectiveSyntaxHelper); + Writer + .WriteStartAssignment(TagHelperDirectiveSyntaxHelper) + .Write("\""); - // The parsing mechanism for a TagHelper directive chunk (CSharpCodeParser.TagHelperDirective()) - // removes quotes that surround the text. - CSharpCodeVisitor.CreateExpressionCodeMapping( - string.Format(CultureInfo.InvariantCulture, "\"{0}\"", text), - chunk); + using (new CSharpLineMappingWriter(Writer, chunk.Start, text.Length)) + { + Writer.Write(text); + } - Writer.WriteLine(";"); + Writer.WriteLine("\";"); } } } diff --git a/src/Microsoft.AspNet.Razor/Parser/CSharpCodeParser.Directives.cs b/src/Microsoft.AspNet.Razor/Parser/CSharpCodeParser.Directives.cs index c241e160d3..5db4ea0ec5 100644 --- a/src/Microsoft.AspNet.Razor/Parser/CSharpCodeParser.Directives.cs +++ b/src/Microsoft.AspNet.Razor/Parser/CSharpCodeParser.Directives.cs @@ -26,23 +26,17 @@ namespace Microsoft.AspNet.Razor.Parser { TagHelperDirective( SyntaxConstants.CSharp.TagHelperPrefixKeyword, - prefix => new TagHelperPrefixDirectiveChunkGenerator(prefix)); + new TagHelperPrefixDirectiveChunkGenerator()); } protected virtual void AddTagHelperDirective() { - TagHelperDirective( - SyntaxConstants.CSharp.AddTagHelperKeyword, - lookupText => - new AddOrRemoveTagHelperChunkGenerator(removeTagHelperDescriptors: false, lookupText: lookupText)); + TagHelperDirective(SyntaxConstants.CSharp.AddTagHelperKeyword, new AddTagHelperChunkGenerator()); } protected virtual void RemoveTagHelperDirective() { - TagHelperDirective( - SyntaxConstants.CSharp.RemoveTagHelperKeyword, - lookupText => - new AddOrRemoveTagHelperChunkGenerator(removeTagHelperDescriptors: true, lookupText: lookupText)); + TagHelperDirective(SyntaxConstants.CSharp.RemoveTagHelperKeyword, new RemoveTagHelperChunkGenerator()); } protected virtual void SectionDirective() @@ -289,7 +283,7 @@ namespace Microsoft.AspNet.Razor.Parser Output(SpanKind.Code, AcceptedCharacters.AnyExceptNewline); } - private void TagHelperDirective(string keyword, Func buildChunkGenerator) + private void TagHelperDirective(string keyword, ISpanChunkGenerator chunkGenerator) { AssertDirective(keyword); var keywordStartLocation = CurrentLocation; @@ -324,34 +318,10 @@ namespace Microsoft.AspNet.Razor.Parser // Parse to the end of the line. Essentially accepts anything until end of line, comments, invalid code // etc. AcceptUntil(CSharpSymbolType.NewLine); - - // Pull out the value minus the spaces at the end - var rawValue = Span.GetContent().Value.TrimEnd(); - var startsWithQuote = rawValue.StartsWith("\"", StringComparison.OrdinalIgnoreCase); - - // If the value starts with a quote then we should generate appropriate C# code to colorize the value. - if (startsWithQuote) - { - // Set up chunk generation - // The generated chunk of this chunk generator is picked up by CSharpDesignTimeHelpersVisitor which - // renders the C# to colorize the user provided value. We trim the quotes around the user's value - // so when we render the code we can project the users value into double quotes to not invoke C# - // IntelliSense. - Span.ChunkGenerator = buildChunkGenerator(rawValue.Trim('"')); - } - - // We expect the directive to be surrounded in quotes. - // The format for tag helper directives are: @directivename "SomeValue" - if (!startsWithQuote || - !rawValue.EndsWith("\"", StringComparison.OrdinalIgnoreCase)) - { - Context.OnError( - startLocation, - RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(keyword), - rawValue.Length); - } } + Span.ChunkGenerator = chunkGenerator; + // Output the span and finish the block CompleteBlock(); Output(SpanKind.Code, AcceptedCharacters.AnyExceptNewline); diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs index ad7cee68a1..0289483c9b 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Microsoft.AspNet.Razor.Chunks.Generators; using Microsoft.AspNet.Razor.Parser.SyntaxTree; using Microsoft.AspNet.Razor.Compilation.TagHelpers; +using System.Diagnostics; namespace Microsoft.AspNet.Razor.Parser.TagHelpers { @@ -82,50 +83,42 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers public override void VisitSpan(Span span) { - // We're only interested in spans with an AddOrRemoveTagHelperChunkGenerator. - - if (span.ChunkGenerator is AddOrRemoveTagHelperChunkGenerator) + if (span == null) { - var chunkGenerator = (AddOrRemoveTagHelperChunkGenerator)span.ChunkGenerator; + throw new ArgumentNullException(nameof(span)); + } - var directive = - chunkGenerator.RemoveTagHelperDescriptors ? - TagHelperDirectiveType.RemoveTagHelper : - TagHelperDirectiveType.AddTagHelper; - var textLocation = GetSubTextSourceLocation(span, chunkGenerator.LookupText); - - var directiveDescriptor = new TagHelperDirectiveDescriptor - { - DirectiveText = chunkGenerator.LookupText, - Location = textLocation, - DirectiveType = directive - }; - - _directiveDescriptors.Add(directiveDescriptor); + TagHelperDirectiveType directiveType; + if (span.ChunkGenerator is AddTagHelperChunkGenerator) + { + directiveType = TagHelperDirectiveType.AddTagHelper; + } + else if (span.ChunkGenerator is RemoveTagHelperChunkGenerator) + { + directiveType = TagHelperDirectiveType.RemoveTagHelper; } else if (span.ChunkGenerator is TagHelperPrefixDirectiveChunkGenerator) { - var chunkGenerator = (TagHelperPrefixDirectiveChunkGenerator)span.ChunkGenerator; - var textLocation = GetSubTextSourceLocation(span, chunkGenerator.Prefix); - - var directiveDescriptor = new TagHelperDirectiveDescriptor - { - DirectiveText = chunkGenerator.Prefix, - Location = textLocation, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix - }; - - _directiveDescriptors.Add(directiveDescriptor); + directiveType = TagHelperDirectiveType.TagHelperPrefix; + } + else + { + // Not a chunk generator that we're interested in. + return; } - } - private static SourceLocation GetSubTextSourceLocation(Span span, string text) - { - var startOffset = span.Content.IndexOf(text); + var directiveText = span.Content.Trim(); + var startOffset = span.Content.IndexOf(directiveText); var offsetContent = span.Content.Substring(0, startOffset); var offsetTextLocation = SourceLocation.Advance(span.Start, offsetContent); + var directiveDescriptor = new TagHelperDirectiveDescriptor + { + DirectiveText = directiveText, + Location = offsetTextLocation, + DirectiveType = directiveType + }; - return offsetTextLocation; + _directiveDescriptors.Add(directiveDescriptor); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs b/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs index 317c929956..81b3aa245b 100644 --- a/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs +++ b/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs @@ -1302,22 +1302,6 @@ namespace Microsoft.AspNet.Razor return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_DirectiveMustHaveValue"), p0); } - /// - /// Directive '{0}'s value must be surrounded in double quotes. - /// - internal static string ParseError_DirectiveMustBeSurroundedByQuotes - { - get { return GetString("ParseError_DirectiveMustBeSurroundedByQuotes"); } - } - - /// - /// Directive '{0}'s value must be surrounded in double quotes. - /// - internal static string FormatParseError_DirectiveMustBeSurroundedByQuotes(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_DirectiveMustBeSurroundedByQuotes"), p0); - } - /// /// Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing. /// diff --git a/src/Microsoft.AspNet.Razor/RazorResources.resx b/src/Microsoft.AspNet.Razor/RazorResources.resx index a68e8bea39..841012e31f 100644 --- a/src/Microsoft.AspNet.Razor/RazorResources.resx +++ b/src/Microsoft.AspNet.Razor/RazorResources.resx @@ -378,9 +378,6 @@ Instead, wrap the contents of the block in "{{}}": Directive '{0}' must have a value. - - Directive '{0}'s value must be surrounded in double quotes. - Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.