From 25ab68554b71b43dcfb3a3ffaf8d8889c98c665c Mon Sep 17 00:00:00 2001 From: Lu'ay Date: Thu, 16 Apr 2026 11:18:57 +0100 Subject: [PATCH 1/6] Added comment highlighting for .cs --- assets/highlighting-tests/cs.cs | 7 +++++++ crates/lsh/definitions/cs.lsh | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 assets/highlighting-tests/cs.cs create mode 100644 crates/lsh/definitions/cs.lsh diff --git a/assets/highlighting-tests/cs.cs b/assets/highlighting-tests/cs.cs new file mode 100644 index 00000000000..5579d066521 --- /dev/null +++ b/assets/highlighting-tests/cs.cs @@ -0,0 +1,7 @@ +// Comments +// Single-line comment + +/* +Multi-line +comment +*/ diff --git a/crates/lsh/definitions/cs.lsh b/crates/lsh/definitions/cs.lsh new file mode 100644 index 00000000000..126c278ea7f --- /dev/null +++ b/crates/lsh/definitions/cs.lsh @@ -0,0 +1,22 @@ +#[display_name = "C#"] +#[path = "**/*.cs"] +pub fn CSharp() { + until /$/ { + yield other; + + if /\/\/.*/ { + yield comment; + } else if /\/\*/ { + loop { + yield comment; + await input; + if /\*\// { + yield comment; + break; + } + } + } + + yield other; + } +} From 7f1c836c436c2d07e130ed2181bc61a23a161fbe Mon Sep 17 00:00:00 2001 From: Lu'ay Date: Thu, 16 Apr 2026 12:23:01 +0100 Subject: [PATCH 2/6] Added basic string and char highlighting --- assets/highlighting-tests/cs.cs | 117 ++++++++++++++++++++++++++++++++ crates/lsh/definitions/cs.lsh | 20 ++++++ 2 files changed, 137 insertions(+) diff --git a/assets/highlighting-tests/cs.cs b/assets/highlighting-tests/cs.cs index 5579d066521..0f732fca3f0 100644 --- a/assets/highlighting-tests/cs.cs +++ b/assets/highlighting-tests/cs.cs @@ -5,3 +5,120 @@ Multi-line comment */ + +global using static System.Console; +using System.Diagnostics; +using System; + +// Numbers +42; +3.14; +.5; +10_000_000; +1e10; +1.5e-3; +0xff; +0xFF; +0Xff; +0XFF; +0b1010; +0B1010; +42u; +42U; +42l; +42L; +42UL; +42Ul; +42uL; +42ul; +42LU; +42Lu; +42lU; +42lu; +3.14f; +3.14d; + +// Constants +true; +false; +null; + +// Strings and Characters +'a'; +'\n'; +"double quotes with escape: \" \n \t \\"; +$""; +@""; +$@""; +@$""; + +// Control flow keywords +if (true) +{ + +} +else if (false) +{ + +} +else +{ + +} + +for (int i = 0; i < 10; i++) +{ + if (i == 5) continue; + if (i == 8) break; +} + +while (false) { } +do { } while (true); + +switch (42) +{ + case 1: break; + default: break; +} + +try +{ + throw new Exception("oops"); +} +catch (System.Exception) +{ + +} +finally +{ + +} + +Debug; + +// Other keywords (some are contextually reserved) +var a = 1; +dynamic b = 2; +T c = 3; + +void Greet(string name) +{ + return "Hello, " + name; +} + +static void Greet(string name) +{ + return "Hello, " + name; +} + +async void Greet(string name) +{ + return "Hello, " + name; +} + +class Animal +{ + private int age; + protected bool isAlive; + public Animal() +} diff --git a/crates/lsh/definitions/cs.lsh b/crates/lsh/definitions/cs.lsh index 126c278ea7f..d2cae4f6fdd 100644 --- a/crates/lsh/definitions/cs.lsh +++ b/crates/lsh/definitions/cs.lsh @@ -15,6 +15,26 @@ pub fn CSharp() { break; } } + } else if /"/ { + until /$/ { + yield string; + if /\\./ {} + else if /"/ { + yield string; + break; + } + await input; + } + } else if /'/ { + until /$/ { + yield string; + if /\\./ {} + else if /'/ { + yield string; + break; + } + await input; + } } yield other; From a30040569b69da9e32e570af8cd754dd522126aa Mon Sep 17 00:00:00 2001 From: Lu'ay Date: Thu, 16 Apr 2026 19:35:45 +0100 Subject: [PATCH 3/6] Added keyword, method and numeric highlighting, numeric is not perfect --- assets/highlighting-tests/cs.cs | 6 ++++++ crates/lsh/definitions/cs.lsh | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/assets/highlighting-tests/cs.cs b/assets/highlighting-tests/cs.cs index 0f732fca3f0..f4d672fe962 100644 --- a/assets/highlighting-tests/cs.cs +++ b/assets/highlighting-tests/cs.cs @@ -18,9 +18,15 @@ 1e10; 1.5e-3; 0xff; +0xffu; +0xffl; +0xfful; 0xFF; 0Xff; 0XFF; +0XFFU; +0XFFL; +0XFFLU; 0b1010; 0B1010; 42u; diff --git a/crates/lsh/definitions/cs.lsh b/crates/lsh/definitions/cs.lsh index d2cae4f6fdd..4bb3670daa2 100644 --- a/crates/lsh/definitions/cs.lsh +++ b/crates/lsh/definitions/cs.lsh @@ -35,6 +35,24 @@ pub fn CSharp() { } await input; } + } else if /(?:global|using|static)/ { + yield keyword.control; + } else if /(?:as|break|case|catch|checked|continue|default|do|else|for|foreach|finaly|fixed|goto|if|is$|lock|return|switch|throw|try|while|unchecked|by|descending|equals|extention|from|group|into|join|nameof|on|or|orderby|select|when|where|with|yield)/ { + yield keyword.control; + } else if /(?:abstract|bool|byte|char|class|const|decimal|delegate|double|enum|event|explicit|extern|float|implicit|int|interface|internal|long|namespace|new|object|operator|out|override|params|private|protected|public|readonly|ref|sealed|short|static|string|struct|this|typeof|uint|ulong|unsafe|ushort|virtual|void|volatile|add|args|async|await|dynamic|field|file|get|init|let|managed|nint|not|notnull|nuint|partial|record|required|scoped|set|unmanaged)/ { + yield keyword.other; + } else if /(?:true|false|null)/ { + yield constant.language; + } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|[\d']+\.?[\d_]*|\.[\d]+(?i:_\d+)*)(?:p[+-]?[\d']+|e[+-]?[\d']+)?[ulfz]*)/ { + if /\w+/ { + // Invalid numeric literal + } else { + yield constant.numeric; + } + }else if /(\w+)\s*\(/ { + yield $1 as method; + } else if /\w+/ { + // Gobble word chars to align the next iteration on a word boundary. } yield other; From d0e591071188ec70f837bcd6c43fa5c93c3036e8 Mon Sep 17 00:00:00 2001 From: Lu'ay Date: Thu, 16 Apr 2026 20:05:58 +0100 Subject: [PATCH 4/6] numeric highlighting is a tad better --- crates/lsh/definitions/cs.lsh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/lsh/definitions/cs.lsh b/crates/lsh/definitions/cs.lsh index 4bb3670daa2..f3bf2d8a64b 100644 --- a/crates/lsh/definitions/cs.lsh +++ b/crates/lsh/definitions/cs.lsh @@ -25,11 +25,11 @@ pub fn CSharp() { } await input; } - } else if /'/ { + } else if /_/ { until /$/ { yield string; if /\\./ {} - else if /'/ { + else if /_/ { yield string; break; } @@ -39,16 +39,16 @@ pub fn CSharp() { yield keyword.control; } else if /(?:as|break|case|catch|checked|continue|default|do|else|for|foreach|finaly|fixed|goto|if|is$|lock|return|switch|throw|try|while|unchecked|by|descending|equals|extention|from|group|into|join|nameof|on|or|orderby|select|when|where|with|yield)/ { yield keyword.control; - } else if /(?:abstract|bool|byte|char|class|const|decimal|delegate|double|enum|event|explicit|extern|float|implicit|int|interface|internal|long|namespace|new|object|operator|out|override|params|private|protected|public|readonly|ref|sealed|short|static|string|struct|this|typeof|uint|ulong|unsafe|ushort|virtual|void|volatile|add|args|async|await|dynamic|field|file|get|init|let|managed|nint|not|notnull|nuint|partial|record|required|scoped|set|unmanaged)/ { + } else if /(?:abstract|bool|byte|char|class|const|decimal|delegate|double|enum|event|explicit|extern|float|implicit|int|interface|internal|long|namespace|new|object|operator|out|override|params|private|protected|public|readonly|ref|sealed|short|static|string|struct|this|typeof|uint|ulong|unsafe|ushort|virtual|void|volatile|add|args|async|await|dynamic|field|file|get|init|let|managed|nint|not|notnull|nuint|partial|record|required|sbyte|scoped|set|T|unmanaged|var)/ { yield keyword.other; - } else if /(?:true|false|null)/ { - yield constant.language; - } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|[\d']+\.?[\d_]*|\.[\d]+(?i:_\d+)*)(?:p[+-]?[\d']+|e[+-]?[\d']+)?[ulfz]*)/ { + } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?:p[+-]?[\d_]+|e[+-]?[\d_]+)?[ulfd]*)/ { if /\w+/ { // Invalid numeric literal } else { yield constant.numeric; } + } else if /(?:true|false|null)/ { + yield constant.language; }else if /(\w+)\s*\(/ { yield $1 as method; } else if /\w+/ { From 42f609727b973373b8593fe31a1e716d9ee4718f Mon Sep 17 00:00:00 2001 From: Lu'ay Date: Thu, 16 Apr 2026 21:01:49 +0100 Subject: [PATCH 5/6] numeric highlighting polished --- crates/lsh/definitions/cs.lsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lsh/definitions/cs.lsh b/crates/lsh/definitions/cs.lsh index f3bf2d8a64b..86ce193d207 100644 --- a/crates/lsh/definitions/cs.lsh +++ b/crates/lsh/definitions/cs.lsh @@ -41,7 +41,7 @@ pub fn CSharp() { yield keyword.control; } else if /(?:abstract|bool|byte|char|class|const|decimal|delegate|double|enum|event|explicit|extern|float|implicit|int|interface|internal|long|namespace|new|object|operator|out|override|params|private|protected|public|readonly|ref|sealed|short|static|string|struct|this|typeof|uint|ulong|unsafe|ushort|virtual|void|volatile|add|args|async|await|dynamic|field|file|get|init|let|managed|nint|not|notnull|nuint|partial|record|required|sbyte|scoped|set|T|unmanaged|var)/ { yield keyword.other; - } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?:p[+-]?[\d_]+|e[+-]?[\d_]+)?[ulfd]*)/ { + } else if /(?i:-?(?i:0x[\da-fA-F_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?i:p[+-]?[\d_]+|e[+-]?[\d_]+)?[uUlLfFdD]*)/ { if /\w+/ { // Invalid numeric literal } else { From 854cebb02e7448352e33e8719e420d670453d096 Mon Sep 17 00:00:00 2001 From: Lu'ay Date: Fri, 17 Apr 2026 09:07:28 +0100 Subject: [PATCH 6/6] Updated markdown and c# example --- assets/highlighting-tests/cs.cs | 49 +++++++++++++++++++-------- assets/highlighting-tests/markdown.md | 7 ++++ crates/lsh/definitions/cs.lsh | 10 +++--- crates/lsh/definitions/markdown.lsh | 10 ++++++ 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/assets/highlighting-tests/cs.cs b/assets/highlighting-tests/cs.cs index f4d672fe962..cee84344a91 100644 --- a/assets/highlighting-tests/cs.cs +++ b/assets/highlighting-tests/cs.cs @@ -7,7 +7,6 @@ */ global using static System.Console; -using System.Diagnostics; using System; // Numbers @@ -43,6 +42,7 @@ 42lu; 3.14f; 3.14d; +-.5_0_1e3_0d; // Constants true; @@ -53,8 +53,8 @@ 'a'; '\n'; "double quotes with escape: \" \n \t \\"; -$""; -@""; +$"double quotes with a value {1 + 1}"; +@"double quotes with "; $@""; @$""; @@ -100,31 +100,52 @@ } -Debug; - // Other keywords (some are contextually reserved) var a = 1; dynamic b = 2; T c = 3; -void Greet(string name) +string Greet(string name) { return "Hello, " + name; } -static void Greet(string name) +static int Factorial(int n) { - return "Hello, " + name; + if (n == 0) + { + return 1; + } + + return n * Factorial(n - 1); } -async void Greet(string name) +class Animal { - return "Hello, " + name; + private int _Age; + public int Age { get => _Age; } + protected bool _IsAlive; + public bool IsAlive { get => _IsAlive; } + public Animal(int age, bool isAlive) + { + _Age = age; + _IsAlive = isAlive; + } + + public virtual void Speak() { } } -class Animal +class Dog : Animal { - private int age; - protected bool isAlive; - public Animal() + private string _Bark; + + public Dog(string bark, int age, bool isAlive) : base(age, isAlive) + { + + } + + public override void Speak() + { + Console.WriteLine(_Bark); + } } diff --git a/assets/highlighting-tests/markdown.md b/assets/highlighting-tests/markdown.md index 555b182f961..b0ecfbf1d1f 100644 --- a/assets/highlighting-tests/markdown.md +++ b/assets/highlighting-tests/markdown.md @@ -84,3 +84,10 @@ export function greet(name) { def greet(name: str) -> str: return f"hello {name}" ``` + +```CSharp +public string Greet(string name) +{ + return $"hello {name}"; +} +``` diff --git a/crates/lsh/definitions/cs.lsh b/crates/lsh/definitions/cs.lsh index 86ce193d207..18cd02f67be 100644 --- a/crates/lsh/definitions/cs.lsh +++ b/crates/lsh/definitions/cs.lsh @@ -15,7 +15,7 @@ pub fn CSharp() { break; } } - } else if /"/ { + } else if /[@$]{0,2}"/ { until /$/ { yield string; if /\\./ {} @@ -25,11 +25,11 @@ pub fn CSharp() { } await input; } - } else if /_/ { + } else if /'/ { until /$/ { yield string; if /\\./ {} - else if /_/ { + else if /'/ { yield string; break; } @@ -37,11 +37,11 @@ pub fn CSharp() { } } else if /(?:global|using|static)/ { yield keyword.control; - } else if /(?:as|break|case|catch|checked|continue|default|do|else|for|foreach|finaly|fixed|goto|if|is$|lock|return|switch|throw|try|while|unchecked|by|descending|equals|extention|from|group|into|join|nameof|on|or|orderby|select|when|where|with|yield)/ { + } else if /(?:as$|break|case|catch|checked|continue|default|do|else|for|foreach|finaly|fixed|goto|if|is$|lock|return|switch|throw|try|while|unchecked|by|descending|equals|extention|from|group|into|join|nameof|on$|or$|orderby|select|when|where|with|yield)/ { yield keyword.control; } else if /(?:abstract|bool|byte|char|class|const|decimal|delegate|double|enum|event|explicit|extern|float|implicit|int|interface|internal|long|namespace|new|object|operator|out|override|params|private|protected|public|readonly|ref|sealed|short|static|string|struct|this|typeof|uint|ulong|unsafe|ushort|virtual|void|volatile|add|args|async|await|dynamic|field|file|get|init|let|managed|nint|not|notnull|nuint|partial|record|required|sbyte|scoped|set|T|unmanaged|var)/ { yield keyword.other; - } else if /(?i:-?(?i:0x[\da-fA-F_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?i:p[+-]?[\d_]+|e[+-]?[\d_]+)?[uUlLfFdD]*)/ { + } else if /(?i:-?(?i:0x[\da-fA-F_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?i:[+-]?[\d_]+|e[+-]?[\d_]+)?[uUlLfFdD]*)/ { if /\w+/ { // Invalid numeric literal } else { diff --git a/crates/lsh/definitions/markdown.lsh b/crates/lsh/definitions/markdown.lsh index 77a005fe925..784c46e29cc 100644 --- a/crates/lsh/definitions/markdown.lsh +++ b/crates/lsh/definitions/markdown.lsh @@ -90,6 +90,16 @@ pub fn markdown() { if /.*/ {} } } + } else if /(?i:C\#|CSharp|cs)/ { + loop { + await input; + if /\s*```/ { + return; + } else { + CSharp(); + if /.*/ { } + } + } } else { loop { await input;