scaffold: VSCode/VSCodium extension wrapping testium lsp

A thin LSP client that spawns `testium lsp` and forwards messages to
VSCode. All language intelligence lives in the testium repo, so this
extension only needs republishing for editor-side UX changes.

  - package.json: declares the .tum language, registers the LSP client,
    exposes testium.serverPath and testium.trace.server settings.
  - src/extension.ts: vscode-languageclient setup over stdio, surfaces a
    user-visible error if `testium lsp` can't start.
  - syntaxes/tum.tmLanguage.json: TextMate grammar embedding source.yaml
    plus tum-specific tokens for $(name), <| python |>, {% jinja %},
    {{ jinja }}.
  - language-configuration.json: comment char, bracket pairs, auto-close
    for $(/), <|/|>, {%/%}, {{/}}.
  - README.md: install (incl. testium[lsp] extra), settings, packaging
    via vsce, publish to both VS Marketplace and Open VSX (the latter
    is what VSCodium / Cursor / Gitpod use — same .vsix artifact).

Works identically on VSCode and VSCodium — no Microsoft-proprietary
API surface used.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-29 14:59:22 +02:00
parent c6aa6bb07a
commit 770e4cacf1
9 changed files with 514 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Testium TUM",
"scopeName": "source.tum",
"patterns": [
{ "include": "#tum-tokens" },
{ "include": "source.yaml" }
],
"repository": {
"tum-tokens": {
"patterns": [
{ "include": "#globaldict-reference" },
{ "include": "#eval-expression" },
{ "include": "#jinja-statement" },
{ "include": "#jinja-expression" }
]
},
"globaldict-reference": {
"name": "variable.other.tum.globaldict",
"begin": "\\$\\(",
"end": "\\)",
"beginCaptures": {
"0": { "name": "punctuation.definition.variable.begin.tum" }
},
"endCaptures": {
"0": { "name": "punctuation.definition.variable.end.tum" }
},
"patterns": [
{ "name": "entity.name.variable.tum", "match": "[A-Za-z_][A-Za-z0-9_]*" }
]
},
"eval-expression": {
"name": "meta.embedded.expression.tum",
"begin": "<\\|",
"end": "\\|>",
"beginCaptures": {
"0": { "name": "punctuation.definition.expression.begin.tum" }
},
"endCaptures": {
"0": { "name": "punctuation.definition.expression.end.tum" }
},
"patterns": [
{ "include": "source.python" }
]
},
"jinja-statement": {
"name": "meta.embedded.block.jinja.tum",
"begin": "\\{%-?",
"end": "-?%\\}",
"beginCaptures": {
"0": { "name": "punctuation.definition.template-statement.begin.tum" }
},
"endCaptures": {
"0": { "name": "punctuation.definition.template-statement.end.tum" }
},
"patterns": [
{ "name": "keyword.control.jinja.tum",
"match": "\\b(for|endfor|if|elif|else|endif|set|include|extends|block|endblock|macro|endmacro|in|and|or|not|is|with|without|context)\\b" },
{ "name": "string.quoted.double.jinja.tum", "match": "\"(?:[^\"\\\\]|\\\\.)*\"" },
{ "name": "string.quoted.single.jinja.tum", "match": "'(?:[^'\\\\]|\\\\.)*'" },
{ "name": "constant.numeric.jinja.tum", "match": "\\b[0-9]+(?:\\.[0-9]+)?\\b" }
]
},
"jinja-expression": {
"name": "meta.embedded.expression.jinja.tum",
"begin": "\\{\\{-?",
"end": "-?\\}\\}",
"beginCaptures": {
"0": { "name": "punctuation.definition.template-expression.begin.tum" }
},
"endCaptures": {
"0": { "name": "punctuation.definition.template-expression.end.tum" }
},
"patterns": [
{ "name": "string.quoted.double.jinja.tum", "match": "\"(?:[^\"\\\\]|\\\\.)*\"" },
{ "name": "string.quoted.single.jinja.tum", "match": "'(?:[^'\\\\]|\\\\.)*'" },
{ "name": "variable.other.jinja.tum", "match": "[A-Za-z_][A-Za-z0-9_]*" }
]
}
}
}