Skip to content

Commit 32d3ef4

Browse files
committed
Syntax highlighting support for class/interface generic constrains and tests.
1 parent 425dd6b commit 32d3ef4

File tree

4 files changed

+105
-4
lines changed

4 files changed

+105
-4
lines changed

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ trim_trailing_whitespace = true
1313
[{.travis.yml},package.json]
1414
indent_style = space
1515
indent_size = 2
16+
17+
[syntaxes/csharp.json]
18+
indent_style = space
19+
indent_size = 2

syntaxes/csharp.json

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,43 @@
123123
}
124124
]
125125
},
126+
"genericConstraints": {
127+
"begin": "(where)\\s*(\\w+)\\s*:",
128+
"end": "(?={)",
129+
"beginCaptures": {
130+
"1": {
131+
"name": "keyword.other.cs"
132+
},
133+
"2": {
134+
"name": "storage.type.cs"
135+
}
136+
},
137+
"patterns": [
138+
{
139+
"match": "\\b(class|struct)\\b",
140+
"name": "keyword.other.cs"
141+
},
142+
{
143+
"match": "(new)\\s*\\(\\s*\\)",
144+
"captures": {
145+
"1": {
146+
"name": "keyword.other.cs"
147+
}
148+
}
149+
},
150+
{
151+
"match": "([\\w<>]+)\\s*(?=,|where|{)",
152+
"captures": {
153+
"1": {
154+
"name": "storage.type.cs"
155+
}
156+
}
157+
},
158+
{
159+
"include": "#genericConstraints"
160+
}
161+
]
162+
},
126163
"class": {
127164
"begin": "(?=\\w?[\\w\\s]*[^@]?(?:class|struct|interface|enum)\\s+\\w+)",
128165
"end": "}",
@@ -153,18 +190,21 @@
153190
},
154191
{
155192
"begin": ":",
156-
"end": "(?={)",
193+
"end": "(?={|where)",
157194
"patterns": [
158195
{
196+
"match": "([\\w<>]+)\\s*",
159197
"captures": {
160198
"1": {
161199
"name": "storage.type.cs"
162200
}
163-
},
164-
"match": "\\s*,?([A-Za-z_]\\w*)\\b"
201+
}
165202
}
166203
]
167204
},
205+
{
206+
"include": "#genericConstraints"
207+
},
168208
{
169209
"begin": "{",
170210
"beginCaptures": {

test/syntaxes/class.tests.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe("Grammar", function() {
88
});
99

1010
describe("Class", function() {
11-
it("has a class keyword, a name and optional storage modifiers", function() {
11+
it("class keyword and storage modifiers", function() {
1212

1313
const input = `
1414
namespace TestNamespace
@@ -73,6 +73,58 @@ namespace TestNamespace
7373

7474
});
7575

76+
it("inheritance", function() {
77+
78+
const input = `
79+
namespace TestNamespace
80+
{
81+
class PublicClass : IInterface, IInterfaceTwo { }
82+
class PublicClass<T> : IInterface<T>, IInterfaceTwo { }
83+
}`;
84+
let tokens: Token[] = TokenizerUtil.tokenize(input);
85+
86+
tokens.should.contain(Tokens.ClassKeyword("class", 4, 5));
87+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 4, 11));
88+
tokens.should.contain(Tokens.Type("IInterface", 4, 28));
89+
tokens.should.contain(Tokens.Type("IInterfaceTwo", 4, 43));
90+
91+
tokens.should.contain(Tokens.ClassKeyword("class", 5, 5));
92+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 5, 11));
93+
tokens.should.contain(Tokens.Type("IInterface<T>", 5, 28));
94+
tokens.should.contain(Tokens.Type("IInterfaceTwo", 5, 43));
95+
});
96+
97+
it("generic constraints", function() {
98+
99+
const input = `
100+
namespace TestNamespace
101+
{
102+
class PublicClass<T> where T : ISomething { }
103+
class PublicClass<T, X> : List<T>, ISomething where T : ICar, new() where X : struct { }
104+
}`;
105+
let tokens: Token[] = TokenizerUtil.tokenize(input);
106+
107+
tokens.should.contain(Tokens.ClassKeyword("class", 4, 5));
108+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 4, 11));
109+
tokens.should.contain(Tokens.Keyword("where", 4, 26));
110+
tokens.should.contain(Tokens.Type("T", 4, 32));
111+
tokens.should.contain(Tokens.Type("ISomething", 4, 36));
112+
113+
tokens.should.contain(Tokens.ClassKeyword("class", 5, 5));
114+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 5, 11));
115+
tokens.should.contain(Tokens.Type("List<T>", 5, 31));
116+
tokens.should.contain(Tokens.Type("ISomething", 5, 40));
117+
tokens.should.contain(Tokens.Keyword("where", 5, 51));
118+
tokens.should.contain(Tokens.Type("T", 5, 57));
119+
tokens.should.contain(Tokens.Type("ICar", 5, 61));
120+
tokens.should.contain(Tokens.Keyword("new", 5, 67));
121+
tokens.should.contain(Tokens.Keyword("where", 5, 73));
122+
tokens.should.contain(Tokens.Type("X", 5, 79));
123+
tokens.should.contain(Tokens.Keyword("struct", 5, 83));
124+
125+
});
126+
127+
76128
});
77129
});
78130

test/syntaxes/utils/tokenizer.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,10 @@ export namespace Tokens {
7373
export const StorageModifierKeyword = (text: string, line?: number, column?: number) =>
7474
createToken(text, "storage.modifier.cs", line, column);
7575

76+
export const Type = (text: string, line?: number, column?: number) =>
77+
createToken(text, "storage.type.cs", line, column);
78+
79+
export const Keyword = (text: string, line?: number, column?: number) =>
80+
createToken(text, "keyword.other.cs", line, column);
7681
}
7782

0 commit comments

Comments
 (0)