跳到主要内容

语言服务器的生命周期有哪些阶段?

结论​

顺序是客户端发 initialize,服务器返回能力,客户端再发 initialized,之后才是文档同步和各种语言请求。结束时客户端发 shutdown 请求,再发 exit 通知,然后进程退出。

展开​

  1. 扩展激活,客户端按 ServerOptions 启动进程。
  2. initialize 请求带上进程 id、根 URI、工作区文件夹、客户端能力、初始化选项。服务器还不能发业务请求。
  3. 服务器回复自己的 capabilities,例如文本同步方式、是否支持补全和定义。
  4. 客户端发 initialized 通知。之后服务器才能发 workspace/configuration、动态注册之类的请求。
  5. 打开文档时 textDocument/didOpen。客户端把全文交给服务器。
  6. 编辑时 didChange,保存 didSave,关闭 didClose。
  7. 用户操作触发 textDocument/completion、hover、definition 等请求。
  8. 插件停用或窗口关闭:shutdown 请求,服务器清资源并响应;随后 exit 通知,进程退出。

服务器在 initialize 完成前就推诊断,客户端可以丢掉。动态注册(client/registerCapability)要等 initialized 之后。

配置变化通常由客户端再通知服务器,或者服务器自己请求 workspace/configuration。不要只在启动时读一次配置然后永远不更新。

容易讲错的点​

  • shutdown 是请求,exit 才是通知。只杀进程不做 shutdown,服务器来不及写缓存。
  • initialized 和 initialize 不是重复消息。前者是通知,表示「握手完成,可以开始主动要东西」。
  • 服务器持有的是文档副本。用户没打开的文件,服务器默认看不到,除非用工作区符号或自己的工程索引。