From de94a6c8cf5e065d1e54f18ec9c374a779526247 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sun, 18 Feb 2024 19:08:24 +0100 Subject: [PATCH 1/2] [C#] Add 'required' keyword Resolves #3926 This commit adds `required` modifier which has been added by C#11. see: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required --- C#/C#.sublime-syntax | 6 +++--- C#/tests/syntax_test_C#11.cs | 22 ++++++++++++++++++++++ C#/tests/syntax_test_C#7.cs | 6 ++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/C#/C#.sublime-syntax b/C#/C#.sublime-syntax index 0d079cf087..6965d0fc5f 100644 --- a/C#/C#.sublime-syntax +++ b/C#/C#.sublime-syntax @@ -40,7 +40,7 @@ variables: brackets_capture: '((\[)(,*)(\]))' type_suffix_capture: '(\?)?{{brackets_capture}}?(?:\s*(\*))?' - reserved: '(?:abstract|as|base|break|case|catch|checked|class|const|continue|default|delegate|do|else|enum|event|explicit|extern|finally|fixed|for|foreach|goto|if|implicit|in|interface|internal|is|lock|nameof|namespace|new|not|null|operator|out|override|params|private|protected|public|readonly|ref|return|sealed|sizeof|stackalloc|static|string|struct|switch|this|throw|try|typeof|unchecked|unsafe|using|virtual|volatile|while)' + reserved: '(?:abstract|as|base|break|case|catch|checked|class|const|continue|default|delegate|do|else|enum|event|explicit|extern|finally|fixed|for|foreach|goto|if|implicit|in|interface|internal|is|lock|nameof|namespace|new|not|null|operator|out|override|params|private|protected|public|readonly|ref|required|return|sealed|sizeof|stackalloc|static|string|struct|switch|this|throw|try|typeof|unchecked|unsafe|using|virtual|volatile|while)' name: '(?:@{{reserved}}|@{{base_type}}|@var|@?{{name_normal}})' namespaced_name: (?:(?:{{name}}{{generic_declaration}}\s*\.\s*)*{{name}}{{generic_declaration}}) @@ -225,7 +225,7 @@ contexts: # allows coloration of code outside a class - match: (?=\S) push: - - match: (?={{visibility}}|\b(?:class|delegate|interface|namespace|readonly|record|static)\b) + - match: (?={{visibility}}|\b(?:class|delegate|interface|namespace|readonly|record|required|static)\b) pop: true - include: line_of_code @@ -334,7 +334,7 @@ contexts: - include: main class_declaration: - - match: '\b(static|unsafe|abstract|partial|sealed)\b' + - match: \b(static|unsafe|abstract|partial|required|sealed)\b scope: storage.modifier.cs - match: '{{visibility}}' scope: storage.modifier.access.cs diff --git a/C#/tests/syntax_test_C#11.cs b/C#/tests/syntax_test_C#11.cs index 5e914c02fa..24dbff049f 100644 --- a/C#/tests/syntax_test_C#11.cs +++ b/C#/tests/syntax_test_C#11.cs @@ -134,3 +134,25 @@ The following example shows how newlines can improve the readability of an expre /// ^^^^^^ punctuation.definition.string.begin /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - constant /// ^^^ punctuation.definition.string.end + +public class C2 { +/// <- storage.modifier.access +/// ^^^^^ keyword.declaration.class +/// ^^ entity.name.class + + public required string FirstName { get; init; } +/// ^^^^^^ storage.modifier.access +/// ^^^^^^^^ storage.modifier +/// ^^^^^^ storage.type +} + +public struct S2 { +/// <- storage.modifier.access +/// ^^^^^^ keyword.declaration.struct +/// ^^ entity.name.struct + + public required string FirstName { get; init; } +/// ^^^^^^ storage.modifier.access +/// ^^^^^^^^ storage.modifier +/// ^^^^^^ storage.type +} diff --git a/C#/tests/syntax_test_C#7.cs b/C#/tests/syntax_test_C#7.cs index 1806840a86..be9a814c28 100644 --- a/C#/tests/syntax_test_C#7.cs +++ b/C#/tests/syntax_test_C#7.cs @@ -7,6 +7,12 @@ class Foo { ///^^^^^^^^ meta.class /// ^ meta.class.body + public readonly double value; +/// ^^^^^^ storage.modifier.access +/// ^^^^^^^^ storage.modifier +/// ^^^^^^ storage.type +/// ^^^^^ variable.other.member + void Main(string[] args) { /// ^^^^ storage.type /// ^^^^^^^^^^^^^^^^^^^^^ meta.method From 0913c40fe187ea681dc0529a4fa149896651a303 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sun, 18 Feb 2024 19:13:28 +0100 Subject: [PATCH 2/2] [C#] Less strict readonly keyword matching This commit scopes `readonly` modifier more lazily to improve interoperability with `required` keyword. --- C#/C#.sublime-syntax | 21 +++++++++------------ C#/tests/syntax_test_C#10.cs | 2 +- C#/tests/syntax_test_C#11.cs | 8 +++++--- C#/tests/syntax_test_C#7.cs | 2 +- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/C#/C#.sublime-syntax b/C#/C#.sublime-syntax index 6965d0fc5f..4c3fc7e769 100644 --- a/C#/C#.sublime-syntax +++ b/C#/C#.sublime-syntax @@ -334,7 +334,7 @@ contexts: - include: main class_declaration: - - match: \b(static|unsafe|abstract|partial|required|sealed)\b + - match: \b(static|unsafe|abstract|partial|readonly|required|sealed)\b scope: storage.modifier.cs - match: '{{visibility}}' scope: storage.modifier.access.cs @@ -343,22 +343,19 @@ contexts: 1: keyword.declaration.class.cs 2: entity.name.class.cs push: [class_signature, data_type_signature] - - match: (?:\b(readonly)\s+)?\b(record)\s+(?:(struct)\s+)?({{name}}) + - match: \b(record)\s+(?:(struct)\s+)?({{name}}) captures: - 1: storage.modifier.cs - 2: keyword.declaration.class.record.cs - 3: keyword.declaration.struct.record.cs - 4: entity.name.class.cs + 1: keyword.declaration.class.record.cs + 2: keyword.declaration.struct.record.cs + 3: entity.name.class.cs push: [record_signature, data_type_constraint, record_parameters, data_type_signature] - - match: (?:\b(readonly)\s+)?(?:\b(partial)\s+)?(?:\b(ref)\s+)?\b(struct)\s+({{name}}) + - match: (?:\b(ref)\s+)?\b(struct)\s+({{name}}) captures: 1: storage.modifier.cs - 2: storage.modifier.cs - 3: storage.modifier.cs - 4: keyword.declaration.struct.cs - 5: entity.name.struct.cs + 2: keyword.declaration.struct.cs + 3: entity.name.struct.cs push: [struct_signature, data_type_signature] - - match: '\b(enum)\s+({{name}})\s*(?:(:)\s*(byte|sbyte|short|ushort|int|uint|long|ulong))?' + - match: \b(enum)\s+({{name}})\s*(?:(:)\s*(byte|sbyte|short|ushort|int|uint|long|ulong))? scope: meta.enum.cs captures: 1: keyword.declaration.enum.cs diff --git a/C#/tests/syntax_test_C#10.cs b/C#/tests/syntax_test_C#10.cs index 1434a3f350..f016b063bb 100644 --- a/C#/tests/syntax_test_C#10.cs +++ b/C#/tests/syntax_test_C#10.cs @@ -34,7 +34,7 @@ public record struct Person(string Name); public readonly record struct Person(string Name); ///^^^ storage.modifier.access -/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.record - meta.class.record meta.class.record +/// ^^^^^^^^^^^^^^^^^^^^ meta.class.record - meta.class.record meta.class.record /// ^^^^^^^^^^^^^ meta.class.record.parameters - meta.class.record meta.class.record /// ^^^^^^^^ storage.modifier /// ^^^^^^ keyword.declaration.class.record diff --git a/C#/tests/syntax_test_C#11.cs b/C#/tests/syntax_test_C#11.cs index 24dbff049f..a3c6299e8f 100644 --- a/C#/tests/syntax_test_C#11.cs +++ b/C#/tests/syntax_test_C#11.cs @@ -146,10 +146,12 @@ public class C2 { /// ^^^^^^ storage.type } -public struct S2 { +public readonly required struct S2 { /// <- storage.modifier.access -/// ^^^^^^ keyword.declaration.struct -/// ^^ entity.name.struct +/// ^^^^^^^^ storage.modifier +/// ^^^^^^^^ storage.modifier +/// ^^^^^^ keyword.declaration.struct +/// ^^ entity.name.struct public required string FirstName { get; init; } /// ^^^^^^ storage.modifier.access diff --git a/C#/tests/syntax_test_C#7.cs b/C#/tests/syntax_test_C#7.cs index be9a814c28..d154affe75 100644 --- a/C#/tests/syntax_test_C#7.cs +++ b/C#/tests/syntax_test_C#7.cs @@ -727,7 +727,7 @@ void Foo (in string s, in int x, in Point point) bytes[2] = 44; // throws IndexOutOfRangeException public readonly ref struct Span -/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.struct +/// ^^^^^^^^^^^^^^^^^^^ meta.struct /// ^ storage.modifier.access /// ^^^^^^^^ storage.modifier /// ^^^ storage.modifier