Skip to content

Commit

Permalink
CSHTML: Added support for @helper and inline C# inside attribute va…
Browse files Browse the repository at this point in the history
…lues (#3355)
  • Loading branch information
RunDevelopment authored Mar 13, 2022
1 parent 7ac84dd commit 31a38d0
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 19 deletions.
52 changes: 34 additions & 18 deletions components/prism-cshtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@
}

var round = nested(/\((?:[^()'"@/]|<str>|<comment>|<self>)*\)/.source, 2);
var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 2);
var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 1);
var curly = nested(/\{(?:[^{}'"@/]|<str>|<comment>|<self>)*\}/.source, 2);
var angle = nested(/<(?:[^<>'"@/]|<str>|<comment>|<self>)*>/.source, 2);
var angle = nested(/<(?:[^<>'"@/]|<comment>|<self>)*>/.source, 1);

var inlineCs = /@/.source +
/(?:await\b\s*)?/.source +
'(?:' + /(?!await\b)\w+\b/.source + '|' + round + ')' +
'(?:' + /[?!]?\.\w+\b/.source + '|' + '(?:' + angle + ')?' + round + '|' + square + ')*' +
/(?![?!\.(\[]|<(?!\/))/.source;

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

var tagAttrs = /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?/.source;
var tagAttrInlineCs = /@(?![\w()])/.source + '|' + inlineCs;
var tagAttrValue = '(?:' +
/"[^"@]*"|'[^'@]*'|[^\s'"@>=]+(?=[\s>])/.source +
'|' +
'["\'][^"\'@]*(?:(?:' + tagAttrInlineCs + ')[^"\'@]*)+["\']' +
')';

var tagAttrs = /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*<tagAttrValue>|(?=[\s/>])))+)?/.source.replace(/<tagAttrValue>/, tagAttrValue);
var tagContent = /(?!\d)[^\s>\/=$<%]+/.source + tagAttrs + /\s*\/?>/.source;
var tagRegion =
/\B@?/.source +
Expand Down Expand Up @@ -110,6 +123,21 @@
inside: csharpWithHtml
};

var inlineValue = {
pattern: RegExp(/(^|[^@])/.source + inlineCs),
lookbehind: true,
greedy: true,
alias: 'variable',
inside: {
'keyword': /^@/,
'csharp': cs
}
};

Prism.languages.cshtml.tag.pattern = RegExp(/<\/?/.source + tagContent);
Prism.languages.cshtml.tag.inside['attr-value'].pattern = RegExp(/=\s*/.source + tagAttrValue);
Prism.languages.insertBefore('inside', 'punctuation', { 'value': inlineValue }, Prism.languages.cshtml.tag.inside['attr-value']);

Prism.languages.insertBefore('cshtml', 'prolog', {
'razor-comment': {
pattern: /@\*[\s\S]*?\*@/,
Expand All @@ -134,6 +162,8 @@
/try\s*/.source + curly + /\s*catch\s*/.source + round + /\s*/.source + curly + /\s*finally\s*/.source + curly,
// @if (...) {...} else if (...) {...} else {...}
/if\s*/.source + round + /\s*/.source + curly + '(?:' + /\s*else/.source + '(?:' + /\s+if\s*/.source + round + ')?' + /\s*/.source + curly + ')*',
// @helper Ident(params) { ... }
/helper\s+\w+\s*/.source + round + /\s*/.source + curly,
].join('|') +
')'
),
Expand All @@ -155,21 +185,7 @@
}
},

'value': {
pattern: RegExp(
/(^|[^@])@/.source +
/(?:await\b\s*)?/.source +
'(?:' + /\w+\b/.source + '|' + round + ')' +
'(?:' + /[?!]?\.\w+\b/.source + '|' + round + '|' + square + '|' + angle + round + ')*'
),
lookbehind: true,
greedy: true,
alias: 'variable',
inside: {
'keyword': /^@/,
'csharp': cs
}
},
'value': inlineValue,

'delegate-operator': {
pattern: /(^|[^@])@(?=<)/,
Expand Down
2 changes: 1 addition & 1 deletion components/prism-cshtml.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions tests/languages/cshtml/block_feature.test
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ finally
// Do critical section work
}

@helper TrialHelper(string name) {
// some code
}

----------------------------------------------------

[
Expand Down Expand Up @@ -893,6 +897,24 @@ finally
["punctuation", "("], "SomeLock", ["punctuation", ")"],
["punctuation", "{"],
["comment", "// Do critical section work"],
["punctuation", "}"]
]]
]],

["block", [
["keyword", "@helper"],
["csharp", [
["function", "TrialHelper"],
["punctuation", "("],
["class-name", [
["keyword", "string"]
]],
" name",
["punctuation", ")"],
["punctuation", "{"],

["comment", "// some code"],

["punctuation", "}"]
]]
]]
Expand Down
194 changes: 194 additions & 0 deletions tests/languages/cshtml/issue3354.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<input type="text" placeholder="@Localize.GetLabelHtml("PLACEHOLDER")"/>

<h1>
@Localize.GetLabelHtml("TITLE")
</h1>

@{
var man = "Federico";
var text = string.Concat("Nice to meet you", " ", man);
}

@helper TrialHelper(string name) {
var text = string.Concat("Hello", " ", name);
<h1>
@(text + ", how's going?")
</h1>
<p>
Hello World!
</p>
}

----------------------------------------------------

[
["tag", [
["tag", [
["punctuation", "<"],
"input"
]],
["attr-name", ["type"]],
["attr-value", [
["punctuation", "="],
["punctuation", "\""],
"text",
["punctuation", "\""]
]],
["attr-name", ["placeholder"]],
["attr-value", [
["punctuation", "="],
["punctuation", "\""],
["value", [
["keyword", "@"],
["csharp", [
"Localize",
["punctuation", "."],
["function", "GetLabelHtml"],
["punctuation", "("],
["string", "\"PLACEHOLDER\""],
["punctuation", ")"]
]]
]],
["punctuation", "\""]
]],
["punctuation", "/>"]
]],

["tag", [
["tag", [
["punctuation", "<"],
"h1"
]],
["punctuation", ">"]
]],
["value", [
["keyword", "@"],
["csharp", [
"Localize",
["punctuation", "."],
["function", "GetLabelHtml"],
["punctuation", "("],
["string", "\"TITLE\""],
["punctuation", ")"]
]]
]],
["tag", [
["tag", [
["punctuation", "</"],
"h1"
]],
["punctuation", ">"]
]],

["block", [
["keyword", "@"],
["csharp", [
["punctuation", "{"],

["class-name", [
["keyword", "var"]
]],
" man ",
["operator", "="],
["string", "\"Federico\""],
["punctuation", ";"],

["class-name", [
["keyword", "var"]
]],
" text ",
["operator", "="],
["keyword", "string"],
["punctuation", "."],
["function", "Concat"],
["punctuation", "("],
["string", "\"Nice to meet you\""],
["punctuation", ","],
["string", "\" \""],
["punctuation", ","],
" man",
["punctuation", ")"],
["punctuation", ";"],

["punctuation", "}"]
]]
]],

["block", [
["keyword", "@helper"],
["csharp", [
["function", "TrialHelper"],
["punctuation", "("],
["class-name", [
["keyword", "string"]
]],
" name",
["punctuation", ")"],
["punctuation", "{"],

["class-name", [
["keyword", "var"]
]],
" text ",
["operator", "="],
["keyword", "string"],
["punctuation", "."],
["function", "Concat"],
["punctuation", "("],
["string", "\"Hello\""],
["punctuation", ","],
["string", "\" \""],
["punctuation", ","],
" name",
["punctuation", ")"],
["punctuation", ";"],

["html", [
["tag", [
["tag", [
["punctuation", "<"],
"h1"
]],
["punctuation", ">"]
]],
["value", [
["keyword", "@"],
["csharp", [
["punctuation", "("],
"text ",
["operator", "+"],
["string", "\", how's going?\""],
["punctuation", ")"]
]]
]],
["tag", [
["tag", [
["punctuation", "</"],
"h1"
]],
["punctuation", ">"]
]]
]],

["html", [
["tag", [
["tag", [
["punctuation", "<"],
"p"
]],
["punctuation", ">"]
]],
"\r\n Hello World!\r\n ",
["tag", [
["tag", [
["punctuation", "</"],
"p"
]],
["punctuation", ">"]
]]
]],

["punctuation", "}"]
]]
]]
]

0 comments on commit 31a38d0

Please sign in to comment.