Eclipse LSP服务的代码分析
Eclipse的c/c++语法服务组件分为三部分插件,从顶层到底层依次是cdt-lsp,lsp4e,lsp4j。其中 lsp4j是lsp协议的java实现,是可以脱离eclipse运行的。lsp4e主要作用是将eclipse的编辑器与lsp4j绑定,cdt-lsp的主要作用是配置clangd的路径。Lsp4j是基础,lsp4e是核心,cdt-lsp是用于配置lsp4e。
org.eclipse.lsp4e.LanguageServerWrapper类是启动clangd可执行程序,多线程监听输入输出的核心。
LanguageServerWrapper的启动
LanguageServerWrapper.start
HandlerProxy.setEnabled(Object) line: 229方法会在编辑器打开的时候调用创建lspStreamProvider
LanguageServerWrapper.start()方法会调用lspStreamProvider.start(),lspStreamProvider.start()会读取cdt-clangd插件配置的clangd路径和clangd的启动参数,然后启动一个Process。创建LanguageServer对象
启动lspStreamProvider之后,LanguageServerWrapper会创建一个org.eclipse.lsp4j.jsonrpc.Launcher.Builder对象,通过此对象用于配置和创建LanguageServer对象。创建StreamMessageProducer对象
为了实现从Process的标准输出里读取jsonrpc的返回值,创建了一个StreamMessageProducer对象,该对象是读取jsonrpc返回值创建ResponseMessage对象的核心方法。创建StreamMessageConsumer对象
为了往Process的标准输入里面写入一个json对象,创建了一个StreamMessageConsumer对象,该对象的作用是将RequestMessage写入到Process的标准输入。创建ConcurrentMessageProcessor对象
为了持续读取Process的标准输入输出,使用MessageProducer, MessageConsumer作为参数创建了一个ConcurrentMessageProcessor的Runable类并将其放在线程池里面执行。
RequestMessage和ResponseMessage
以鼠标覆盖代码以获得api提示为例介绍,lsp4e插件是如何与clangd可执行程序交互的。
配置LSPTextHover
将LSPTextHover与编辑器绑定,使得编辑器获取鼠标覆盖事件时调用LSPTextHover。调用getHoverInfo
创建RequestMessage对象
- 发送RequestMessage
调用StreamMessageConsumer,将RequestMessage对象写入到Process的标准输入
接收clangd的输出
发送了RequestMessage对象之后,clangd会输出一些字符串,此时另一个线程的int c = input.read();语句解除等待。
从input里面读取字符串,将该字符串使用GSON解析为ResponseMessage对象
处理获取的message对象。callback.consume(message);
在创建RequestMessage对象时,需要为其赋予一个ID,clangd输出的字符串也有哟个ID,该ID与RequestMessage的ID一致,因此就可以确定ResponseMessage与RequestMessage的一一对应关系。
将ResponseMessage返回到getHoverInfo方法
编辑器展示string的提示
