Skip to content

Hessesian/kotlin-lsp

Repository files navigation

kotlin-lsp

crates.io downloads release build license

A fast, low-memory LSP server for Kotlin, Java, and Swift, written in Rust.
Built with tree-sitter — instant startup, no JVM.

kotlin-lsp demo

Install

cargo install kotlin-lsp

No Cargo? Get it at rustup.rs. After install, kotlin-lsp is at ~/.cargo/bin/ — make sure it's on your PATH.

Optional: Install fd and rg (ripgrep) for faster file discovery and cross-file search.

Other install methods

One-liner (Linux / macOS) — installs both kotlin-lsp and the native JAR indexer:

curl -fsSL https://raw.githubusercontent.com/Hessesian/kotlin-lsp/main/install.sh | sh

cargo-binstall — downloads the pre-built binary (no compilation):

cargo binstall kotlin-lsp

mise — via the aqua backend:

mise use -g aqua:Hessesian/kotlin-lsp

mason.nvim (Neovim) — once listed in the registry:

require("mason").setup()
require("mason-lspconfig").setup({ ensure_installed = { "kotlin_ls" } })

JAR indexer sidecar

For full JAR/library type information (Compose, AndroidX, Kotlin stdlib docs), the native sidecar is needed. The install.sh and mise/aqua channels install both binaries automatically. cargo-binstall and mason.nvim install only kotlin-lsp — in those cases, download the matching tarball manually to get the sidecar too:

# Linux x86_64 example — both binaries extracted from one tarball
tar -xzf kotlin-lsp-linux-x86_64.tar.gz
mv kotlin-lsp ~/.cargo/bin/
mv kotlin-jar-indexer ~/.cargo/bin/

The sidecar is a self-contained native binary — no JVM required. Starts in ~4 ms.

Fallback: if the native sidecar is absent but java is on your PATH, kotlin-lsp automatically falls back to the JAR version.

Quick start

VS Code — download and install the .vsix from the latest release:

code --install-extension kotlin-lsp-linux-x64-vX.Y.Z.vsix   # Linux
code --install-extension kotlin-lsp-darwin-arm64-vX.Y.Z.vsix # macOS Apple Silicon

The extension bundles syntax highlighting and launches kotlin-lsp automatically.

Zed — install the bundled extension (registers kotlin-lsp from $PATH, no manual wiring):

zed --install-dev-extension contrib/zed-extension

Then add to ~/.config/zed/settings.json:

{
  "languages": {
    "Kotlin": {
      "language_servers": ["kotlin-lsp", "!kotlin-language-server"],
      "format_on_save": "off",
      "show_completions_on_input": true
    },
    "Java":  { "language_servers": ["kotlin-lsp"], "format_on_save": "off" },
    "Swift": { "language_servers": ["kotlin-lsp"], "format_on_save": "off" }
  }
}

Full Zed setup + manual wiring option →

Helix — add to ~/.config/helix/languages.toml:

[[language]]
name = "kotlin"
language-servers = ["kotlin-lsp"]

[[language]]
name = "java"
language-servers = ["kotlin-lsp"]

[language-server.kotlin-lsp]
command = "kotlin-lsp"

Neovim, Zed setup →

Once your editor is wired up:

  1. Open a Kotlin/Java file — hover, go-to-definition, and completions work immediately via rg fallback while the index builds in the background.
  2. Library sources are discovered automatically — no configuration needed in most cases:
    • Android SDK (Activity, Context, View, …) — detected from local.properties$ANDROID_HOME$ANDROID_SDK_ROOT
    • Gradle library sources (Compose, coroutines, AndroidX, …) — run once to unpack *-sources.jar from the Gradle cache:
kotlin-lsp extract-sources   # one-time; restart editor after
  • IntelliJ/Android Studio projectsworkspace.json source roots are picked up automatically, including any sourcePaths you've configured there.

Features

Capability Notes
Go-to-definition Index → superclass hierarchy → rg fallback. Multi-hop chains, lambda params, this/super
Hover Declaration signature, lambda param types, Kotlin stdlib docs
Completion Dot-completion with type resolution, auto-import, scored ranking, stdlib entries
References Project-wide rg --word-regexp + open buffers; scoped to declaring class for fields/properties
Document/workspace symbol Outline view, fuzzy search, dot-qualified extension function queries
Rename Project-wide via WorkspaceEdit
Inlay hints Lambda it, named params, this, untyped val/var; enriched async via background rg pass
Semantic tokens Full syntax highlighting via tree-sitter CST + cross-file resolution
Diagnostics Syntax errors (tree-sitter), missing when branches (sealed/enum), missing call arguments
Go-to-implementation Interface methods and abstract functions; transitive subtype BFS; scoped by declaring class
Signature help Active parameter highlighting
Code actions Fill missing when branches for sealed classes and enums
Folding Brace regions + consecutive comment blocks
CLI mode find, refs, hover, index, complete, tokens, tree, sources, extract-sources — scriptable, no daemon

All features work immediately — rg fallback handles symbols before indexing finishes.

What gets indexed

Language Symbols
Kotlin class, interface, object, fun, val, var, typealias, constructor params, enum entries
Java class, interface, enum, method, field, enum_constant
Swift class, struct, enum, protocol, func, let, var, typealias, extension, init, enum cases

CLI

kotlin-lsp works standalone — no editor, no daemon.

kotlin-lsp CLI demo

kotlin-lsp find MyViewModel              # search declarations
kotlin-lsp refs MyViewModel              # find all references
kotlin-lsp hover src/Foo.kt 42 10        # hover info at line 42, col 10
kotlin-lsp complete src/Foo.kt 42 --dot  # completions after last '.' on line 42
kotlin-lsp index --root ./android        # pre-build cache
kotlin-lsp sources --root ./android      # list detected source roots
kotlin-lsp extract-sources               # unpack library sources from Gradle cache
Flag Behaviour
(none) Auto: use cached index if available, fall back to fast rg/fd
--fast Always use rg/fd; instant, no index needed
--smart Require index; build it if missing
--json Machine-readable output
--root <dir> Workspace root (default: nearest .git dir)

complete returns JSON [{label, kind, detail?, import?}]. Use --dot / --eol to auto-place the cursor; --no-stdlib skips ~/.kotlin-lsp/sources for ~5× faster project-only results.

Full CLI reference →


Configuration

Workspace root

Resolved in order:

  1. KOTLIN_LSP_WORKSPACE_ROOT env var
  2. LSP client rootUri / workspaceFolders
  3. ~/.config/kotlin-lsp/workspace file (for clients that send no root)

Ignore patterns

# ~/.config/helix/languages.toml
[language-server.kotlin-lsp.config.indexingOptions]
ignorePatterns = ["bazel-*", "build/**", "third-party/**"]

Patterns follow gitignore glob rules and apply to both fd and walkdir fallback.

Source paths

Library sources are resolved automatically — no manual config needed in most cases:

Source How it's discovered
Android SDK (Activity, Context, …) sdk.dir in local.properties$ANDROID_HOME$ANDROID_SDK_ROOT
Gradle library sources (Compose, coroutines, …) ~/.kotlin-lsp/sources after running kotlin-lsp extract-sources
IntelliJ/Android Studio project roots workspace.json at project root (exported by IDE)
Standard Gradle/Maven layouts src/main/kotlin, src/test/kotlin, per-module subprojects

workspace.json — JetBrains IDEs export this file to the project root. It describes every module's source roots and lets you override library source directories:

{
  "sourcePaths": [
    "<WORKSPACE>/custom-stubs",
    "/absolute/path/to/generated-sources"
  ]
}

When sourcePaths is present (even as []), it overrides the ~/.kotlin-lsp/sources default. Use [] to disable all library sources for a specific project.

Manual override via LSP config (for custom stubs or generated code):

# ~/.config/helix/languages.toml
[language-server.kotlin-lsp.config.indexingOptions]
sourcePaths = ["buildSrc/src", "/path/to/generated-stubs"]

Source path files are indexed for hover and completions but excluded from findReferences and rename.

Full configuration reference →


Limitations

  • No type inference for generic lambda parameters — use explicit annotations for unresolvable cases
  • No type checking — syntax errors only; use Gradle/Xcode/CI for semantic diagnostics
  • Swift support is structural — all symbols indexed; no module boundaries or closure type inference
  • Java completion is less refined than Kotlin
  • findReferences on common names returns noise — name-based search via rg, no import filtering yet
  • Binary .aar/.jar — only the public API surface is available; full source navigation requires a *-sources.jar (use kotlin-lsp extract-sources). Direct class-file indexing is planned.

vs. Official Kotlin LSP

kotlin-lsp Kotlin/kotlin-lsp (JetBrains)
Runtime Native Rust, no JVM JVM 17+, ~500 MB
Startup Instant Gradle import (slow)
Memory < 200 MB 1+ GB
Accuracy Syntactic (tree-sitter) Full IntelliJ Analysis API
Editor support Any LSP editor VS Code (official)
Swift

They can coexist — use kotlin-lsp for fast navigation, the official one for type-checked diagnostics.


Learn more


Acknowledgements

Superclass hierarchy resolution, this/super qualifier handling, and lambda parameter recognition were inspired by code-compass.nvim by Emmanuel Touzery.

About

Fast, low-memory LSP server for Kotlin and Java, written in Rust

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors