Add structured coroutines and explicit error handling
This commit is contained in:
parent
de1262b4cf
commit
fe62e81152
31 changed files with 1701 additions and 325 deletions
|
|
@ -8,7 +8,7 @@ VS Code language support for Gotlin (`.gt`) files.
|
|||
- 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
|
||||
- Snippets for data classes, SQL table rows and operations, structured coroutines, embeds, defer, and foreach loops
|
||||
- `gotlin-lsp` integration, including its optional `gopls` bridge for Go-imported symbols
|
||||
|
||||
## Development
|
||||
|
|
|
|||
|
|
@ -42,12 +42,13 @@ assert(language.folding?.markers?.start && language.indentationRules?.increaseIn
|
|||
|
||||
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",
|
||||
"data", "class", "suspend", "private", "override", "val", "var", "if", "else",
|
||||
"while", "for", "in", "select", "return", "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",
|
||||
"generated", "Int", "Long", "String", "Boolean", "Unit", "Double", "Float", "Any",
|
||||
"ByteSlice", "Error", "Result", "List", "MutableList", "Map", "MutableMap", "Channel", "GotlinSQLQuery",
|
||||
"GotlinSQLIterator", "from", "where", "orderBy", "orderByDescending", "limit",
|
||||
"runBlocking", "coroutineScope", "launch", "async", "await", "delay", "withTimeout", "isActive",
|
||||
"forUpdate", "skipLocked", "insert", "update", "delete", "onConflict", "doNothing",
|
||||
"doUpdate", "returning", "build", "fetch", "single", "iterator", "set", "now", "mapTo"
|
||||
];
|
||||
|
|
@ -81,7 +82,7 @@ for (const declaration of [
|
|||
|
||||
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",
|
||||
"dataclass", "tablerow", "embed", "coroutinescope", "launch", "async", "enum", "match", "mapto", "safe", "nonnull", "resultfun", "resultmatch", "defer", "foreach", "sqlfetch",
|
||||
"sqlsingle", "sqliterator", "sqlinsertnothing", "sqlinsertupdate", "sqlupdatereturning"
|
||||
]) {
|
||||
assert(prefixes.has(prefix), `snippets are missing prefix ${prefix}`);
|
||||
|
|
|
|||
|
|
@ -52,19 +52,6 @@
|
|||
"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": [
|
||||
|
|
@ -98,14 +85,50 @@
|
|||
"body": ["val ${1:target} = ${2:source}.mapTo<${3:Target}>()"],
|
||||
"description": "Recursively map compatible classes or enums"
|
||||
},
|
||||
"Go Block": {
|
||||
"prefix": "go",
|
||||
"Nullable Safe Access": {
|
||||
"prefix": "safe",
|
||||
"body": ["${1:value}?.${2:field}"],
|
||||
"description": "Safely access a nullable value"
|
||||
},
|
||||
"Non-null Assertion": {
|
||||
"prefix": "nonnull",
|
||||
"body": ["${1:value}!!"],
|
||||
"description": "Assert that a nullable value is non-null"
|
||||
},
|
||||
"Result Function": {
|
||||
"prefix": "resultfun",
|
||||
"body": [
|
||||
"go {",
|
||||
" $0",
|
||||
"fun ${1:name}(${2}): Result<${3:Value}, Error> {",
|
||||
" val ${4:value} = ${5:operation}()?",
|
||||
" return Result::Ok(${4:value})",
|
||||
"}"
|
||||
],
|
||||
"description": "Run a block concurrently"
|
||||
"description": "Function with Rust-style Result propagation"
|
||||
},
|
||||
"Result Match": {
|
||||
"prefix": "resultmatch",
|
||||
"body": [
|
||||
"match (${1:result}) {",
|
||||
" Result::Ok(${2:value}) -> { $3 }",
|
||||
" Result::Err(${4:error}) -> { $0 }",
|
||||
"}"
|
||||
],
|
||||
"description": "Match a Result value"
|
||||
},
|
||||
"Coroutine Scope": {
|
||||
"prefix": "coroutinescope",
|
||||
"body": ["coroutineScope {", " $0", "}"],
|
||||
"description": "Structured child coroutine scope"
|
||||
},
|
||||
"Launch Coroutine": {
|
||||
"prefix": "launch",
|
||||
"body": ["launch {", " $0", "}"],
|
||||
"description": "Launch a structured child coroutine"
|
||||
},
|
||||
"Async Coroutine": {
|
||||
"prefix": "async",
|
||||
"body": ["val ${1:result} = async<${2:Type}> {", " $0", "}"],
|
||||
"description": "Start a typed deferred coroutine"
|
||||
},
|
||||
"Defer Call": {
|
||||
"prefix": "defer",
|
||||
|
|
@ -124,7 +147,7 @@
|
|||
"Typed SQL Fetch": {
|
||||
"prefix": "sqlfetch",
|
||||
"body": [
|
||||
"val ${1:rows}: List<*${2:Row}> = sql.from<${2:Row}>()",
|
||||
"val ${1:rows}: List<${2:Row}> = sql.from<${2:Row}>()",
|
||||
" .where { ${3:it.id == id} }",
|
||||
" .fetch(${4:pool}, ${5:ctx})"
|
||||
],
|
||||
|
|
@ -133,7 +156,7 @@
|
|||
"Typed SQL Single": {
|
||||
"prefix": "sqlsingle",
|
||||
"body": [
|
||||
"val ${1:row}: *${2:Row} = sql.from<${2:Row}>()",
|
||||
"val ${1:row}: ${2:Row} = sql.from<${2:Row}>()",
|
||||
" .where { ${3:it.id == id} }",
|
||||
" .single(${4:pool}, ${5:ctx})"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -142,14 +142,6 @@
|
|||
"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_]*)",
|
||||
|
|
@ -262,7 +254,7 @@
|
|||
"patterns": [
|
||||
{
|
||||
"name": "keyword.control.declaration.gotlin",
|
||||
"match": "\\b(package|import|data|class|interface|worker|enum|fun)\\b"
|
||||
"match": "\\b(package|import|data|class|interface|enum|suspend|fun)\\b"
|
||||
},
|
||||
{
|
||||
"name": "storage.modifier.gotlin",
|
||||
|
|
@ -282,7 +274,7 @@
|
|||
},
|
||||
{
|
||||
"name": "keyword.control.concurrency.gotlin",
|
||||
"match": "\\b(select|go|defer)\\b"
|
||||
"match": "\\b(select|defer|runBlocking|coroutineScope|launch|async|await|delay|withTimeout|isActive)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.exception.gotlin",
|
||||
|
|
@ -298,7 +290,7 @@
|
|||
"patterns": [
|
||||
{
|
||||
"name": "support.type.builtin.gotlin",
|
||||
"match": "\\b(Int|String|Boolean|Unit|Double|Float|Any|ByteSlice|List|MutableList|Map|MutableMap|Channel|GotlinSQLQuery|GotlinSQLIterator)\\b"
|
||||
"match": "\\b(Int|Long|String|Boolean|Unit|Double|Float|Any|Error|Result|ByteSlice|List|MutableList|Map|MutableMap|Channel|GotlinSQLQuery|GotlinSQLIterator)\\b"
|
||||
},
|
||||
{
|
||||
"name": "support.type.qualified.gotlin",
|
||||
|
|
@ -324,6 +316,14 @@
|
|||
},
|
||||
"typeOperators": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.operator.nullsafe.gotlin",
|
||||
"match": "\\?\\.|!!"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.error-propagation.gotlin",
|
||||
"match": "(?<=[a-z0-9_)\\]])\\?(?!\\.)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.type.nullable.gotlin",
|
||||
"match": "(?<=[A-Za-z0-9_>])\\?"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue