Skip to content

Commit 7aff247

Browse files
author
Jordi Ramos
authored
Textmate: fix Razor expression classification inside of HTML tags using injection (#7055)
* fix "fix-html-textmate" using injection - this commit explores a new way of injecting razor textmate grammar into the html textmate grammar. so that razor expressions can still be recognized inside html tags without having to directly change any of the html textmate - we also updated some grammar tests to make the test cases more comprehensive regarding this matter - revert the changes made to html.tmlanguage.json so that it matches the one on the textmate repo (we removed all the razor refences inside it)
1 parent e726f27 commit 7aff247

File tree

5 files changed

+115
-29
lines changed

5 files changed

+115
-29
lines changed

src/razor/syntaxes/aspnetcorerazor.tmLanguage.json

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@
55
"razor",
66
"cshtml"
77
],
8+
"injections": {
9+
"string.quoted.double.html": {
10+
"patterns": [
11+
{
12+
"include": "#explicit-razor-expression"
13+
},
14+
{
15+
"include": "#implicit-expression"
16+
}
17+
]
18+
},
19+
"string.quoted.single.html": {
20+
"patterns": [
21+
{
22+
"include": "#explicit-razor-expression"
23+
},
24+
{
25+
"include": "#implicit-expression"
26+
}
27+
]
28+
}
29+
},
830
"patterns": [
931
{
1032
"include": "#razor-control-structures"
@@ -64,16 +86,6 @@
6486
}
6587
]
6688
},
67-
"implicit-or-explicit-expression": {
68-
"patterns": [
69-
{
70-
"include": "#explicit-razor-expression"
71-
},
72-
{
73-
"include": "#implicit-expression"
74-
}
75-
]
76-
},
7789
"escaped-transition": {
7890
"name": "constant.character.escape.razor.transition",
7991
"match": "@@"

src/razor/syntaxes/aspnetcorerazor.tmLanguage.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ scopeName: text.aspnetcorerazor
33
fileTypes:
44
- 'razor'
55
- 'cshtml'
6+
7+
# These injections make sure that razor expressions can be recognized in the HTML grammar, specifically in strings
8+
injections:
9+
string.quoted.double.html:
10+
patterns:
11+
- include: '#explicit-razor-expression'
12+
- include: '#implicit-expression'
13+
14+
string.quoted.single.html:
15+
patterns:
16+
- include: '#explicit-razor-expression'
17+
- include: '#implicit-expression'
18+
619
patterns:
720
- include: '#razor-control-structures'
821
- include: 'text.html.basic'
@@ -31,11 +44,6 @@ repository:
3144
- include: '#optionally-transitioned-csharp-control-structures'
3245
- include: '#implicit-expression'
3346

34-
# a clause to combine the explicit and implicit razor expressions, used by the html grammar
35-
implicit-or-explicit-expression:
36-
patterns:
37-
- include: '#explicit-razor-expression'
38-
- include: '#implicit-expression'
3947

4048
escaped-transition:
4149
name: constant.character.escape.razor.transition

test/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/embeddedGrammars/html.tmLanguage.json

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,6 @@
113113
},
114114
"name": "string.quoted.double.html",
115115
"patterns": [
116-
{
117-
"include": "text.aspnetcorerazor#implicit-or-explicit-expression"
118-
},
119116
{
120117
"include": "#entities"
121118
}
@@ -140,9 +137,6 @@
140137
},
141138
"name": "string.quoted.single.html",
142139
"patterns": [
143-
{
144-
"include": "text.aspnetcorerazor#implicit-or-explicit-expression"
145-
},
146140
{
147141
"include": "#entities"
148142
}
@@ -409,9 +403,6 @@
409403
},
410404
"name": "string.quoted.double.html",
411405
"patterns": [
412-
{
413-
"include": "text.aspnetcorerazor#implicit-or-explicit-expression"
414-
},
415406
{
416407
"include": "#entities"
417408
}
@@ -432,9 +423,6 @@
432423
},
433424
"name": "string.quoted.single.html",
434425
"patterns": [
435-
{
436-
"include": "text.aspnetcorerazor#implicit-or-explicit-expression"
437-
},
438426
{
439427
"include": "#entities"
440428
}

test/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/__snapshots__/grammarTests.test.ts.snap

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5205,7 +5205,7 @@ exports[`Grammar tests HTML dynamic (razor) attribute double quotes inside singl
52055205
"
52065206
`;
52075207

5208-
exports[`Grammar tests HTML dynamic (razor) attribute razor inside attribute 1`] = `
5208+
exports[`Grammar tests HTML dynamic (razor) attribute razor inside attribute double inside double quotes 1`] = `
52095209
"Line: <div id="@("")"> </div>
52105210
- token from 0 to 1 (<) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.begin.html
52115211
- token from 1 to 4 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, entity.name.tag.html
@@ -5227,6 +5227,73 @@ exports[`Grammar tests HTML dynamic (razor) attribute razor inside attribute 1`]
52275227
"
52285228
`;
52295229

5230+
exports[`Grammar tests HTML dynamic (razor) attribute razor inside attribute double inside single quotes 1`] = `
5231+
"Line: <div id='@("")'> </div>
5232+
- token from 0 to 1 (<) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.begin.html
5233+
- token from 1 to 4 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, entity.name.tag.html
5234+
- token from 4 to 5 ( ) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html
5235+
- token from 5 to 7 (id) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, entity.other.attribute-name.html
5236+
- token from 7 to 8 (=) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, punctuation.separator.key-value.html
5237+
- token from 8 to 9 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, punctuation.definition.string.begin.html
5238+
- token from 9 to 10 (@) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, keyword.control.cshtml.transition
5239+
- token from 10 to 11 (() with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, keyword.control.cshtml
5240+
- token from 11 to 12 (") with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, string.quoted.double.cs, punctuation.definition.string.begin.cs
5241+
- token from 12 to 13 (") with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, string.quoted.double.cs, punctuation.definition.string.end.cs
5242+
- token from 13 to 14 ()) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, keyword.control.cshtml
5243+
- token from 14 to 15 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, punctuation.definition.string.end.html
5244+
- token from 15 to 16 (>) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.end.html
5245+
- token from 16 to 17 ( ) with scopes text.aspnetcorerazor
5246+
- token from 17 to 19 (</) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, punctuation.definition.tag.begin.html
5247+
- token from 19 to 22 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, entity.name.tag.html
5248+
- token from 22 to 23 (>) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, punctuation.definition.tag.end.html
5249+
"
5250+
`;
5251+
5252+
exports[`Grammar tests HTML dynamic (razor) attribute razor inside attribute single inside double quotes 1`] = `
5253+
"Line: <div id="@('')"> </div>
5254+
- token from 0 to 1 (<) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.begin.html
5255+
- token from 1 to 4 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, entity.name.tag.html
5256+
- token from 4 to 5 ( ) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html
5257+
- token from 5 to 7 (id) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, entity.other.attribute-name.html
5258+
- token from 7 to 8 (=) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, punctuation.separator.key-value.html
5259+
- token from 8 to 9 (") with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, punctuation.definition.string.begin.html
5260+
- token from 9 to 10 (@) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, meta.expression.explicit.cshtml, keyword.control.cshtml.transition
5261+
- token from 10 to 11 (() with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, meta.expression.explicit.cshtml, keyword.control.cshtml
5262+
- token from 11 to 12 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, meta.expression.explicit.cshtml, string.quoted.single.cs, punctuation.definition.char.begin.cs
5263+
- token from 12 to 13 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, meta.expression.explicit.cshtml, string.quoted.single.cs, punctuation.definition.char.end.cs
5264+
- token from 13 to 14 ()) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, meta.expression.explicit.cshtml, keyword.control.cshtml
5265+
- token from 14 to 15 (") with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.double.html, punctuation.definition.string.end.html
5266+
- token from 15 to 16 (>) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.end.html
5267+
- token from 16 to 17 ( ) with scopes text.aspnetcorerazor
5268+
- token from 17 to 19 (</) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, punctuation.definition.tag.begin.html
5269+
- token from 19 to 22 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, entity.name.tag.html
5270+
- token from 22 to 23 (>) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, punctuation.definition.tag.end.html
5271+
"
5272+
`;
5273+
5274+
exports[`Grammar tests HTML dynamic (razor) attribute razor inside attribute single inside single quotes 1`] = `
5275+
"Line: <div id='@('')''> </div>
5276+
- token from 0 to 1 (<) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.begin.html
5277+
- token from 1 to 4 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, entity.name.tag.html
5278+
- token from 4 to 5 ( ) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html
5279+
- token from 5 to 7 (id) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, entity.other.attribute-name.html
5280+
- token from 7 to 8 (=) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, punctuation.separator.key-value.html
5281+
- token from 8 to 9 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, punctuation.definition.string.begin.html
5282+
- token from 9 to 10 (@) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, keyword.control.cshtml.transition
5283+
- token from 10 to 11 (() with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, keyword.control.cshtml
5284+
- token from 11 to 12 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, string.quoted.single.cs, punctuation.definition.char.begin.cs
5285+
- token from 12 to 13 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, string.quoted.single.cs, punctuation.definition.char.end.cs
5286+
- token from 13 to 14 ()) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, meta.expression.explicit.cshtml, keyword.control.cshtml
5287+
- token from 14 to 15 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, meta.attribute.id.html, string.quoted.single.html, punctuation.definition.string.end.html
5288+
- token from 15 to 16 (') with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, invalid.illegal.character-not-allowed-here.html
5289+
- token from 16 to 17 (>) with scopes text.aspnetcorerazor, meta.tag.structure.div.start.html, punctuation.definition.tag.end.html
5290+
- token from 17 to 18 ( ) with scopes text.aspnetcorerazor
5291+
- token from 18 to 20 (</) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, punctuation.definition.tag.begin.html
5292+
- token from 20 to 23 (div) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, entity.name.tag.html
5293+
- token from 23 to 24 (>) with scopes text.aspnetcorerazor, meta.tag.structure.div.end.html, punctuation.definition.tag.end.html
5294+
"
5295+
`;
5296+
52305297
exports[`Grammar tests HTML dynamic (razor) attribute single quotes in side double quotes 1`] = `
52315298
"Line: <button @onclick="myFunction('test')">Test</button>
52325299
- token from 0 to 1 (<) with scopes text.aspnetcorerazor, meta.tag.structure.button.start.html, punctuation.definition.tag.begin.html

test/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/htmlDynamicAttribute.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,21 @@ import { assertMatchesSnapshot } from './infrastructure/testUtilities';
1010

1111
export function RunHTMLDynamicAttributeSuite() {
1212
describe('HTML dynamic (razor) attribute', () => {
13-
it('razor inside attribute', async () => {
13+
it('razor inside attribute double inside double quotes', async () => {
1414
await assertMatchesSnapshot('<div id="@("")"> </div>');
1515
});
1616

17+
it('razor inside attribute single inside single quotes', async () => {
18+
await assertMatchesSnapshot("<div id='@('')''> </div>");
19+
});
20+
21+
it('razor inside attribute single inside double quotes', async () => {
22+
await assertMatchesSnapshot('<div id="@(\'\')"> </div>');
23+
});
24+
it('razor inside attribute double inside single quotes', async () => {
25+
await assertMatchesSnapshot('<div id=\'@("")\'> </div>');
26+
});
27+
1728
it('single quotes in side double quotes', async () => {
1829
await assertMatchesSnapshot('<button @onclick="myFunction(\'test\')">Test</button>');
1930
});

0 commit comments

Comments
 (0)