Skip to content

Commit f47698f

Browse files
committed
Improved highlighting of generics in class identifier, inheritance and generic constraints.
1 parent 5ca75df commit f47698f

File tree

3 files changed

+57
-17
lines changed

3 files changed

+57
-17
lines changed

syntaxes/csharp.json

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,31 @@
160160
}
161161
]
162162
},
163+
"type": {
164+
"patterns": [
165+
{
166+
"match": "(\\w+\\s*<(?:[\\w\\s,\\.`\\[\\]\\*]+|\\g<1>)+>(?:\\s*\\[\\s*\\])?)",
167+
"comment": "generic type",
168+
"captures": {
169+
"1": {
170+
"name": "storage.type.cs"
171+
}
172+
}
173+
},
174+
{
175+
"match": "\\b([a-zA-Z]+[\\w]*\\b(?:\\s*\\[\\s*\\])?\\*?)",
176+
"comment": "non-generic type",
177+
"captures": {
178+
"1": {
179+
"name": "storage.type.cs"
180+
}
181+
}
182+
}
183+
]
184+
},
163185
"generic-constraints": {
164186
"begin": "(where)\\s+(\\w+)\\s*:",
165-
"end": "(?={)",
187+
"end": "(?=where|{|$)",
166188
"beginCaptures": {
167189
"1": {
168190
"name": "keyword.other.cs"
@@ -185,12 +207,7 @@
185207
}
186208
},
187209
{
188-
"match": "([\\w<>,\\[\\]]+)\\s*(?=,|where|{)",
189-
"captures": {
190-
"1": {
191-
"name": "storage.type.cs"
192-
}
193-
}
210+
"include": "#type"
194211
},
195212
{
196213
"include": "#generic-constraints"
@@ -214,21 +231,27 @@
214231
"include": "#comments"
215232
},
216233
{
217-
"captures": {
234+
"begin": "(class|struct|interface|enum)\\s+",
235+
"end": "(?={|:|$|where)",
236+
"name": "meta.class.identifier.cs",
237+
"beginCaptures": {
218238
"1": {
219239
"name": "storage.modifier.cs"
220-
},
221-
"2": {
222-
"name": "entity.name.type.class.cs"
223240
}
224241
},
225-
"match": "(class|struct|interface|enum)\\s+(\\w+)",
226-
"name": "meta.class.identifier.cs"
242+
"patterns": [
243+
{
244+
"include": "#type"
245+
}
246+
]
227247
},
228248
{
229249
"begin": ":",
230250
"end": "(?={|where)",
231251
"patterns": [
252+
{
253+
"include": "#type"
254+
},
232255
{
233256
"match": "([\\w<>]+)\\s*",
234257
"captures": {

test/syntaxes/class.tests.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,27 @@ namespace TestNamespace
7373

7474
});
7575

76+
it("generics in identifier", function () {
77+
78+
const input = `
79+
namespace TestNamespace
80+
{
81+
class Dictionary<T, Dictionary<string, string>> { }
82+
}`;
83+
let tokens: Token[] = TokenizerUtil.tokenize(input);
84+
85+
tokens.should.contain(Tokens.ClassKeyword("class", 4, 5));
86+
tokens.should.contain(Tokens.ClassIdentifier("Dictionary<T, Dictionary<string, string>>", 4, 11));
87+
});
88+
7689
it("inheritance", function() {
7790

7891
const input = `
7992
namespace TestNamespace
8093
{
8194
class PublicClass : IInterface, IInterfaceTwo { }
8295
class PublicClass<T> : IInterface<T>, IInterfaceTwo { }
96+
class PublicClass<T> : Dictionary<T, Dictionary<string, string>>, IMap<T, Dictionary<string, string>> { }
8397
}`;
8498
let tokens: Token[] = TokenizerUtil.tokenize(input);
8599

@@ -89,9 +103,12 @@ namespace TestNamespace
89103
tokens.should.contain(Tokens.Type("IInterfaceTwo", 4, 43));
90104

91105
tokens.should.contain(Tokens.ClassKeyword("class", 5, 5));
92-
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 5, 11));
106+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass<T>", 5, 11));
93107
tokens.should.contain(Tokens.Type("IInterface<T>", 5, 28));
94108
tokens.should.contain(Tokens.Type("IInterfaceTwo", 5, 43));
109+
110+
tokens.should.contain(Tokens.Type("Dictionary<T, Dictionary<string, string>>", 6, 28));
111+
tokens.should.contain(Tokens.Type("IMap<T, Dictionary<string, string>>", 6, 71));
95112
});
96113

97114
it("generic constraints", function() {
@@ -105,13 +122,13 @@ namespace TestNamespace
105122
let tokens: Token[] = TokenizerUtil.tokenize(input);
106123

107124
tokens.should.contain(Tokens.ClassKeyword("class", 4, 5));
108-
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 4, 11));
125+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass<T>", 4, 11));
109126
tokens.should.contain(Tokens.Keyword("where", 4, 26));
110127
tokens.should.contain(Tokens.Type("T", 4, 32));
111128
tokens.should.contain(Tokens.Type("ISomething", 4, 36));
112129

113130
tokens.should.contain(Tokens.ClassKeyword("class", 5, 5));
114-
tokens.should.contain(Tokens.ClassIdentifier("PublicClass", 5, 11));
131+
tokens.should.contain(Tokens.ClassIdentifier("PublicClass<T, X>", 5, 11));
115132
tokens.should.contain(Tokens.Type("Dictionary<T, List<string>[]>", 5, 31));
116133
tokens.should.contain(Tokens.Type("ISomething", 5, 62));
117134
tokens.should.contain(Tokens.Keyword("where", 5, 73));

test/syntaxes/utils/tokenizer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export namespace Tokens {
6868
createToken(text, "storage.modifier.cs", line, column);
6969

7070
export const ClassIdentifier = (text: string, line?: number, column?: number) =>
71-
createToken(text, "entity.name.type.class.cs", line, column);
71+
createToken(text, "storage.type.cs", line, column);
7272

7373
export const StorageModifierKeyword = (text: string, line?: number, column?: number) =>
7474
createToken(text, "storage.modifier.cs", line, column);

0 commit comments

Comments
 (0)