Skip to content

Editor tooling

Writing .koi is nicer with an editor that understands it. Koine ships two pieces of tooling, both living under tooling/ in the repo:

  • a TextMate grammar (tooling/koine-textmate) for syntax highlighting, and
  • a language server (koine lsp) for live diagnostics, completion, hover, and go-to-definition.

The grammar works in JetBrains Rider (and any IntelliJ-based IDE) and VS Code. The language server is wired up in Rider today via the LSP4IJ plugin; a thin VS Code client is a small follow-up.

tooling/koine-textmate/ is a TextMate grammar bundle that is also a valid VS Code grammar extension. It scopes keywords, declaration names, field names, primitive types, invariants, the matches /regex/ literal, strings, numbers, comments, and operators.

koine-textmate/
├── package.json # language + grammar contribution
├── language-configuration.json # comments, brackets, auto-closing
└── syntaxes/koine.tmLanguage.json # the TextMate grammar (scopeName: source.koine)

Colors follow your active color scheme through standard TextMate scopes — keyword.control, storage.type, entity.name.type, support.type, string.quoted, string.regexp, comment, constant.numeric, and keyword.operator — so it looks at home in whatever theme you use.

Beyond generic scopes, Koine colors each DDD concept — an aggregate, a value object, an enum — with its own hue, the same one the Studio explorer and canvas use, driven by the language server’s kind modifiers. See Concept Colors for the palette and how it works.

Rider reads TextMate bundles directly — no plugin or build step needed.

  1. Settings / PreferencesEditorTextMate Bundles.
  2. Click + and select the tooling/koine-textmate folder.
  3. Click OK / Apply.

Open any .koi file (for example templates/pizzeria/menu.koi) and it lights up.

The same folder is a complete extension.

  • Quick try: copy or symlink koine-textmate into ~/.vscode/extensions/koine-textmate and reload.

  • Package it: install the packager and build a .vsix:

    Terminal window
    npm i -g @vscode/vsce
    cd tooling/koine-textmate && vsce package

    Then install the resulting .vsix via Extensions → … → Install from VSIX.

The extension contributes the koine language id, so VS Code already knows .koi files are Koine — which is exactly what the language client below hooks into.

Syntax highlighting is static — it never reads your whole model. To get inline error squiggles for unknown types, duplicate members, invalid invariants, and syntax errors, Koine ships a small language server:

Terminal window
koine lsp # speaks LSP over stdio, pushes textDocument/publishDiagnostics

The key property: koine lsp reuses the compiler’s own Parse + semantic validation. Editor diagnostics are produced by the same code path as koine build, so you get the same messages at the same line and column. There is no second, drifting implementation of the rules — if the editor flags it, the build flags it, and vice versa.

Over stdio, koine lsp provides:

  • Diagnostics — syntax and semantic errors as you type.
  • Completion (Ctrl Space) — type names after :, enum members after =, and the declaration keywords valid at the current scope (for example value / entity / enum inside a context, or operation inside a service). Completion is lexer-based, so it keeps working while the document is mid-edit and not yet parseable.
  • Hover — a markdown card showing a type’s kind, members (with full generic types like List<OrderLine>), and doc comment. It resolves across files, and an *Id reference shows its owning entity.
  • Go-to-definition — jump from a type, enum-member, spec, or *Id reference to its declaration in any .koi file in the workspace.

Rider runs external LSP servers through the LSP4IJ plugin.

  1. Build the CLI once so the server binary exists:

    Terminal window
    dotnet build src/Koine.Cli -c Release

    Note the path to …/src/Koine.Cli/bin/Release/net10.0/Koine.Cli.dll.

  2. Settings → Plugins → Marketplace → install LSP4IJ → restart.

  3. Settings → Languages & Frameworks → Language Servers+ (New Language Server):

    • Name: Koine
    • Command: dotnet "<abs-path>/src/Koine.Cli/bin/Release/net10.0/Koine.Cli.dll" lsp
    • Mappings → File name patterns: *.koi
  4. OK, then open a .koi file. Errors appear as you type; fix one and the squiggle clears.

The Koine extension (tooling/koine-textmate) supplies the koine language id and highlighting and ships a language client that spawns koine lsp — so diagnostics, hover, go-to-definition, outline, rename, and formatting work out of the box, plus four commands for the Koine-specific requests: Preview Emitted Code, Show Glossary, Show Context Map, and Check Compatibility.

By default the client launches koine from your PATH. Point it at a different server with two settings (e.g. to run the CLI straight from source):

.vscode/settings.json
{
"koine.server.path": "dotnet",
"koine.server.args": ["run", "--project", "src/Koine.Cli", "--"]
}

koine.server.path empty → koine lsp (executable on PATH); set it to a self-contained koine binary (dotnet publish src/Koine.Cli -p:PublishProfile=osx-arm64) for the fastest startup. Set koine.trace.server to verbose to log JSON-RPC traffic.

The same enriched koine lsp server also backs Koine Studio, the standalone desktop IDE — both clients share one server, so a capability added to the LSP appears in both.

If LSP4IJ reports that the server “stopped unexpectedly”, there are three places to look:

  1. LSP4IJ console (most useful). View → Tool Windows → LSP Consoles → Koine. The server writes lifecycle and per-request lines to stderr, which appear here:

    [koine-lsp] server started (pid 12345)
    [koine-lsp] <- initialize
    [koine-lsp] <- textDocument/didOpen
    [koine-lsp] error handling 'textDocument/didChange': <full stack trace> ← a real crash shows here

    For raw JSON-RPC traffic, set the server’s Trace to verbose under Settings → Languages & Frameworks → Language Servers → Koine.

  2. A log file. Set KOINE_LSP_LOG=/tmp/koine-lsp.log in the language server’s Environment variables, then tail -f /tmp/koine-lsp.log (handy when the console clears on restart).

  3. Rider’s own log for plugin-level issues: Help → Show Log in Finder/Explorer (idea.log).

Common causes of an immediate exit:

SymptomCauseFix
Console empty or “cannot execute”Wrong command/pathRe-check the absolute path to Koine.Cli.dll; rebuild first
Protocol stream corrupted on startThe .NET host’s first-run / telemetry banner lands on stdoutAdd DOTNET_NOLOGO=1 and DOTNET_CLI_TELEMETRY_OPTOUT=1 to the server’s environment, or use the dotnet publish binary
[koine-lsp] error handling … lineA handler bug on one messageThe server catches per-message exceptions and logs them instead of dying — the named line points at the culprit
  • CLI referencekoine build and koine check, which share the server’s parser and validator.
  • Your first model — write a .koi file to try the tooling on.
  • Language reference — the constructs the grammar highlights and the server understands.