Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 70 additions & 24 deletions editors/vscode/syntaxes/odin.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@
"patterns": [
{ "include": "#attribute" },
{ "include": "#procedure-assignment" },
{ "include": "#enum-assignment" },
{ "include": "#type-assignment" },
{ "include": "#distinct-type-assignment" },
{ "include": "#for-in-assignment" },
{ "include": "#constant-assignment" },
{ "include": "#variable-assignment" },
{ "include": "#case-clause" },
Expand All @@ -69,8 +71,10 @@
"assignments": {
"patterns": [
{ "include": "#procedure-assignment" },
{ "include": "#enum-assignment" },
{ "include": "#type-assignment" },
{ "include": "#distinct-type-assignment" },
{ "include": "#for-in-assignment" },
{ "include": "#constant-assignment" },
{ "include": "#variable-assignment" },
{ "include": "#type-annotation" }
Expand Down Expand Up @@ -115,8 +119,8 @@
"match": "\\b([A-Za-z_]\\w*)\\b",
"name": "entity.other.attribute-name.odin"
}, {
"match": ",",
"name": "punctuation.odin"
"name": "punctuation.odin",
"match": ","
},{
"begin": "=",
"beginCaptures": {"0": {"name": "keyword.operator.assignment.odin"}},
Expand All @@ -127,11 +131,13 @@
},
"procedure-assignment": {
"name": "meta.definition.variable.odin",
"begin": "\\b([A-Za-z_]\\w*)\\s*(:\\s*:|=)\\s*(#\\w+)?\\s*(?=proc\\b)",
"begin": "\\b([A-Za-z_]\\w*)\\s*(:)\\s*\\w*\\s*(:|=)\\s*(?:(#)(\\w+))?\\s*(?=proc\\b)",
"beginCaptures": {
"1": { "name": "meta.definition.function.odin entity.name.function.odin" },
"2": { "name": "keyword.operator.assignment.odin" },
"3": { "name": "keyword.other.odin" }
"2": { "name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" },
"3": { "name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" },
"4": { "name": "keyword.control.directive.odin" },
"5": { "name": "entity.other.directive-name.odin" }
},
"end": "(?=^)|(?<=\\})",
"patterns": [ { "include": "#type-declaration" } ]
Expand All @@ -140,8 +146,8 @@
"name": "meta.definition.variable.odin",
"begin": "\\b([A-Za-z_]\\w*)\\s*(:\\s*:)\\s*(?=(struct|union|enum|bit_set|bit_field)\\b)",
"beginCaptures": {
"1": { "name": "entity.name.type.odin" },
"2": { "name": "keyword.operator.assignment.odin" },
"1": { "name": "entity.name.type.odin entity.name.constant.odin" },
"2": { "name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" },
"3": { "name": "storage.type.odin" }
},
"end": "(?=^)|(?<=\\})",
Expand All @@ -151,8 +157,8 @@
"name": "meta.definition.variable.odin",
"begin": "\\b([A-Za-z_]\\w*)\\s*(:\\s*:)\\s*(?=(distinct)\\b)",
"beginCaptures": {
"1": { "name": "entity.name.type.odin" },
"2": { "name": "keyword.operator.assignment.odin" },
"1": { "name": "entity.name.type.odin entity.name.constant.odin" },
"2": { "name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" },
"3": { "name": "storage.type.odin" }
},
"end": "(?=^)|(?<=\\})",
Expand All @@ -162,32 +168,57 @@
"name": "meta.definition.variable.odin",
"match": "([A-Za-z_]\\w*)\\s*(:\\s*:)",
"captures": {
"1": { "name": "variable.other.constant.odin" },
"2": { "name": "keyword.operator.assignment.odin" }
"1": { "name": "variable.other.constant.odin entity.name.constant.odin" },
"2": { "name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" }
}
},
"for-in-assignment": {
"name": "meta.definition.for-in.odin",
"match": "for\\s+(?:(\\&)?([A-Za-z_]\\w*)\\s*(,)\\s*)?(\\&)?([A-Za-z_]\\w*)\\s*(in)\\b",
"captures": {
"1": { "name": "punctuation.odin" },
"2": { "name": "variable.name.odin entity.name.variable.odin" },
"3": { "name": "punctuation.odin" },
"4": { "name": "punctuation.odin" },
"5": { "name": "variable.name.odin entity.name.variable.odin" },
"6": { "name": "keyword.control.odin" }
}
},
"variable-assignment": {
"name": "meta.definition.variable.odin",
"match": "(?:([A-Za-z_]\\w*)\\s*(,)\\s*)?(?:([A-Za-z_]\\w*)\\s*(,)\\s*)?([A-Za-z_]\\w*)\\s*(:\\s*=)",
"captures": {
"1": { "name": "variable.name.odin" },
"1": { "name": "variable.name.odin entity.name.variable.odin" },
"2": { "name": "punctuation.odin" },
"3": { "name": "variable.name.odin" },
"3": { "name": "variable.name.odin entity.name.variable.odin" },
"4": { "name": "punctuation.odin" },
"5": { "name": "variable.name.odin" },
"6": { "name": "keyword.operator.assignment.odin" }
"5": { "name": "variable.name.odin entity.name.variable.odin" },
"6": { "name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" }
}
},
"enum-assignment": {
"name": "meta.definition.enum.odin",
"begin": "([A-Za-z_]\\w*)\\s*:\\s*:\\s*(enum)\\s*(?=\\w*\\s*\\{)",
"beginCaptures": {
"1": { "name": "entity.name.enum.odin" },
"2": { "name": "keyword.enum.odin" }
},
"end": "\\}",
"endCaptures": {
"0": { "name": "punctuation.definition.block.odin" }
},
"patterns": [ { "include": "#statements" } ]
},
"type-annotation": {
"name": "meta.type.annotation.odin",
"begin": "(?:([A-Za-z_]\\w*)\\s*(,)\\s*)?(?:([A-Za-z_]\\w*)\\s*(,)\\s*)?([A-Za-z_]\\w*)\\s*(:)",
"beginCaptures": {
"1": { "name": "variable.name.odin" },
"1": { "name": "variable.name.odin entity.name.variable.odin" },
"2": { "name": "punctuation.odin" },
"3": { "name": "variable.name.odin" },
"3": { "name": "variable.name.odin entity.name.variable.odin" },
"4": { "name": "punctuation.odin" },
"5": { "name": "variable.name.odin" },
"6": { "name": "keyword.operator.type.annotation.odin" }
"5": { "name": "variable.name.odin entity.name.variable.odin" },
"6": { "name": "keyword.operator.type.annotation.odin keyword.operator.declaration.odin" }
},
"end": "(?=^|,|;|\\)|=|:|for|switch|if|{)",
"patterns": [ { "include": "#type-declaration" } ]
Expand Down Expand Up @@ -451,7 +482,11 @@
},
{
"name": "keyword.control.odin",
"match": "\\b(if|else|or_else|when|where|for|in|not_in|defer|switch|return|or_return)\\b"
"match": "\\b(if|else|or_else|when|where|for|in|not_in|defer|switch)\\b"
},
{
"name": "keyword.control.odin keyword.control.jumpy.odin",
"match": "\\b(return|or_return)\\b"
},
{
"match": "\\b(break|or_break|continue|or_continue)\\b\\s*(\\w+)?",
Expand Down Expand Up @@ -506,11 +541,13 @@
},
{
"name": "keyword.operator.assignment.compound.odin",
"match": "[+\\-*/%]=|%%="
"match": "([+\\-*/%]%?)=",
"captures": {"1": {"name": "keyword.operator.in-compound" }}
},
{
"name": "keyword.operator.assignment.compound.bitwise.odin",
"match": "\\|=|~=|&~?=|<<=|>>="
"match": "(\\||~|&~?|<<|>>)=",
"captures": {"1": {"name": "keyword.operator.in-compound" }}
},
{
"name": "keyword.operator.comparison.odin",
Expand All @@ -530,7 +567,12 @@
},
{
"name": "keyword.operator.assignment.odin",
"match": ":[:=]|="
"match": "(:)=|(::)|(=)",
"captures": {
"1": {"name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" },
"2": {"name": "keyword.operator.assignment.odin keyword.operator.declaration.odin" },
"3": {"name": "keyword.operator.assignment.odin" }
}
},
{
"name": "keyword.operator.address.odin",
Expand All @@ -550,7 +592,11 @@
},
{
"name": "entity.name.tag.odin",
"match": "#[A-Za-z_]\\w*"
"match": "(#)([A-Za-z_]\\w*)",
"captures": {
"1": { "name": "keyword.control.directive.odin" },
"2": { "name": "entity.other.directive-name.odin" }
}
}
]
},
Expand Down
14 changes: 9 additions & 5 deletions src/server/semantic_tokens.odin
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/spe
*/
package server

import "core:log"
import "core:odin/ast"
import "core:odin/tokenizer"
import "core:unicode/utf8"
Expand Down Expand Up @@ -245,7 +246,7 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder) {
visit_node(n.row_index, builder)
visit_node(n.column_index, builder)
case ^ast.Poly_Type:
write_semantic_node(builder, n.type, .TypeParameter)
write_semantic_node(builder, n.type, .TypeParameter, {.Declaration})
visit_node(n.specialization, builder)
case ^ast.Range_Stmt:
for val in n.vals {
Expand Down Expand Up @@ -403,6 +404,7 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder) {

visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder) {
modifiers: SemanticTokenModifiers = value_decl.is_mutable ? {} : {.ReadOnly}
modifiers += {.Declaration}

for name in value_decl.names {
ident := name.derived.(^ast.Ident) or_continue
Expand All @@ -425,7 +427,7 @@ visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder) {
for param in node.params.list {
for name in param.names {
if ident, ok := name.derived.(^ast.Ident); ok {
write_semantic_node(builder, name, .Parameter)
write_semantic_node(builder, name, .Parameter, {.Declaration})
}
}

Expand All @@ -436,7 +438,9 @@ visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder) {

if node.results != nil {
for result in node.results.list {
visit_nodes(result.names, builder)
for name in result.names {
write_semantic_node(builder, name, .Variable, {.Declaration})
}
visit_node(result.type, builder)
}
}
Expand Down Expand Up @@ -467,7 +471,7 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde
for field in node.fields.list {
for name in field.names {
if ident, ok := name.derived.(^ast.Ident); ok {
write_semantic_node(builder, ident, .Property)
write_semantic_node(builder, ident, .Property, {.Declaration})
}
}

Expand All @@ -483,7 +487,7 @@ visit_poly_params :: proc(params: ^ast.Field_List, builder: ^SemanticTokenBuilde
for param in params.list {
for name in param.names {
if poly, ok := name.derived.(^ast.Poly_Type); ok {
write_semantic_node(builder, poly.type, .TypeParameter)
write_semantic_node(builder, poly.type, .TypeParameter, {.Declaration})
}
}
visit_node(param.type, builder)
Expand Down
4 changes: 3 additions & 1 deletion src/testing/testing.odin
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ expect_action_with_edit :: proc(t: ^testing.T, src: ^Source, action_name: string
log.errorf("Action '%s' not found in actions: %v", action_name, actions)
}

expect_semantic_tokens :: proc(t: ^testing.T, src: ^Source, expected: []server.SemanticToken) {
expect_semantic_tokens :: proc(t: ^testing.T, src: ^Source, expected: []server.SemanticToken, loc := #caller_location) {
setup(src)
defer teardown(src)

Expand All @@ -723,6 +723,7 @@ expect_semantic_tokens :: proc(t: ^testing.T, src: ^Source, expected: []server.S
"\nExpected %d tokens, but received %d",
len(expected),
len(tokens),
loc=loc,
)

for i in 0 ..< min(len(expected), len(tokens)) {
Expand All @@ -742,6 +743,7 @@ expect_semantic_tokens :: proc(t: ^testing.T, src: ^Source, expected: []server.S
a.len,
a.type,
a.modifiers,
loc=loc,
)
}
}
Expand Down
Loading
Loading