Skip to content

Commit 729d6ae

Browse files
authored
Add Odin highlighting (#863)
1 parent 6301ef3 commit 729d6ae

4 files changed

Lines changed: 217 additions & 0 deletions

File tree

assets/highlighting-tests/markdown.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,9 @@ export function greet(name) {
8484
def greet(name: str) -> str:
8585
return f"hello {name}"
8686
```
87+
88+
```odin
89+
greet :: proc(name: string) -> string {
90+
return fmt.tprintf("hello %s", name)
91+
}
92+
```
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// Line comment
2+
/*
3+
* Multi-line
4+
* comment
5+
*/
6+
7+
#+feature dynamic-literals
8+
package main
9+
10+
import "core:fmt"
11+
12+
// Numbers
13+
Dec :: 42
14+
Neg :: -7
15+
Hex :: 0xCAFE_BABE
16+
Oct :: 0o755
17+
Bin :: 0b1010
18+
Sep :: 1_000_000
19+
Flt :: 3.14
20+
Half :: .5
21+
Exp :: 1e10
22+
Sci :: 1.5e-3
23+
Imag :: 2i
24+
Quat :: 3j
25+
HexF :: 0h3f800000
26+
Bad :: 1abc
27+
28+
// Constants
29+
yes := true
30+
no := false
31+
none := nil
32+
_ = 0
33+
34+
// Basic types
35+
b: bool
36+
b32v: b32
37+
r: rune
38+
s: string
39+
cs: cstring
40+
i: int
41+
i128v: i128
42+
u: uint
43+
up: uintptr
44+
u32b: u32be
45+
i16l: i16le
46+
f16v: f16
47+
f64v: f64
48+
c128: complex128
49+
q256: quaternion256
50+
p: rawptr
51+
t: typeid
52+
a: any
53+
54+
// Strings and runes
55+
char := 'a'
56+
escaped := '\n'
57+
quote := '\''
58+
str := "double quotes with escapes: \" \n \t \\"
59+
raw := `raw string
60+
spans lines and may contain "quotes"`
61+
62+
Speaker :: struct #packed {
63+
name: string `fmt:"q"`,
64+
}
65+
66+
Value :: union {int, f64}
67+
68+
Direction :: enum {North, South}
69+
70+
Flags :: bit_set[Direction]
71+
72+
Meters :: distinct f32
73+
74+
Header :: bit_field u32 {
75+
tag: u8 | 3,
76+
}
77+
78+
@(deprecated = "use speak instead")
79+
old_speak :: proc(s: Speaker) -> string {
80+
return fmt.tprintf("%s speaks", s.name)
81+
}
82+
83+
@private
84+
compare :: proc(a, b: $T) -> bool where intrinsics.type_is_comparable(T) {
85+
return a == b
86+
}
87+
88+
foreign import kernel32 "system:kernel32.lib"
89+
90+
@(default_calling_convention = "std")
91+
foreign kernel32 {
92+
ExitProcess :: proc(code: u32) ---
93+
}
94+
95+
main :: proc() {
96+
if yes {
97+
fmt.println("enabled")
98+
} else when ODIN_DEBUG {
99+
fmt.println("debug")
100+
} else {
101+
fmt.println("disabled")
102+
}
103+
104+
for i := 0; i < 10; i += 1 {
105+
switch {
106+
case i == 5:
107+
continue
108+
case i == 8:
109+
break
110+
case:
111+
fallthrough
112+
}
113+
}
114+
115+
for i in 0..<10 {}
116+
for i in 0..=9 {}
117+
118+
values := [dynamic]int{1, 2, 3}
119+
m := map[string]int{"one" = 1}
120+
defer delete(values)
121+
for value, index in values {
122+
fmt.println(index, value, m["one"])
123+
}
124+
125+
v: Value = 137
126+
#partial switch _ in v {
127+
case int:
128+
fmt.println("int")
129+
}
130+
131+
soa: #soa[4]Speaker
132+
#unroll for i in 0..<2 {}
133+
134+
x := cast(int)3.14
135+
y := transmute(u32)f32(1)
136+
z := auto_cast x
137+
w := m["two"] or_else 0
138+
_, _, _, _ = x, y, z, w
139+
140+
#assert(size_of(u8) == 1)
141+
context.user_index = 1
142+
ptr := &x
143+
ptr^ = 456
144+
}

crates/lsh/definitions/markdown.lsh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ pub fn markdown() {
6060
if /.*/ {}
6161
}
6262
}
63+
} else if /(?i:odin)/ {
64+
loop {
65+
await input;
66+
if /\s*```/ {
67+
return;
68+
} else {
69+
odin();
70+
if /.*/ {}
71+
}
72+
}
6373
} else if /(?i:py|python)/ {
6474
loop {
6575
await input;

crates/lsh/definitions/odin.lsh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#[display_name = "Odin"]
2+
#[path = "**/*.odin"]
3+
pub fn odin() {
4+
until /$/ {
5+
yield other;
6+
7+
if /\/\/.*/ {
8+
yield comment;
9+
} else if /\/\*/ {
10+
loop {
11+
yield comment;
12+
await input;
13+
if /\*\// {
14+
yield comment;
15+
break;
16+
}
17+
}
18+
} else if /`/ {
19+
loop {
20+
yield string;
21+
if /`/ {
22+
yield string;
23+
break;
24+
}
25+
await input;
26+
}
27+
} else if /'/ {
28+
single_quote_string();
29+
} else if /"/ {
30+
double_quote_string();
31+
} else if /(?:break|case|continue|defer|do|else|fallthrough|for|if|in|not_in|or_break|or_continue|or_else|or_return|return|switch|when|where)\>/ {
32+
yield keyword.control;
33+
} else if /(?:asm|auto_cast|bit_field|bit_set|cast|context|distinct|dynamic|enum|foreign|import|map|matrix|package|proc|struct|transmute|union|using)\>/ {
34+
yield keyword.other;
35+
} else if /(?:true|false|nil)\>/ {
36+
yield constant.language;
37+
} else if /(?:any|bool|complex(?:32|64|128)|cstring|int|quaternion(?:64|128|256)|rawptr|rune|string|typeid|uintptr|uint|(?:[iu](?:8|16|32|64|128)|f(?:16|32|64)|b(?:8|16|32|64))(?:be|le)?)\>/ {
38+
yield storage.type;
39+
} else if /-?(?:0[xh][\da-fA-F_]+|0b[01_]+|0o[0-7_]+|\d[\d_]*\.[\d_]+|\d[\d_]*|\.\d[\d_]*)(?:[eE][+-]?[\d_]+)?[ijk]?/ {
40+
if /\w+/ {
41+
// Invalid numeric literal
42+
} else {
43+
yield constant.numeric;
44+
}
45+
} else if /#\+?\w+/ {
46+
yield keyword.other;
47+
} else if /@\w*/ {
48+
yield storage.annotation;
49+
} else if /(\w+)\s*\(/ {
50+
yield $1 as method;
51+
} else if /\w+/ {
52+
// Gobble word chars to align the next iteration on a word boundary.
53+
}
54+
55+
yield other;
56+
}
57+
}

0 commit comments

Comments
 (0)