Skip to content

Commit 4433ccf

Browse files
Added support for ASP.NET Razor (#3064)
1 parent 6a356d2 commit 4433ccf

13 files changed

+1844
-3
lines changed

components.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.

components.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,18 @@
10861086
"alias": "rkt",
10871087
"owner": "RunDevelopment"
10881088
},
1089+
"cshtml": {
1090+
"title": "Razor C#",
1091+
"alias": "razor",
1092+
"require": ["markup", "csharp"],
1093+
"optional":[
1094+
"css",
1095+
"css-extras",
1096+
"javascript",
1097+
"js-extras"
1098+
],
1099+
"owner": "RunDevelopment"
1100+
},
10891101
"jsx": {
10901102
"title": "React JSX",
10911103
"require": ["markup", "javascript"],

components/prism-cshtml.js

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// Docs:
2+
// https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-5.0&tabs=visual-studio
3+
// https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-5.0
4+
5+
(function (Prism) {
6+
7+
var commentLike = /\/(?![/*])|\/\/.*[\r\n]|\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\//.source;
8+
var stringLike =
9+
/@(?!")|"(?:[^\r\n\\"]|\\.)*"|@"(?:[^\\"]|""|\\[\s\S])*"(?!")/.source +
10+
'|' +
11+
/'(?:(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'|(?=[^\\](?!')))/.source;
12+
13+
/**
14+
* Creates a nested pattern where all occurrences of the string `<<self>>` are replaced with the pattern itself.
15+
*
16+
* @param {string} pattern
17+
* @param {number} depthLog2
18+
* @returns {string}
19+
*/
20+
function nested(pattern, depthLog2) {
21+
for (var i = 0; i < depthLog2; i++) {
22+
pattern = pattern.replace(/<self>/g, function () { return '(?:' + pattern + ')'; });
23+
}
24+
return pattern
25+
.replace(/<self>/g, '[^\\s\\S]')
26+
.replace(/<str>/g, '(?:' + stringLike + ')')
27+
.replace(/<comment>/g, '(?:' + commentLike + ')');
28+
}
29+
30+
var round = nested(/\((?:[^()'"@/]|<str>|<comment>|<self>)*\)/.source, 2);
31+
var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 2);
32+
var curly = nested(/\{(?:[^{}'"@/]|<str>|<comment>|<self>)*\}/.source, 2);
33+
var angle = nested(/<(?:[^<>'"@/]|<str>|<comment>|<self>)*>/.source, 2);
34+
35+
// Note about the above bracket patterns:
36+
// They all ignore HTML expressions that might be in the C# code. This is a problem because HTML (like strings and
37+
// comments) is parsed differently. This is a huge problem because HTML might contain brackets and quotes which
38+
// messes up the bracket and string counting implemented by the above patterns.
39+
//
40+
// This problem is not fixable because 1) HTML expression are highly context sensitive and very difficult to detect
41+
// and 2) they require one capturing group at every nested level. See the `tagRegion` pattern to admire the
42+
// complexity of an HTML expression.
43+
//
44+
// To somewhat alleviate the problem a bit, the patterns for characters (e.g. 'a') is very permissive, it also
45+
// allows invalid characters to support HTML expressions like this: <p>That's it!</p>.
46+
47+
var tagAttrs = /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?/.source;
48+
var tagContent = /(?!\d)[^\s>\/=$<%]+/.source + tagAttrs + /\s*\/?>/.source;
49+
var tagRegion =
50+
/\B@?/.source +
51+
'(?:' +
52+
/<([a-zA-Z][\w:]*)/.source + tagAttrs + /\s*>/.source +
53+
'(?:' +
54+
(
55+
/[^<]/.source +
56+
'|' +
57+
// all tags that are not the start tag
58+
// eslint-disable-next-line regexp/strict
59+
/<\/?(?!\1\b)/.source + tagContent +
60+
'|' +
61+
// nested start tag
62+
nested(
63+
// eslint-disable-next-line regexp/strict
64+
/<\1/.source + tagAttrs + /\s*>/.source +
65+
'(?:' +
66+
(
67+
/[^<]/.source +
68+
'|' +
69+
// all tags that are not the start tag
70+
// eslint-disable-next-line regexp/strict
71+
/<\/?(?!\1\b)/.source + tagContent +
72+
'|' +
73+
'<self>'
74+
) +
75+
')*' +
76+
// eslint-disable-next-line regexp/strict
77+
/<\/\1\s*>/.source,
78+
2
79+
)
80+
) +
81+
')*' +
82+
// eslint-disable-next-line regexp/strict
83+
/<\/\1\s*>/.source +
84+
'|' +
85+
/</.source + tagContent +
86+
')';
87+
88+
// Now for the actual language definition(s):
89+
//
90+
// Razor as a language has 2 parts:
91+
// 1) CSHTML: A markup-like language that has been extended with inline C# code expressions and blocks.
92+
// 2) C#+HTML: A variant of C# that can contain CSHTML tags as expressions.
93+
//
94+
// In the below code, both CSHTML and C#+HTML will be create as separate language definitions that reference each
95+
// other. However, only CSHTML will be exported via `Prism.languages`.
96+
97+
Prism.languages.cshtml = Prism.languages.extend('markup', {});
98+
99+
var csharpWithHtml = Prism.languages.insertBefore('csharp', 'string', {
100+
'html': {
101+
pattern: RegExp(tagRegion),
102+
greedy: true,
103+
inside: Prism.languages.cshtml
104+
},
105+
}, { csharp: Prism.languages.extend('csharp', {}) });
106+
107+
var cs = {
108+
pattern: /\S[\s\S]*/,
109+
alias: 'language-csharp',
110+
inside: csharpWithHtml
111+
};
112+
113+
Prism.languages.insertBefore('cshtml', 'prolog', {
114+
'razor-comment': {
115+
pattern: /@\*[\s\S]*?\*@/,
116+
greedy: true,
117+
alias: 'comment'
118+
},
119+
120+
'block': {
121+
pattern: RegExp(
122+
/(^|[^@])@/.source +
123+
'(?:' +
124+
[
125+
// @{ ... }
126+
curly,
127+
// @code{ ... }
128+
/(?:code|functions)\s*/.source + curly,
129+
// @for (...) { ... }
130+
/(?:for|foreach|lock|switch|using|while)\s*/.source + round + /\s*/.source + curly,
131+
// @do { ... } while (...);
132+
/do\s*/.source + curly + /\s*while\s*/.source + round + /(?:\s*;)?/.source,
133+
// @try { ... } catch (...) { ... } finally { ... }
134+
/try\s*/.source + curly + /\s*catch\s*/.source + round + /\s*/.source + curly + /\s*finally\s*/.source + curly,
135+
// @if (...) {...} else if (...) {...} else {...}
136+
/if\s*/.source + round + /\s*/.source + curly + '(?:' + /\s*else/.source + '(?:' + /\s+if\s*/.source + round + ')?' + /\s*/.source + curly + ')*',
137+
].join('|') +
138+
')'
139+
),
140+
lookbehind: true,
141+
greedy: true,
142+
inside: {
143+
'keyword': /^@\w*/,
144+
'csharp': cs
145+
}
146+
},
147+
148+
'directive': {
149+
pattern: /^([ \t]*)@(?:addTagHelper|attribute|implements|inherits|inject|layout|model|namespace|page|preservewhitespace|removeTagHelper|section|tagHelperPrefix|using)(?=\s).*/m,
150+
lookbehind: true,
151+
greedy: true,
152+
inside: {
153+
'keyword': /^@\w+/,
154+
'csharp': cs
155+
}
156+
},
157+
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+
},
173+
174+
'delegate-operator': {
175+
pattern: /(^|[^@])@(?=<)/,
176+
lookbehind: true,
177+
alias: 'operator'
178+
}
179+
});
180+
181+
Prism.languages.razor = Prism.languages.cshtml;
182+
183+
}(Prism));

components/prism-cshtml.min.js

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

examples/prism-cshtml.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<h2>Full example</h2>
2+
<pre><code>@* Source: https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-5.0&amp;tabs=visual-studio#the-home-page *@
3+
4+
@page
5+
@model RazorPagesContacts.Pages.Customers.IndexModel
6+
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
7+
8+
&lt;h1>Contacts home page&lt;/h1>
9+
&lt;form method="post">
10+
&lt;table class="table">
11+
&lt;thead>
12+
&lt;tr>
13+
&lt;th>ID&lt;/th>
14+
&lt;th>Name&lt;/th>
15+
&lt;th>&lt;/th>
16+
&lt;/tr>
17+
&lt;/thead>
18+
&lt;tbody>
19+
@foreach (var contact in Model.Customer)
20+
{
21+
&lt;tr>
22+
&lt;td> @contact.Id &lt;/td>
23+
&lt;td>@contact.Name&lt;/td>
24+
&lt;td>
25+
&lt;a asp-page="./Edit" asp-route-id="@contact.Id">Edit&lt;/a> |
26+
&lt;button type="submit" asp-page-handler="delete"
27+
asp-route-id="@contact.Id">delete
28+
&lt;/button>
29+
&lt;/td>
30+
&lt;/tr>
31+
}
32+
&lt;/tbody>
33+
&lt;/table>
34+
&lt;a asp-page="Create">Create New&lt;/a>
35+
&lt;/form>
36+
</code></pre>

plugins/autoloader/prism-autoloader.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@
115115
"qml": "javascript",
116116
"qore": "clike",
117117
"racket": "scheme",
118+
"cshtml": [
119+
"markup",
120+
"csharp"
121+
],
118122
"jsx": [
119123
"markup",
120124
"javascript"
@@ -224,6 +228,7 @@
224228
"py": "python",
225229
"qs": "qsharp",
226230
"rkt": "racket",
231+
"razor": "cshtml",
227232
"rpy": "renpy",
228233
"robot": "robotframework",
229234
"rb": "ruby",

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy