问题现象

在 Zed 编辑器中打开 Java + Kotlin 混编的 Android 项目,打开 .kt.java 文件后,cmd-clickcmd-] 无法跳转到方法定义的位置,底部状态栏也看不到对应的 LSP 服务。

原因排查

1. 确认 LSP 进程

# 查看正在运行的 LSP 进程
ps aux | grep -iE "jdt|lsp|kotlin" | grep -v grep

正常情况应看到两个进程:

  • jdtls — Eclipse JDT LS(Java LSP)
  • kotlin-language-server — Kotlin LSP

2. 检查 Zed 日志

# 查看最近的 LSP 日志
grep -iE "kotlin|lsp" ~/Library/Logs/Zed/Zed.log | tail -20

常见的错误信息:

ERROR [project::lsp_store] Failed to start language server "kotlin-lsp":
from extension "Kotlin" version 0.3.0:
error sending request for url (...RELEASES.md)
Caused by: Operation timed out (os error 60)

3. 根因分析

Zed 的 Kotlin 扩展(v0.3.0)内置了两种语言服务器:

LSP 名称 类型 说明
kotlin-lsp JetBrains IntelliJ Server 需 JDK 25+,认证已过期,无法使用
kotlin-language-server fwcd/kotlin-language-server 轻量,JDK 11 即可,独立运行

扩展的 WASM 代码启动时会先尝试 kotlin-lsp(IntelliJ 版),通过网络请求 GitHub 的 RELEASES.md 检查最新版本。即使网络正常,JetBrains IntelliJ Server 的认证也已过期,导致其无法正常启动和使用。这是不使用 JetBrains IntelliJ Server 的主因——它已不再是一个可行的选项。

此外,如果网络不通(比如国内无法访问 GitHub raw),扩展会直接崩溃,连本地已下载好的服务器文件也不看,导致 Kotlin 文件完全没有 LSP。

Java LSP(Eclipse JDT LS)是独立扩展,通常不受影响。

解决方案

方案一(推荐):手动安装 fwcd/kotlin-language-server

绕过内置扩展的 IntelliJ 服务器,使用独立的 fwcd/kotlin-language-server。

下载

从 GitHub Releases 下载最新版 server.zip

# 如果无法直接访问 GitHub,使用 ghproxy 镜像
curl -sL -o server.zip \
  "https://ghproxy.net/https://github.com/fwcd/kotlin-language-server/releases/download/1.3.13/server.zip"
# 你也可以直接使用浏览器访问这个地址进行下载

解压

mkdir -p ~/.local/share/kotlin-language-server
unzip server.zip -d ~/.local/share/kotlin-language-server/
chmod +x ~/.local/share/kotlin-language-server/bin/kotlin-language-server

验证

# 发送 LSP initialize 请求测试
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"capabilities":{},"rootUri":null}}' \
  | timeout 3 ~/.local/share/kotlin-language-server/bin/kotlin-language-server 2>&1 | head -5

配置 Zed

在项目根目录创建 .zed/settings.json

{
    "lsp": {
        "java": {
            "settings": {
                "java.configuration.runtimes": [
                    {
                        "name": "JavaSE-1.8",
                        "path": "/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home",
                        "default": true
                    }
                ],
                "java.import.gradle.enabled": true,
                "java.import.gradle.wrapper.enabled": true,
                "java.import.gradle.version": "6.5",
                "java.import.gradle.home": "",
                "java.import.gradle.user.home": "${workspaceFolder}/.gradle-home",
                "java.import.gradle.offline.enabled": false
            }
        },
        "kotlin-language-server": {
            "binary": {
                "path": "~/.local/share/kotlin-language-server/bin/kotlin-language-server"
            },
            "settings": {
                "kotlin.compiler.jvmTarget": "1.8",
                "kotlin.trace.server": "off",
                "kotlin.excludes": "**/build/**, **/.gradle/**"
            }
        }
    },
    "languages": {
        "Kotlin": {
            "language_servers": ["kotlin-language-server"]
        }
    },
    "file_scan_exclusions": [
        ".gradle/**",
        "build/**",
        "*/build/**",
        "**/build/**",
        ".git/**",
        ".idea/**",
        "**/*.jar",
        "**/*.aar",
        "**/*.class"
    ]
}

关键点:

  • binary.path — 指向手动安装的 kotlin-language-server 可执行文件
  • languages.Kotlin.language_servers — 强制 Kotlin 文件使用这个自定义 LSP,不再尝试内置的 IntelliJ 服务器
  • JDK 路径要根据本地环境调整

重启 Zed

cmd-q 完全退出后重新打开,底部状态栏应能看到 Java 和 Kotlin 两个 LSP 图标。

方案二:临时使用代理让内置扩展初始化(不推荐)

⚠️ 注意:JetBrains IntelliJ Server 认证已过期,此方案已失效。 仅当该问题未来被修复时才可能有用。

如果只是首次需要网络,临时设置代理后重启 Zed:

HTTPS_PROXY=https://ghproxy.net/ open -a Zed

扩展拿到 RELEASES.md 发现本地版本已是最新后,后续启动不再需要网络。

方案三:给混合模块的 build.gradle 加 sourceSets(辅助 JDT LS)

对于同时包含 Java 和 Kotlin 源码的模块,在 android {} 块内添加:

android {
    sourceSets {
        main {
            java.srcDirs += 'src/main/kotlin'
        }
    }
}

帮助 Eclipse JDT LS 的 Gradle 导入器识别 Kotlin 源目录。

注意事项

检查 Kotlin LSP 进程

ps aux | grep kotlin-language-server | grep -v grep | grep -v CompileDaemon

首次启动时,Kotlin LSP 会消耗大量 CPU(100%+)进行项目索引,属于正常现象,等待 1-2 分钟即可。

需要加 sourceSets 的混合模块

如果模块同时有 .java.kt 文件,建议加上 sourceSets 配置:

模块 Java Kotlin 需要
v4-core
core(旧版)
app
v4-tx-player
v4-youku-player

纯 Java 或纯 Kotlin 的模块不需要。

关于跨语言跳转

fwcd/kotlin-language-server 能解析 Java 类路径,因此从 Kotlin 文件跳转到 Java 类的定义是可以工作的。JDT LS 也能通过 Gradle 模型解析跨模块依赖。两者结合可实现完整的跨语言导航。