Skip to content

Commit 31a38d0

Browse files
CSHTML: Added support for @helper and inline C# inside attribute values (#3355)
1 parent 7ac84dd commit 31a38d0

File tree

4 files changed

+251
-19
lines changed

4 files changed

+251
-19
lines changed

components/prism-cshtml.js

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@
2828
}
2929

3030
var round = nested(/\((?:[^()'"@/]|<str>|<comment>|<self>)*\)/.source, 2);
31-
var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 2);
31+
var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 1);
3232
var curly = nested(/\{(?:[^{}'"@/]|<str>|<comment>|<self>)*\}/.source, 2);
33-
var angle = nested(/<(?:[^<>'"@/]|<str>|<comment>|<self>)*>/.source, 2);
33+
var angle = nested(/<(?:[^<>'"@/]|<comment>|<self>)*>/.source, 1);
34+
35+
var inlineCs = /@/.source +
36+
/(?:await\b\s*)?/.source +
37+
'(?:' + /(?!await\b)\w+\b/.source + '|' + round + ')' +
38+
'(?:' + /[?!]?\.\w+\b/.source + '|' + '(?:' + angle + ')?' + round + '|' + square + ')*' +
39+
/(?![?!\.(\[]|<(?!\/))/.source;
3440

3541
// Note about the above bracket patterns:
3642
// They all ignore HTML expressions that might be in the C# code. This is a problem because HTML (like strings and
@@ -44,7 +50,14 @@
4450
// To somewhat alleviate the problem a bit, the patterns for characters (e.g. 'a') is very permissive, it also
4551
// allows invalid characters to support HTML expressions like this: <p>That's it!</p>.
4652

47-
var tagAttrs = /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?/.source;
53+
var tagAttrInlineCs = /@(?![\w()])/.source + '|' + inlineCs;
54+
var tagAttrValue = '(?:' +
55+
/"[^"@]*"|'[^'@]*'|[^\s'"@>=]+(?=[\s>])/.source +
56+
'|' +
57+
'["\'][^"\'@]*(?:(?:' + tagAttrInlineCs + ')[^"\'@]*)+["\']' +
58+
')';
59+
60+
var tagAttrs = /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*<tagAttrValue>|(?=[\s/>])))+)?/.source.replace(/<tagAttrValue>/, tagAttrValue);
4861
var tagContent = /(?!\d)[^\s>\/=$<%]+/.source + tagAttrs + /\s*\/?>/.source;
4962
var tagRegion =
5063
/\B@?/.source +
@@ -110,6 +123,21 @@
110123
inside: csharpWithHtml
111124
};
112125

126+
var inlineValue = {
127+
pattern: RegExp(/(^|[^@])/.source + inlineCs),
128+
lookbehind: true,
129+
greedy: true,
130+
alias: 'variable',
131+
inside: {
132+
'keyword': /^@/,
133+
'csharp': cs
134+
}
135+
};
136+
137+
Prism.languages.cshtml.tag.pattern = RegExp(/<\/?/.source + tagContent);
138+
Prism.languages.cshtml.tag.inside['attr-value'].pattern = RegExp(/=\s*/.source + tagAttrValue);
139+
Prism.languages.insertBefore('inside', 'punctuation', { 'value': inlineValue }, Prism.languages.cshtml.tag.inside['attr-value']);
140+
113141
Prism.languages.insertBefore('cshtml', 'prolog', {
114142
'razor-comment': {
115143
pattern: /@\*[\s\S]*?\*@/,
@@ -134,6 +162,8 @@
134162
/try\s*/.source + curly + /\s*catch\s*/.source + round + /\s*/.source + curly + /\s*finally\s*/.source + curly,
135163
// @if (...) {...} else if (...) {...} else {...}
136164
/if\s*/.source + round + /\s*/.source + curly + '(?:' + /\s*else/.source + '(?:' + /\s+if\s*/.source + round + ')?' + /\s*/.source + curly + ')*',
165+
// @helper Ident(params) { ... }
166+
/helper\s+\w+\s*/.source + round + /\s*/.source + curly,
137167
].join('|') +
138168
')'
139169
),
@@ -155,21 +185,7 @@
155185
}
156186
},
157187

158-
'value': {
159-
pattern: RegExp(
160-
/(^|[^@])@/.source +
161-
/(?:await\b\s*)?/.source +
162-
'(?:' + /\w+\b/.source + '|' + round + ')' +
163-
'(?:' + /[?!]?\.\w+\b/.source + '|' + round + '|' + square + '|' + angle + round + ')*'
164-
),
165-
lookbehind: true,
166-
greedy: true,
167-
alias: 'variable',
168-
inside: {
169-
'keyword': /^@/,
170-
'csharp': cs
171-
}
172-
},
188+
'value': inlineValue,
173189

174190
'delegate-operator': {
175191
pattern: /(^|[^@])@(?=<)/,

components/prism-cshtml.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/languages/cshtml/block_feature.test

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ finally
9494
// Do critical section work
9595
}
9696

97+
@helper TrialHelper(string name) {
98+
// some code
99+
}
100+
97101
----------------------------------------------------
98102

99103
[
@@ -893,6 +897,24 @@ finally
893897
["punctuation", "("], "SomeLock", ["punctuation", ")"],
894898
["punctuation", "{"],
895899
["comment", "// Do critical section work"],
900+
["punctuation", "}"]
901+
]]
902+
]],
903+
904+
["block", [
905+
["keyword", "@helper"],
906+
["csharp", [
907+
["function", "TrialHelper"],
908+
["punctuation", "("],
909+
["class-name", [
910+
["keyword", "string"]
911+
]],
912+
" name",
913+
["punctuation", ")"],
914+
["punctuation", "{"],
915+
916+
["comment", "// some code"],
917+
896918
["punctuation", "}"]
897919
]]
898920
]]
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
<input type="text" placeholder="@Localize.GetLabelHtml("PLACEHOLDER")"/>
2+
3+
<h1>
4+
@Localize.GetLabelHtml("TITLE")
5+
</h1>
6+
7+
@{
8+
var man = "Federico";
9+
var text = string.Concat("Nice to meet you", " ", man);
10+
}
11+
12+
@helper TrialHelper(string name) {
13+
var text = string.Concat("Hello", " ", name);
14+
<h1>
15+
@(text + ", how's going?")
16+
</h1>
17+
<p>
18+
Hello World!
19+
</p>
20+
}
21+
22+
----------------------------------------------------
23+
24+
[
25+
["tag", [
26+
["tag", [
27+
["punctuation", "<"],
28+
"input"
29+
]],
30+
["attr-name", ["type"]],
31+
["attr-value", [
32+
["punctuation", "="],
33+
["punctuation", "\""],
34+
"text",
35+
["punctuation", "\""]
36+
]],
37+
["attr-name", ["placeholder"]],
38+
["attr-value", [
39+
["punctuation", "="],
40+
["punctuation", "\""],
41+
["value", [
42+
["keyword", "@"],
43+
["csharp", [
44+
"Localize",
45+
["punctuation", "."],
46+
["function", "GetLabelHtml"],
47+
["punctuation", "("],
48+
["string", "\"PLACEHOLDER\""],
49+
["punctuation", ")"]
50+
]]
51+
]],
52+
["punctuation", "\""]
53+
]],
54+
["punctuation", "/>"]
55+
]],
56+
57+
["tag", [
58+
["tag", [
59+
["punctuation", "<"],
60+
"h1"
61+
]],
62+
["punctuation", ">"]
63+
]],
64+
["value", [
65+
["keyword", "@"],
66+
["csharp", [
67+
"Localize",
68+
["punctuation", "."],
69+
["function", "GetLabelHtml"],
70+
["punctuation", "("],
71+
["string", "\"TITLE\""],
72+
["punctuation", ")"]
73+
]]
74+
]],
75+
["tag", [
76+
["tag", [
77+
["punctuation", "</"],
78+
"h1"
79+
]],
80+
["punctuation", ">"]
81+
]],
82+
83+
["block", [
84+
["keyword", "@"],
85+
["csharp", [
86+
["punctuation", "{"],
87+
88+
["class-name", [
89+
["keyword", "var"]
90+
]],
91+
" man ",
92+
["operator", "="],
93+
["string", "\"Federico\""],
94+
["punctuation", ";"],
95+
96+
["class-name", [
97+
["keyword", "var"]
98+
]],
99+
" text ",
100+
["operator", "="],
101+
["keyword", "string"],
102+
["punctuation", "."],
103+
["function", "Concat"],
104+
["punctuation", "("],
105+
["string", "\"Nice to meet you\""],
106+
["punctuation", ","],
107+
["string", "\" \""],
108+
["punctuation", ","],
109+
" man",
110+
["punctuation", ")"],
111+
["punctuation", ";"],
112+
113+
["punctuation", "}"]
114+
]]
115+
]],
116+
117+
["block", [
118+
["keyword", "@helper"],
119+
["csharp", [
120+
["function", "TrialHelper"],
121+
["punctuation", "("],
122+
["class-name", [
123+
["keyword", "string"]
124+
]],
125+
" name",
126+
["punctuation", ")"],
127+
["punctuation", "{"],
128+
129+
["class-name", [
130+
["keyword", "var"]
131+
]],
132+
" text ",
133+
["operator", "="],
134+
["keyword", "string"],
135+
["punctuation", "."],
136+
["function", "Concat"],
137+
["punctuation", "("],
138+
["string", "\"Hello\""],
139+
["punctuation", ","],
140+
["string", "\" \""],
141+
["punctuation", ","],
142+
" name",
143+
["punctuation", ")"],
144+
["punctuation", ";"],
145+
146+
["html", [
147+
["tag", [
148+
["tag", [
149+
["punctuation", "<"],
150+
"h1"
151+
]],
152+
["punctuation", ">"]
153+
]],
154+
["value", [
155+
["keyword", "@"],
156+
["csharp", [
157+
["punctuation", "("],
158+
"text ",
159+
["operator", "+"],
160+
["string", "\", how's going?\""],
161+
["punctuation", ")"]
162+
]]
163+
]],
164+
["tag", [
165+
["tag", [
166+
["punctuation", "</"],
167+
"h1"
168+
]],
169+
["punctuation", ">"]
170+
]]
171+
]],
172+
173+
["html", [
174+
["tag", [
175+
["tag", [
176+
["punctuation", "<"],
177+
"p"
178+
]],
179+
["punctuation", ">"]
180+
]],
181+
"\r\n Hello World!\r\n ",
182+
["tag", [
183+
["tag", [
184+
["punctuation", "</"],
185+
"p"
186+
]],
187+
["punctuation", ">"]
188+
]]
189+
]],
190+
191+
["punctuation", "}"]
192+
]]
193+
]]
194+
]

0 commit comments

Comments
 (0)