languages: Add built-in Kotlin support via kotlin-language-server - #29
Merged
Conversation
Adds Kotlin as a first-class built-in: tree-sitter grammar registered,
.kt/.kts files recognized, syntax highlighting + outline + indents on,
and kotlin-language-server (fwcd) driven for completion/hover/go-to-def.
- Grammar: tree-sitter-kotlin-codanna 0.3.9 (MIT). Picked specifically
because canonical tree-sitter-kotlin pins tree-sitter <0.23 (conflicts
with workspace 0.26) and the modern tree-sitter-kotlin-ng rewrite
renamed nodes (would require rewriting every .scm from
zed-extensions/kotlin). Codanna preserves the original
simple_identifier node shape while relaxing the tree-sitter version
constraint. Rationale recorded in a multi-line comment on the
native_grammars() entry.
- Queries: pulled from zed-extensions/kotlin (MIT) into
crates/grammars/src/kotlin/. Two patches needed during smoke testing:
(a) highlights.scm: anonymous "null" token replaced with the
(null_literal) named node — codanna models null as a named node.
(b) outline.scm: dropped ["val" "var"] @context matchers inside
property_declaration — codanna only exposes named children, so
the original pattern was "Impossible". Property names still
appear in the outline, just without the val/var prefix.
- Adapter: new crates/languages/src/kotlin.rs (~190 LOC). Modeled on
c.rs::CLspAdapter — $PATH lookup first, otherwise downloads
server.zip from fwcd/kotlin-language-server (one asset per release,
no platform suffix; launcher is a shell script, implementation is a
JVM JAR). Sets 0o755 on the launcher post-unzip on Unix.
- Wired into crates/languages/src/lib.rs::init with PaddleBoard tags on
every upstream-shaped edit.
Second of four planned bake-in PRs (Swift -> Kotlin -> Java -> PHP).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 16, 2026
jasonsmithio
added a commit
that referenced
this pull request
May 31, 2026
languages: Add built-in Kotlin support via kotlin-language-server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Kotlin as a built-in language.
.ktand.ktsfiles get syntax highlighting, indent rules, outline, and completion / hover / go-to-def viakotlin-language-server— found on$PATHfirst, otherwise downloaded asserver.zipfromfwcd/kotlin-language-serverGitHub releases. Same zip works on all platforms because the launcher is a shell script and the implementation is a JVM JAR.Second of four planned bake-in PRs (Swift → Kotlin → Java → PHP). Independent of #28 — both base on main and don't conflict.
Grammar crate selection (the hard part)
Three published Kotlin tree-sitter crates, only one usable:
tree-sitterconstraint0.26?tree-sitter-kotlin0.3.8<0.23simple_identifier(matches Zed extension queries)tree-sitter-kotlin-ng1.1.0^0.24identifier/qualified_identifier(would force rewriting every.scm)tree-sitter-kotlin-codanna0.3.9>=0.21(open-ended)simple_identifier(preserves original)Went with codanna. Rationale is recorded in a multi-line comment on the
("kotlin", tree_sitter_kotlin_codanna::language())entry incrates/grammars/src/grammars.rsso the next reader doesn't try to switch back to "the canonical" crate.What's here
tree-sitter-kotlin-codanna = "0.3.9"(MIT). Added to workspaceCargo.toml,crates/grammars/Cargo.toml(deps +load-grammarsfeature), and registered incrates/grammars/src/grammars.rs::native_grammars().zed-extensions/kotlin(MIT, compatible with the GPL-3.0languagescrate) intocrates/grammars/src/kotlin/:brackets.scm,config.toml,highlights.scm(one patch),indents.scm,injections.scm,outline.scm(one patch),overrides.scm.crates/languages/src/kotlin.rs(~190 LOC). Modeled onc.rs::CLspAdapter(GitHub-zip pattern).check_if_user_installeddoesdelegate.which("kotlin-language-server");fetch_latest_server_versionqueriesfwcd/kotlin-language-serverfor the singleserver.zipasset (constant name across releases);fetch_server_binarydownloads, unzips into<container>/kotlin-language-server_<tag>/server/, returnsserver/bin/kotlin-language-server[.bat]. Sets0o755on the launcher post-unzip on Unix. Skips the--versionvalidity probe used byc.rsbecause the launcher shells out tojava— every probe would boot a JVM; file-existence check + digest comparison is enough.crates/languages/src/lib.rs::initgains amod kotlin;, anArc::new(kotlin::KotlinLspAdapter)instantiation, and aLanguageInfo { name: "kotlin", adapters: vec![kotlin_lsp_adapter], .. }entry betweenjsoncandmarkdown. All four touch points tagged// PaddleBoard:for upstream-merge resolution.Query fixups discovered during smoke testing
The
zed-extensions/kotlinqueries were authored against a slightly different grammar shape than codanna's. Two.scmfiles needed minor patches:highlights.scmline 139: anonymous"null"token →(null_literal)named node. Codanna grammar models null as a named node, the quoted form failed withInvalid node type "null".outline.scmlines 24-39: dropped the["val" "var"] @contextmatchers insideproperty_declaration. Codanna'sproperty_declarationonly exposes named children to queries (no anonymous val/var tokens), so the original pattern wasImpossible. Property names still appear in the outline, just without the val/var prefix.Both patches have explanatory
; PaddleBoard:comments inline.Test plan
cargo check -p grammars --features load-grammarscleancargo check -p paddleboardclean.ktbuffer to trigger the ~85 MB download. Mechanically identical toc.rs's clangd flow which is known to work; recommend the first reviewer verify bygit checkout+ open a.ktfile withkotlin-language-servernot on $PATH (force the download path).Known limitations
javaisn't on $PATH. fwcd's recent releases want JDK 17+; older Java will surface a stderr error from the launcher rather than a friendly notification. Adding ajava -versionprobe is a worthwhile follow-up.val/varno longer appears as outline context (see fixup above).settings.jsonoverrides.Out of scope (follow-ups)
Release Notes:
kotlin-language-serverfromfwcd/kotlin-language-server. The server is downloaded automatically on first use, or picked up from$PATHif installed system-wide. Requires a JDK at runtime.