Skip to content

[FEATURE]: Support custom tree-sitter parsers via config for custom languages #18587

@djmittens

Description

@djmittens

Problem

OpenCode's syntax highlighting is driven by tree-sitter parsers hardcoded in parsers-config.ts. There is no way to add a custom language parser via opencode.json config. This means anyone working on a new or niche language gets no syntax highlighting, even if they already have a fully working tree-sitter grammar and WASM binary.

Our Situation

We're building Valkyria, a Lisp dialect with .valk files. We already have:

  • A custom LSP server — configured via opencode.json under lsp, works great with diagnostics, hover, completion, go-to-definition, semantic tokens, etc.
  • A tree-sitter grammar — full grammar.js with highlights, locals, and indents queries
  • A compiled WASM binarytree-sitter-valk.wasm (13KB), built and ready

The LSP integration is seamless thanks to the existing config. But there's no equivalent config path for syntax highlighting — we can't point OpenCode at our WASM + queries.

Proposed Solution

Add a syntax (or parsers) section to opencode.json that allows users to register custom tree-sitter parsers:

{
  "$schema": "https://opencode.ai/config.json",
  "syntax": {
    "valk": {
      "wasm": "./editors/tree-sitter-valk.wasm",
      "extensions": [".valk"],
      "highlights": "./editors/queries/valk/highlights.scm",
      "locals": "./editors/queries/valk/locals.scm"
    }
  }
}

This mirrors the existing lsp config pattern — same shape, same idea: point at a binary + file extensions.

The wasm and highlights fields could accept either local paths (relative to project root) or URLs (for hosted grammars), consistent with how parsers-config.ts already works internally.

Why This Matters

Alternatives Considered

  • PR to add valk to parsers-config.ts: Works for us but doesn't help anyone else with a custom language. Every language needs a separate PR + release cycle.
  • Aliasing extensions to existing parsers: Partial solution (e.g., .valkclojure), but loses language-specific highlights. Would still be useful as a simpler option alongside full custom parser support.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions