Expand Gotlin language and tooling

This commit is contained in:
pavel 2026-08-27 01:46:57 +02:00
commit de1262b4cf
41 changed files with 6059 additions and 379 deletions

View file

@ -1,58 +1,47 @@
# vscode-gotlin
# Gotlin for VS Code
Minimal VS Code extension for `.gt` files.
VS Code language support for Gotlin (`.gt`) files.
It does two things:
## Features
- registers `.gt` as the `gotlin` language
- launches `gotlin-lsp` over stdio
- TextMate highlighting for current Gotlin declarations, control flow, concurrency, exceptions, types, annotations, pointers, nullable types, generics, and numeric literals
- Dedicated highlighting for the typed `sql` DSL and its query, mutation, and execution methods
- Go import highlighting for bare dotted paths, aliases, and quoted module paths
- Bracket matching, indentation, folding markers, comments, and editor pairs
- Snippets for data classes, SQL table rows and operations, workers, embeds, concurrency, defer, and foreach loops
- `gotlin-lsp` integration, including its optional `gopls` bridge for Go-imported symbols
It also includes:
## Development
- syntax highlighting
- bracket/comment configuration
- basic Gotlin snippets
- optional `gopls` bridge for hover/definition on Go-imported symbols
## Setup
From this folder:
From this directory:
```bash
npm install
npm run build
npm run check
```
Then in VS Code:
`npm run build` compiles the extension and `npm test` validates all JSON contribution files plus key current grammar tokens and snippets without additional test dependencies.
1. Open this folder as an extension project.
2. Press `F5` to launch an Extension Development Host.
3. Open your Gotlin workspace in that host.
To run the extension, open this directory in VS Code and press `F5`. In the Extension Development Host, open a Gotlin workspace containing `.gt` files.
## Server path
## Language Server
By default the extension looks for:
```text
<workspace>/bin/gotlin-lsp
```
If your binary lives somewhere else, set:
The extension first looks for the platform-specific server binary at `<workspace>/bin/gotlin-lsp`, then falls back to `gotlin-lsp` on `PATH`. Override it with:
```json
"gotlin.serverPath": "/absolute/path/to/gotlin-lsp"
```
If `gopls` is not on your PATH, also set:
If `gopls` is not on `PATH`, configure:
```json
"gotlin.goplsPath": "/absolute/path/to/gopls"
```
## Build the language server
From the repo root:
Build the language server from the repository root with:
```bash
go build -o ./bin/gotlin-lsp ./cmd/gotlin-lsp
```
The extension activates when a Gotlin document is opened and communicates with the server over stdio.

View file

@ -2,55 +2,43 @@
"comments": {
"lineComment": "//"
},
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\\"\\'\\,\\.\\<\\>\\/\\?\\s]+)",
"wordPattern": "[A-Za-z_][A-Za-z0-9_]*|-?[0-9]+(?:\\.[0-9]+)?",
"brackets": [
[
"{",
"}"
],
[
"(",
")"
]
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
{
"open": "{",
"close": "}"
},
{
"open": "(",
"close": ")"
},
{
"open": "\"",
"close": "\""
}
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "\"", "close": "\"", "notIn": ["string", "comment"] }
],
"surroundingPairs": [
[
"{",
"}"
],
[
"(",
")"
],
[
"\"",
"\""
]
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""]
],
"folding": {
"markers": {
"start": "^\\s*//\\s*(?:#?region)\\b",
"end": "^\\s*//\\s*(?:#?endregion)\\b"
}
},
"indentationRules": {
"increaseIndentPattern": "^.*\\{\\s*$",
"increaseIndentPattern": "^.*\\{[^}]*$",
"decreaseIndentPattern": "^\\s*\\}"
},
"onEnterRules": [
{
"beforeText": "^.*\\{\\s*$",
"action": {
"indent": "indent"
}
"afterText": "^\\s*\\}",
"action": { "indent": "indentOutdent" }
},
{
"beforeText": "^.*\\{\\s*$",
"action": { "indent": "indent" }
}
]
}

View file

@ -1,12 +1,12 @@
{
"name": "gotlin-vscode",
"version": "0.0.1",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gotlin-vscode",
"version": "0.0.1",
"version": "0.1.0",
"license": "UNLICENSED",
"dependencies": {
"vscode-languageclient": "^9.0.1"

View file

@ -1,8 +1,8 @@
{
"name": "gotlin-vscode",
"displayName": "Gotlin",
"description": "VS Code support for Gotlin (.gt) files",
"version": "0.0.1",
"description": "Gotlin language support with syntax highlighting, snippets, and LSP integration",
"version": "0.1.0",
"publisher": "local",
"license": "UNLICENSED",
"engines": {
@ -12,7 +12,7 @@
"Programming Languages"
],
"activationEvents": [
"onLanguage:gotlin"
],
"main": "./out/extension.js",
"contributes": {
@ -60,7 +60,9 @@
},
"scripts": {
"build": "tsc -p .",
"watch": "tsc -w -p ."
"watch": "tsc -w -p .",
"test": "node scripts/validate.js",
"check": "npm run build && npm test"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"

View file

@ -0,0 +1,90 @@
"use strict";
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const root = path.resolve(__dirname, "..");
function readJSON(relativePath) {
return JSON.parse(fs.readFileSync(path.join(root, relativePath), "utf8"));
}
const packageJSON = readJSON("package.json");
const language = readJSON("language-configuration.json");
const grammar = readJSON("syntaxes/gotlin.tmLanguage.json");
const snippets = readJSON("snippets/gotlin.code-snippets");
function validateRegexes(value) {
if (Array.isArray(value)) {
value.forEach(validateRegexes);
return;
}
if (!value || typeof value !== "object") {
return;
}
for (const [key, child] of Object.entries(value)) {
if (["match", "begin", "end"].includes(key)) {
assert.doesNotThrow(() => new RegExp(child), `invalid ${key} regex: ${child}`);
} else {
validateRegexes(child);
}
}
}
validateRegexes(grammar);
assert.equal(packageJSON.version, "0.1.0");
assert(packageJSON.activationEvents.includes("onLanguage:gotlin"));
assert.equal(packageJSON.contributes.grammars[0].scopeName, "source.gotlin");
assert(language.brackets.some(([open, close]) => open === "[" && close === "]"));
assert(language.folding?.markers?.start && language.indentationRules?.increaseIndentPattern);
const grammarSource = JSON.stringify(grammar);
const expectedTokens = [
"data", "class", "worker", "private", "override", "val", "var", "if", "else",
"while", "for", "in", "select", "return", "go", "defer", "try", "catch",
"throw", "enum", "match", "package", "import", "jsonNaming", "embed", "table", "column", "id",
"generated", "Int", "String", "Boolean", "Unit", "Double", "Float", "Any",
"ByteSlice", "List", "MutableList", "Map", "MutableMap", "Channel", "GotlinSQLQuery",
"GotlinSQLIterator", "from", "where", "orderBy", "orderByDescending", "limit",
"forUpdate", "skipLocked", "insert", "update", "delete", "onConflict", "doNothing",
"doUpdate", "returning", "build", "fetch", "single", "iterator", "set", "now", "mapTo"
];
for (const token of expectedTokens) {
assert(grammarSource.includes(token), `grammar is missing ${token}`);
}
const annotationSource = JSON.stringify(grammar.repository.annotations);
for (const annotation of ["jsonNaming", "embed", "table", "column", "id", "generated"]) {
assert(annotationSource.includes(annotation), `annotation grammar is missing ${annotation}`);
}
const sqlSource = JSON.stringify(grammar.repository.sql);
for (const method of [
"from", "where", "select", "orderBy", "orderByDescending", "limit", "forUpdate",
"skipLocked", "insert", "update", "delete", "onConflict", "doNothing", "doUpdate",
"returning", "build", "fetch", "single", "iterator", "set", "now"
]) {
assert(sqlSource.includes(method), `SQL grammar is missing ${method}`);
}
const imports = grammar.repository.imports.patterns.map((pattern) => new RegExp(pattern.match));
for (const declaration of [
"import encoding.json",
"import json encoding.json",
"import pgxpool \"github.com/jackc/pgx/v5/pgxpool\"",
"import \"example.com/module/package\""
]) {
assert(imports.some((pattern) => pattern.test(declaration)), `import grammar rejected: ${declaration}`);
}
const prefixes = new Set(Object.values(snippets).map((snippet) => snippet.prefix));
for (const prefix of [
"dataclass", "tablerow", "embed", "worker", "enum", "match", "mapto", "go", "defer", "foreach", "sqlfetch",
"sqlsingle", "sqliterator", "sqlinsertnothing", "sqlinsertupdate", "sqlupdatereturning"
]) {
assert(prefixes.has(prefix), `snippets are missing prefix ${prefix}`);
}
console.log("Validated Gotlin package metadata, grammar, language configuration, and snippets.");

View file

@ -19,17 +19,169 @@
},
"Package": {
"prefix": "package",
"body": [
"package ${1:demo}"
],
"body": ["package ${1:demo}"],
"description": "Gotlin package declaration"
},
"Go Import": {
"prefix": "importgo",
"body": ["import ${1:alias} \"${2:example.com/module/package}\""],
"description": "Import a Go module path with an alias"
},
"Data Class": {
"prefix": "dataclass",
"body": [
"import go.${1:fmt}"
"data class ${1:Name}(",
" val ${2:value}: ${3:String}",
")"
],
"description": "Import a Go package"
"description": "Gotlin data class"
},
"SQL Table Row": {
"prefix": "tablerow",
"body": [
"@table(\"${1:table_name}\")",
"data class ${2:Row}(",
" @generated @id val ${3:id}: ${4:Int},",
" @column(\"${5:value}\") var ${6:value}: ${7:String}",
")"
],
"description": "Annotated SQL table row data class"
},
"Embedded Value": {
"prefix": "embed",
"body": ["@embed(\"${1:path/to/file}\") val ${2:name}: ${3:ByteSlice}"],
"description": "Embed a file as a top-level value"
},
"Worker": {
"prefix": "worker",
"body": [
"worker ${1:Name} {",
" var ${2:state}: ${3:Int} = ${4:0}",
"",
" fun ${5:run}() {",
" $0",
" }",
"}"
],
"description": "Stateful Gotlin worker"
},
"Rust-style Enum": {
"prefix": "enum",
"body": [
"enum ${1:Result} {",
" ${2:Success}(${3:String})",
" ${4:Failure}(${5:String})",
" ${6:Pending}",
"}"
],
"description": "Rust-style algebraic enum"
},
"Exhaustive Enum Match": {
"prefix": "match",
"body": [
"match (${1:result}) {",
" ${2:Result}::${3:Success}(${4:value}) -> {",
" $5",
" }",
" ${2:Result}::${6:Failure}(${7:reason}) -> {",
" $8",
" }",
" ${2:Result}::${9:Pending} -> {",
" $0",
" }",
"}"
],
"description": "Exhaustive match over enum variants"
},
"Recursive Structural Mapping": {
"prefix": "mapto",
"body": ["val ${1:target} = ${2:source}.mapTo<${3:Target}>()"],
"description": "Recursively map compatible classes or enums"
},
"Go Block": {
"prefix": "go",
"body": [
"go {",
" $0",
"}"
],
"description": "Run a block concurrently"
},
"Defer Call": {
"prefix": "defer",
"body": ["defer ${1:resource}.${2:close}()"],
"description": "Defer a function call"
},
"For Each": {
"prefix": "foreach",
"body": [
"for (${1:item} in ${2:items}) {",
" $0",
"}"
],
"description": "Iterate over a collection"
},
"Typed SQL Fetch": {
"prefix": "sqlfetch",
"body": [
"val ${1:rows}: List<*${2:Row}> = sql.from<${2:Row}>()",
" .where { ${3:it.id == id} }",
" .fetch(${4:pool}, ${5:ctx})"
],
"description": "Fetch typed SQL rows"
},
"Typed SQL Single": {
"prefix": "sqlsingle",
"body": [
"val ${1:row}: *${2:Row} = sql.from<${2:Row}>()",
" .where { ${3:it.id == id} }",
" .single(${4:pool}, ${5:ctx})"
],
"description": "Fetch one typed SQL row"
},
"Typed SQL Iterator": {
"prefix": "sqliterator",
"body": [
"val ${1:rows}: GotlinSQLIterator<${2:Row}> = sql.from<${2:Row}>()",
" .where { ${3:it.id == id} }",
" .iterator(${4:pool}, ${5:ctx})"
],
"description": "Iterate over typed SQL rows"
},
"SQL Insert On Conflict Do Nothing": {
"prefix": "sqlinsertnothing",
"body": [
"sql.insert<${1:Row}>(${2:row})",
" .onConflict { ${3:it.id} }",
" .doNothing()",
" .build()"
],
"description": "Build an insert that ignores a typed conflict"
},
"SQL Insert On Conflict Do Update": {
"prefix": "sqlinsertupdate",
"body": [
"sql.insert<${1:Row}>(${2:row})",
" .onConflict { ${3:it.id} }",
" .doUpdate { ${4:excluded} ->",
" set(${1:Row}.${5:value}, ${4:excluded}.${5:value})",
" }",
" .build()"
],
"description": "Build an insert that updates on a typed conflict"
},
"SQL Update Returning": {
"prefix": "sqlupdatereturning",
"body": [
"val ${1:updated}: *${2:Row} = sql.update<${2:Row}>()",
" .set { ${3:row} ->",
" set(${3:row}.${4:value}, ${5:newValue})",
" }",
" .where { ${6:it.id == id} }",
" .returning { it }",
" .single(${7:pool}, ${8:ctx})"
],
"description": "Update and return a typed SQL row"
},
"If": {
"prefix": "if",
@ -42,9 +194,7 @@
},
"Lambda": {
"prefix": "lambda",
"body": [
"{ ${1:it} -> $0 }"
],
"body": ["{ ${1:it} -> $0 }"],
"description": "Lambda expression"
},
"Override Method": {

View file

@ -3,39 +3,21 @@
"name": "Gotlin",
"scopeName": "source.gotlin",
"patterns": [
{
"include": "#comments"
},
{
"include": "#imports"
},
{
"include": "#package"
},
{
"include": "#functions"
},
{
"include": "#typesDecl"
},
{
"include": "#literals"
},
{
"include": "#keywords"
},
{
"include": "#types"
},
{
"include": "#strings"
},
{
"include": "#numbers"
},
{
"include": "#operators"
}
{ "include": "#comments" },
{ "include": "#imports" },
{ "include": "#package" },
{ "include": "#annotations" },
{ "include": "#declarations" },
{ "include": "#functions" },
{ "include": "#strings" },
{ "include": "#sql" },
{ "include": "#generics" },
{ "include": "#literals" },
{ "include": "#keywords" },
{ "include": "#types" },
{ "include": "#numbers" },
{ "include": "#typeOperators" },
{ "include": "#operators" }
],
"repository": {
"comments": {
@ -49,18 +31,29 @@
"imports": {
"patterns": [
{
"name": "meta.import.gotlin",
"match": "\\b(import)\\b\\s+((?:[A-Za-z_][\\w-]*\\.)*[A-Za-z_][\\w-]*)(?:\\s+((?:[A-Za-z_][\\w-]*\\.)*[A-Za-z_][\\w-]*))?",
"name": "meta.import.go.quoted.gotlin",
"match": "^(\\s*)(import)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s+(\"(?:\\\\.|[^\"\\\\])*\")\\s*;?",
"captures": {
"1": {
"name": "keyword.control.import.gotlin"
},
"2": {
"name": "meta.path.gotlin"
},
"3": {
"name": "meta.path.gotlin"
}
"2": { "name": "keyword.control.import.gotlin" },
"3": { "name": "entity.name.namespace.alias.gotlin" },
"4": { "name": "string.quoted.double.import-path.gotlin" }
}
},
{
"name": "meta.import.go.quoted.gotlin",
"match": "^(\\s*)(import)\\s+(\"(?:\\\\.|[^\"\\\\])*\")\\s*;?",
"captures": {
"2": { "name": "keyword.control.import.gotlin" },
"3": { "name": "string.quoted.double.import-path.gotlin" }
}
},
{
"name": "meta.import.go.bare.gotlin",
"match": "^(\\s*)(import)\\s+(?:([A-Za-z_][A-Za-z0-9_]*)\\s+)?([A-Za-z_][A-Za-z0-9_]*(?:[.-][A-Za-z_][A-Za-z0-9_]*)*)\\s*;?\\s*(?://.*)?$",
"captures": {
"2": { "name": "keyword.control.import.gotlin" },
"3": { "name": "entity.name.namespace.alias.gotlin" },
"4": { "name": "entity.name.namespace.import-path.gotlin" }
}
}
]
@ -69,14 +62,108 @@
"patterns": [
{
"name": "meta.package.gotlin",
"match": "\\b(package)\\b\\s+((?:[A-Za-z_][\\w-]*\\.)*[A-Za-z_][\\w-]*)",
"match": "^(\\s*)(package)\\s+([A-Za-z_][A-Za-z0-9_]*(?:[.-][A-Za-z_][A-Za-z0-9_]*)*)\\s*;?",
"captures": {
"1": {
"name": "keyword.control.package.gotlin"
},
"2": {
"name": "meta.path.gotlin"
}
"2": { "name": "keyword.control.package.gotlin" },
"3": { "name": "entity.name.namespace.gotlin" }
}
}
]
},
"annotations": {
"patterns": [
{
"match": "(@)(jsonNaming)\\b",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.json-naming.gotlin" }
}
},
{
"match": "(@)(embed)\\b",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.embed.gotlin" }
}
},
{
"match": "(@)(table)\\b",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.table.gotlin" }
}
},
{
"match": "(@)(column)\\b",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.column.gotlin" }
}
},
{
"match": "(@)(id)\\b",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.id.gotlin" }
}
},
{
"match": "(@)(generated)\\b",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.generated.gotlin" }
}
},
{
"match": "(@)([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "punctuation.definition.annotation.gotlin" },
"2": { "name": "entity.other.attribute-name.annotation.gotlin" }
}
}
]
},
"declarations": {
"patterns": [
{
"name": "meta.class.data.gotlin",
"match": "\\b(data)\\s+(class)\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "storage.modifier.data.gotlin" },
"2": { "name": "storage.type.class.gotlin" },
"3": { "name": "entity.name.type.class.gotlin" }
}
},
{
"name": "meta.interface.gotlin",
"match": "\\b(interface)\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "storage.type.interface.gotlin" },
"2": { "name": "entity.name.type.interface.gotlin" }
}
},
{
"name": "meta.worker.gotlin",
"match": "\\b(worker)\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "storage.type.worker.gotlin" },
"2": { "name": "entity.name.type.worker.gotlin" }
}
},
{
"name": "meta.enum.gotlin",
"match": "\\b(enum)\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "storage.type.enum.gotlin" },
"2": { "name": "entity.name.type.enum.gotlin" }
}
},
{
"name": "meta.class.gotlin",
"match": "\\b(class)\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "storage.type.class.gotlin" },
"2": { "name": "entity.name.type.class.gotlin" }
}
}
]
@ -85,46 +172,73 @@
"patterns": [
{
"name": "meta.function.gotlin",
"match": "\\b(?:(override)\\s+)?(fun)\\b\\s+([A-Za-z_][A-Za-z0-9_]*)",
"match": "\\b(?:(override)\\s+)?(fun)\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": {
"name": "storage.modifier.gotlin"
},
"2": {
"name": "keyword.control.function.gotlin"
},
"3": {
"name": "entity.name.function.gotlin"
}
"1": { "name": "storage.modifier.override.gotlin" },
"2": { "name": "storage.type.function.gotlin" },
"3": { "name": "entity.name.function.gotlin" }
}
}
]
},
"typesDecl": {
"strings": {
"patterns": [
{
"name": "meta.interface.gotlin",
"match": "\\b(interface)\\b\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": {
"name": "storage.type.interface.gotlin"
},
"2": {
"name": "entity.name.type.interface.gotlin"
"name": "string.quoted.double.gotlin",
"begin": "\"",
"beginCaptures": {
"0": { "name": "punctuation.definition.string.begin.gotlin" }
},
"end": "\"",
"endCaptures": {
"0": { "name": "punctuation.definition.string.end.gotlin" }
},
"patterns": [
{
"name": "constant.character.escape.gotlin",
"match": "\\\\."
}
}
]
}
]
},
"sql": {
"patterns": [
{
"name": "support.type.namespace.sql.gotlin",
"match": "\\bsql\\b(?=\\s*\\.)"
},
{
"name": "meta.class.gotlin",
"match": "\\b(class)\\b\\s+([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": {
"name": "storage.type.class.gotlin"
},
"2": {
"name": "entity.name.type.class.gotlin"
}
}
"name": "support.function.sql.query.gotlin",
"match": "(?<=\\.)\\b(from|where|select|orderBy|orderByDescending|limit|forUpdate|skipLocked)\\b"
},
{
"name": "support.function.sql.mutation.gotlin",
"match": "(?<=\\.)\\b(insert|update|delete|onConflict|doNothing|doUpdate|returning)\\b"
},
{
"name": "support.function.sql.execution.gotlin",
"match": "(?<=\\.)\\b(build|fetch|single|iterator)\\b"
},
{
"name": "support.function.sql.helper.gotlin",
"match": "\\b(set|now)\\b(?=\\s*\\()"
},
{
"name": "support.function.mapping.gotlin",
"match": "(?<=\\.)\\bmapTo\\b"
}
]
},
"generics": {
"patterns": [
{
"name": "punctuation.definition.generic.begin.gotlin",
"match": "(?<=\\w)<(?=\\s*[*A-Za-z_])"
},
{
"name": "punctuation.definition.generic.end.gotlin",
"match": ">(?=\\??\\s*(?:[>,.()\\[\\]{}:=]|$))"
}
]
},
@ -140,26 +254,54 @@
},
{
"name": "variable.language.this.gotlin",
"match": "\\bthis\\b"
"match": "\\b(this|it)\\b"
}
]
},
"keywords": {
"patterns": [
{
"name": "keyword.control.gotlin",
"match": "\\b(fun|val|var|override|if|else|while|return|try|catch|throw)\\b"
"name": "keyword.control.declaration.gotlin",
"match": "\\b(package|import|data|class|interface|worker|enum|fun)\\b"
},
{
"name": "storage.modifier.gotlin",
"match": "\\b(private|override)\\b"
},
{
"name": "storage.type.variable.gotlin",
"match": "\\b(val|var)\\b"
},
{
"name": "keyword.control.conditional.gotlin",
"match": "\\b(if|else|match)\\b"
},
{
"name": "keyword.control.loop.gotlin",
"match": "\\b(while|for|in)\\b"
},
{
"name": "keyword.control.concurrency.gotlin",
"match": "\\b(select|go|defer)\\b"
},
{
"name": "keyword.control.exception.gotlin",
"match": "\\b(try|catch|throw)\\b"
},
{
"name": "keyword.control.return.gotlin",
"match": "\\breturn\\b"
}
]
},
"types": {
"patterns": [
{
"name": "storage.type.gotlin",
"match": "\\b(Int|String|Boolean|Unit)\\b"
"name": "support.type.builtin.gotlin",
"match": "\\b(Int|String|Boolean|Unit|Double|Float|Any|ByteSlice|List|MutableList|Map|MutableMap|Channel|GotlinSQLQuery|GotlinSQLIterator)\\b"
},
{
"name": "support.type.gotlin",
"name": "support.type.qualified.gotlin",
"match": "\\b[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)+\\b"
},
{
@ -168,34 +310,67 @@
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double.gotlin",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.gotlin",
"match": "\\\\."
}
]
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.gotlin",
"match": "\\b\\d+\\b"
"name": "constant.numeric.float.gotlin",
"match": "\\b[0-9]+\\.[0-9]+\\b"
},
{
"name": "constant.numeric.integer.gotlin",
"match": "\\b[0-9]+\\b"
}
]
},
"typeOperators": {
"patterns": [
{
"name": "keyword.operator.type.nullable.gotlin",
"match": "(?<=[A-Za-z0-9_>])\\?"
},
{
"name": "keyword.operator.address.gotlin",
"match": "&(?=\\s*[A-Za-z_(])"
},
{
"name": "keyword.operator.pointer.dereference.spread.gotlin",
"match": "\\*(?=\\s*[A-Za-z_(])"
}
]
},
"operators": {
"patterns": [
{
"name": "keyword.operator.gotlin",
"match": "->|==|!=|<=|>=|&&|\\|\\||[=+\\-*/%<>!:.,]"
"name": "keyword.operator.assignment.gotlin",
"match": "\\+=|="
},
{
"name": "keyword.operator.comparison.gotlin",
"match": "==|!=|<=|>="
},
{
"name": "keyword.operator.logical.gotlin",
"match": "&&|\\|\\||!"
},
{
"name": "keyword.operator.arrow.gotlin",
"match": "->"
},
{
"name": "punctuation.accessor.enum.gotlin",
"match": "::"
},
{
"name": "keyword.operator.arithmetic.gotlin",
"match": "[+\\-*/%<>]"
},
{
"name": "punctuation.accessor.dot.gotlin",
"match": "\\."
},
{
"name": "punctuation.separator.gotlin",
"match": "[,;:]"
}
]
}