VSCode是LSP客户端,需自行实现符合规范的language server;常见失效原因包括server未启动、未调用connection.listen()、capabilities字段缺失或错误、hover range越界或contents非法等。

VSCode 本身不直接开发 LSP(Language Server Protocol),它只是 LSP 的客户端;真正要做的,是写一个符合 LSP 规范的 language server 程序,并通过 vscode-languageclient 在 VSCode 中启动它。
为什么你的 LSP 扩展没响应?检查 server 是否真在运行
LSP 扩展失效最常见的原因是 language server 进程根本没起来,或者启动后立刻退出。VSCode 只负责转发 JSON-RPC 消息,不负责实现协议逻辑。
- 在扩展的
activate()中,用LanguageClient启动 server 时,务必检查serverOptions:若用run/debug两个配置,确保run.command指向可执行文件(如node或编译后的二进制),且路径不含空格或未转义的反斜杠 - 在 server 端(比如用
vscode-languageserver-node),必须调用createConnection()+connection.listen(),缺一不可;漏掉listen()就等于没开监听,VSCode 发来的初始化请求会超时 - 加一句
console.error到 server 入口最开头,再看 VSCode 的Output面板 → 切换到对应Language Server标签,能快速判断进程是否启动成功
vscode-languageclient 启动模式选 stdio 还是 ipc?
绝大多数场景下,无脑选 stdio。VSCode 官方文档和模板默认都用它,兼容性最好,调试也最直接。
-
stdio:server 以子进程方式启动,标准输入/输出作为 RPC 通道;调试时可直接 attach 到子进程(如用node --inspect-brk) -
ipc:依赖 Node.js 的child_process.fork(),只适用于 server 也是 Node.js 编写且与 client 同版本;跨版本或非 Node server(如 Rust 的rust-analyzer)根本不支持 - 如果 server 启动报错
Error: write EPIPE,大概率是 server 过早退出导致 stdio 断连——先查 server 日志,别急着换 ipc
初始化失败卡在 initialize?重点核对 capabilities 字段
VSCode 发送 initialize 请求后,server 必须在响应中返回完整的 capabilities 对象,否则 client 会认为协商失败,后续所有功能(hover、completion)全部禁用。
- 常见低级错误:手写 JSON-RPC 响应时漏掉
capabilities.textDocumentSync—— 即使你暂时不做文件同步,也得显式设为0(表示不支持)、1(全量同步)或2(增量同步) - 若用
vscode-languageserver-node,推荐直接用TextDocuments类管理文档,它会自动帮你处理textDocument/didOpen等基础同步逻辑 - 不要在
initialize响应里返回 VSCode 不认识的 capability 字段(比如拼错成completionsProvider而不是completionProvider),某些老版本 client 会静默忽略整个 capabilities
为什么 hover 返回了但不显示?检查 range 和 markupContent
Hover 内容不出现,90% 是因为 server 返回的 Hover 对象结构不合法,VSCode 直接丢弃响应。
-
range字段必须存在且覆盖光标所在位置;若用Position计算 range,请确认行号/列号从 0 开始(LSP 规范强制要求),而不少编辑器 API 默认从 1 开始 -
contents必须是string、MarkupContent或Array<MarkedString>;其中MarkupContent要求kind: "plaintext"或"markdown",且value是字符串——传null或undefined会导致 hover 彻底消失 - 测试时,在 server 中硬编码返回一个固定
Hover,内容为{"contents": "test"},能快速排除前端解析问题
真正难的从来不是写通第一个 initialize,而是让每个 LSP 方法的输入校验、范围计算、异步时机都严丝合缝;VSCode 不报错,只沉默跳过非法响应——这意味着你得盯着 Output 面板里每一条原始 JSON-RPC 往来,而不是依赖“看起来有反应”。


















