From 65b736dc19e3d9e0a3907bd59bcf706b7fff551b Mon Sep 17 00:00:00 2001 From: barkure <43804451+barkure@users.noreply.github.com> Date: Sat, 9 May 2026 14:30:50 +0800 Subject: [PATCH 1/2] Add Go and Java highlighting --- assets/highlighting-tests/go.go | 108 ++++++++++++++++++++++++++ assets/highlighting-tests/java.java | 93 ++++++++++++++++++++++ assets/highlighting-tests/markdown.md | 18 +++++ crates/lsh/definitions/go.lsh | 59 ++++++++++++++ crates/lsh/definitions/java.lsh | 56 +++++++++++++ crates/lsh/definitions/markdown.lsh | 20 +++++ 6 files changed, 354 insertions(+) create mode 100644 assets/highlighting-tests/go.go create mode 100644 assets/highlighting-tests/java.java create mode 100644 crates/lsh/definitions/go.lsh create mode 100644 crates/lsh/definitions/java.lsh diff --git a/assets/highlighting-tests/go.go b/assets/highlighting-tests/go.go new file mode 100644 index 00000000000..3b6bf3e0602 --- /dev/null +++ b/assets/highlighting-tests/go.go @@ -0,0 +1,108 @@ +// Comments +// Single-line comment + +/* + * Multi-line + * comment + */ + +package main + +import ( + "fmt" + "time" +) + +const Pi = 3.14 +var enabled = true + +// Numbers +42 +3.14 +.5 +1e10 +1.5e-3 +0xff +0XFF +0b1010 +0o77 +1_000_000 +2.5i + +// Constants +true +false +nil +iota + +// Strings and runes +'a' +'\n' +"double quotes with escape: \" \n \t \\" +`raw string +spans lines` + +// Control flow +func main() { + if enabled { + fmt.Println("enabled") + } else { + fmt.Println("disabled") + } + + for i := 0; i < 10; i++ { + if i == 5 { + continue + } + if i == 8 { + break + } + } + + switch now := time.Now().Weekday(); now { + case time.Saturday, time.Sunday: + fmt.Println("weekend") + default: + fmt.Println("weekday") + } + + values := []int{1, 2, 3} + for _, value := range values { + fmt.Println(value) + } + + ch := make(chan int, 1) + go func() { + defer close(ch) + ch <- 42 + }() + + select { + case msg := <-ch: + fmt.Println(msg) + default: + fmt.Println("no message") + } +} + +type Speaker interface { + Speak() string +} + +type Animal struct { + Name string +} + +func (a Animal) Speak() string { + return fmt.Sprintf("%s speaks", a.Name) +} + +func greet(name string) string { + return fmt.Sprintf("hello %s", name) +} + +var _ Speaker = Animal{} + +// Function calls +fmt.Println(greet("world")) +time.Now() diff --git a/assets/highlighting-tests/java.java b/assets/highlighting-tests/java.java new file mode 100644 index 00000000000..9e62f0da8fa --- /dev/null +++ b/assets/highlighting-tests/java.java @@ -0,0 +1,93 @@ +// Comments +// Single-line comment + +/* + * Multi-line + * comment + */ + +package example; + +import java.time.Instant; +import java.util.List; + +@Deprecated +public class Demo { + private static final double PI = 3.14; + private boolean enabled = true; + + // Numbers + int decimal = 42; + double fraction = 3.14; + double leadingDot = .5; + double scientific = 1.5e-3; + int hex = 0xff; + int binary = 0b1010; + long grouped = 1_000_000L; + float floatValue = 2.5f; + + // Constants + boolean yes = true; + boolean no = false; + Object nothing = null; + + // Strings and chars + char letter = 'a'; + char newline = '\n'; + String message = "double quotes with escape: \" \n \t \\"; + + public static void main(String[] args) { + Demo demo = new Demo(); + if (demo.enabled) { + System.out.println("enabled"); + } else { + System.out.println("disabled"); + } + + for (int i = 0; i < 10; i++) { + if (i == 5) { + continue; + } + if (i == 8) { + break; + } + } + + while (false) { + break; + } + + switch (args.length) { + case 0: + System.out.println("no args"); + break; + default: + System.out.println("args"); + } + + try { + demo.run(); + } catch (IllegalStateException ex) { + throw ex; + } finally { + System.out.println(Instant.now()); + } + } + + public void run() { + List names = List.of("Ada", "Grace"); + for (String name : names) { + System.out.println(greet(name)); + } + } + + public String greet(String name) { + return "hello " + name; + } +} + +record Point(int x, int y) {} + +sealed interface Shape permits Circle {} + +final class Circle implements Shape {} diff --git a/assets/highlighting-tests/markdown.md b/assets/highlighting-tests/markdown.md index 555b182f961..05f7ffa2155 100644 --- a/assets/highlighting-tests/markdown.md +++ b/assets/highlighting-tests/markdown.md @@ -66,12 +66,30 @@ Reference: ![Logo][logo-ref] echo "Hello, world" | tr a-z A-Z ``` +```go +package main + +import "fmt" + +func main() { + fmt.Println("hello") +} +``` + ```javascript export function greet(name) { return `hello ${name}`; } ``` +```java +class Demo { + static void main(String[] args) { + System.out.println("hello"); + } +} +``` + ```json { "name": "gfm-kitchen-sink", diff --git a/crates/lsh/definitions/go.lsh b/crates/lsh/definitions/go.lsh new file mode 100644 index 00000000000..920fc19cea5 --- /dev/null +++ b/crates/lsh/definitions/go.lsh @@ -0,0 +1,59 @@ +#[display_name = "Go"] +#[path = "**/*.go"] +pub fn go() { + until /$/ { + yield other; + + if /\/\/.*/ { + yield comment; + } else if /\/\*/ { + loop { + yield comment; + await input; + if /\*\// { + yield comment; + 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; + } + } else if /`/ { + loop { + yield string; + if /[^`]*/ {} + if /`/ { yield string; break; } + await input; + } + } else if /(?:break|case|continue|default|defer|else|fallthrough|for|goto|if|range|return|select|switch)\>/ { + yield keyword.control; + } else if /(?:chan|const|func|go|import|interface|map|package|struct|type|var)\>/ { + yield keyword.other; + } else if /(?:true|false|iota|nil)\>/ { + yield constant.language; + } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|0o[0-7_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?:p[+-]?[\d_]+|e[+-]?[\d_]+)?i?)/ { + 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; + } +} diff --git a/crates/lsh/definitions/java.lsh b/crates/lsh/definitions/java.lsh new file mode 100644 index 00000000000..e203eecfd2a --- /dev/null +++ b/crates/lsh/definitions/java.lsh @@ -0,0 +1,56 @@ +#[display_name = "Java"] +#[path = "**/*.java"] +pub fn java() { + until /$/ { + yield other; + + if /\/\/.*/ { + yield comment; + } else if /\/\*/ { + loop { + yield comment; + await input; + if /\*\// { + yield comment; + 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; + } + } else if /(?:break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|throws|try|while)\>/ { + yield keyword.control; + } else if /(?:abstract|assert|class|enum|extends|final|implements|import|instanceof|interface|module|native|new|package|private|protected|public|record|sealed|static|strictfp|super|synchronized|this|transient|volatile)\>/ { + yield keyword.other; + } else if /(?:boolean|byte|char|double|float|int|long|short|void|var)\>/ { + yield keyword.other; + } else if /(?:true|false|null)\>/ { + yield constant.language; + } else if /@\w+/ { + yield markup.link; + } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?:p[+-]?[\d_]+|e[+-]?[\d_]+)?[dfl]?)/ { + 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; + } +} diff --git a/crates/lsh/definitions/markdown.lsh b/crates/lsh/definitions/markdown.lsh index 77a005fe925..5bd91395dc9 100644 --- a/crates/lsh/definitions/markdown.lsh +++ b/crates/lsh/definitions/markdown.lsh @@ -28,6 +28,16 @@ pub fn markdown() { if /.*/ {} } } + } else if /(?i:go|golang)/ { + loop { + await input; + if /\s*```/ { + return; + } else { + go(); + if /.*/ {} + } + } } else if /(?i:diff)/ { loop { await input; @@ -50,6 +60,16 @@ pub fn markdown() { if /.*/ {} } } + } else if /(?i:java)/ { + loop { + await input; + if /\s*```/ { + return; + } else { + java(); + if /.*/ {} + } + } } else if /(?i:json)/ { loop { await input; From fcc16647eada3bc2154caf882c5eff78b55c726a Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Thu, 30 Jul 2026 21:45:03 +0200 Subject: [PATCH 2/2] Simplify LSH --- assets/highlighting-tests/go.go | 188 ++++++++++++++------------ assets/highlighting-tests/markdown.md | 28 ---- crates/lsh/definitions/go.lsh | 32 ++--- crates/lsh/definitions/markdown.lsh | 32 +---- 4 files changed, 119 insertions(+), 161 deletions(-) diff --git a/assets/highlighting-tests/go.go b/assets/highlighting-tests/go.go index 3b6bf3e0602..517715dc6d8 100644 --- a/assets/highlighting-tests/go.go +++ b/assets/highlighting-tests/go.go @@ -1,6 +1,4 @@ -// Comments -// Single-line comment - +// Line comment /* * Multi-line * comment @@ -9,100 +7,124 @@ package main import ( - "fmt" - "time" + "fmt" + "time" ) -const Pi = 3.14 -var enabled = true - // Numbers -42 -3.14 -.5 -1e10 -1.5e-3 -0xff -0XFF -0b1010 -0o77 -1_000_000 -2.5i - -// Constants -true -false -nil -iota +const ( + Dec = 42 + Neg = -7 + Hex = 0xCAFE_BABE + Oct = 0o755 + Old = 0755 + Bin = 0b1010 + Sep = 1_000_000 + Flt = 3.14 + Half = .5 + Exp = 1e10 + Sci = 1.5e-3 + Imag = 2.5i +) -// Strings and runes -'a' -'\n' -"double quotes with escape: \" \n \t \\" -`raw string -spans lines` +// Constants and iota +const ( + A = iota + B +) -// Control flow -func main() { - if enabled { - fmt.Println("enabled") - } else { - fmt.Println("disabled") - } - - for i := 0; i < 10; i++ { - if i == 5 { - continue - } - if i == 8 { - break - } - } - - switch now := time.Now().Weekday(); now { - case time.Saturday, time.Sunday: - fmt.Println("weekend") - default: - fmt.Println("weekday") - } - - values := []int{1, 2, 3} - for _, value := range values { - fmt.Println(value) - } - - ch := make(chan int, 1) - go func() { - defer close(ch) - ch <- 42 - }() - - select { - case msg := <-ch: - fmt.Println(msg) - default: - fmt.Println("no message") - } -} +var ( + yes = true + no = false + none = nil +) + +// Predeclared types +var ( + b bool + by byte + r rune + s string + i int + i8 int8 + i64 int64 + u uint + u32 uint32 + up uintptr + f64 float64 + c128 complex128 + e error + a any +) + +// Strings and runes +var ( + char = 'a' + escaped = '\n' + quote = '\'' + str = "double quotes with escapes: \" \n \t \\" + raw = `raw string +spans lines and may contain "quotes"` +) type Speaker interface { - Speak() string + Speak() string } type Animal struct { - Name string + Name string `json:"name"` } func (a Animal) Speak() string { - return fmt.Sprintf("%s speaks", a.Name) + return fmt.Sprintf("%s speaks", a.Name) } -func greet(name string) string { - return fmt.Sprintf("hello %s", name) +func compare[T comparable](a, b T) bool { + return a == b } -var _ Speaker = Animal{} - -// Function calls -fmt.Println(greet("world")) -time.Now() +func main() { + if yes { + fmt.Println("enabled") + } else { + fmt.Println("disabled") + } + + for i := 0; i < 10; i++ { + switch { + case i == 5: + continue + case i == 8: + goto done + default: + fallthrough + } + } + + switch now := time.Now().Weekday(); now { + case time.Saturday, time.Sunday: + fmt.Println("weekend") + } + + values := []int{1, 2, 3} + m := map[string]int{"one": 1} + for _, value := range values { + fmt.Println(value, m) + } + + ch := make(chan int, 1) + go func() { + defer close(ch) + ch <- 42 + }() + + select { + case msg := <-ch: + fmt.Println(msg) + default: + fmt.Println("no message") + } + +done: + var _ Speaker = Animal{Name: "dog"} +} diff --git a/assets/highlighting-tests/markdown.md b/assets/highlighting-tests/markdown.md index bf33fb5dc70..555b182f961 100644 --- a/assets/highlighting-tests/markdown.md +++ b/assets/highlighting-tests/markdown.md @@ -66,30 +66,12 @@ Reference: ![Logo][logo-ref] echo "Hello, world" | tr a-z A-Z ``` -```go -package main - -import "fmt" - -func main() { - fmt.Println("hello") -} -``` - ```javascript export function greet(name) { return `hello ${name}`; } ``` -```java -class Demo { - static void main(String[] args) { - System.out.println("hello"); - } -} -``` - ```json { "name": "gfm-kitchen-sink", @@ -98,16 +80,6 @@ class Demo { } ``` -```lua -local function greet(name) - return "hello " .. name -end -``` - -```luau -export type Greeting = (name: string) -> string -``` - ```python def greet(name: str) -> str: return f"hello {name}" diff --git a/crates/lsh/definitions/go.lsh b/crates/lsh/definitions/go.lsh index 920fc19cea5..8b1d82c5279 100644 --- a/crates/lsh/definitions/go.lsh +++ b/crates/lsh/definitions/go.lsh @@ -15,34 +15,28 @@ pub fn go() { 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; - } } else if /`/ { loop { yield string; - if /[^`]*/ {} - if /`/ { yield string; break; } + if /`/ { + yield string; + break; + } await input; } - } else if /(?:break|case|continue|default|defer|else|fallthrough|for|goto|if|range|return|select|switch)\>/ { + } else if /'/ { + single_quote_string(); + } else if /"/ { + double_quote_string(); + } else if /(?:break|case|continue|default|defer|else|fallthrough|for|goto|go|if|range|return|select|switch)\>/ { yield keyword.control; - } else if /(?:chan|const|func|go|import|interface|map|package|struct|type|var)\>/ { + } else if /(?:chan|const|func|import|interface|map|package|struct|type|var)\>/ { yield keyword.other; } else if /(?:true|false|iota|nil)\>/ { yield constant.language; - } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|0o[0-7_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?:p[+-]?[\d_]+|e[+-]?[\d_]+)?i?)/ { + } else if /(?:any|bool|byte|comparable|complex128|complex64|error|float32|float64|int8|int16|int32|int64|int|rune|string|uint8|uint16|uint32|uint64|uintptr|uint)\>/ { + yield storage.type; + } else if /(?i:-?(?:0x[\da-f_]+|0b[01_]+|0o[0-7_]+|\d[\d_]*\.?[\d_]*|\.[\d_]+)(?:[ep][+-]?[\d_]+)?i?)/ { if /\w+/ { // Invalid numeric literal } else { diff --git a/crates/lsh/definitions/markdown.lsh b/crates/lsh/definitions/markdown.lsh index a3e220376fd..2abaa580c00 100644 --- a/crates/lsh/definitions/markdown.lsh +++ b/crates/lsh/definitions/markdown.lsh @@ -28,16 +28,6 @@ pub fn markdown() { if /.*/ {} } } - } else if /(?i:go|golang)/ { - loop { - await input; - if /\s*```/ { - return; - } else { - go(); - if /.*/ {} - } - } } else if /(?i:diff)/ { loop { await input; @@ -60,16 +50,6 @@ pub fn markdown() { if /.*/ {} } } - } else if /(?i:java)/ { - loop { - await input; - if /\s*```/ { - return; - } else { - java(); - if /.*/ {} - } - } } else if /(?i:json)/ { loop { await input; @@ -80,17 +60,7 @@ pub fn markdown() { if /.*/ {} } } - } else if /(?i:lua|luau)/ { - loop { - await input; - if /\s*```/ { - return; - } else { - lua(); - if /.*/ {} - } - } - } else if /(?i:py)/ { + } else if /(?i:py|python)/ { loop { await input; if /\s*```/ {