LSP(Language Server Protocol)是由 redhat, microsoft, codenvy 联合推出的语言服务器协议,
用于编辑器和语言服务器之间的通信。
LSP is a win for both language tooling providers and code editor vendors!
LSP创造了编辑器和编程语言的一种双赢局面。
1. 复杂度
我们知道市面上有很多种不同的编辑器,VSCode,IntelliJ IDEA,Emacs,Vim,……
每一个编辑器也能支持多种不同的编程语言,Java,JavaScript,Python,Ruby,……
编辑器中有一些常见的功能,通常需要在每个编辑器中,针对每一种编程语言单独实现一遍,
例如,自动完成(auto complete),转到定义(go to definition),鼠标悬停展示文档(documentation on hover),……
这样的实现方式太繁琐了,上述功能,我们能不能让每个编辑器,对于不同的编程语言只实现一遍?
这就是LSP给出的解决方案,编辑器只管基于LSP跟语言服务器通信就好了,
通过LSP,问题复杂度由原来的 m * n
转换为了 m + n
,
其中 m
为编程语言的数量,n
为编辑器的数量。
对于自动完成/转到定义/鼠标悬停展示文档,每个编辑器只用实现一遍,
每种编程语言也只用实现一遍。
2. 跨语言
语言服务器通常是由编程语言自身实现的,
Java语言服务器,和Node.js语言服务器,可能分别是由Java和Node.js编写的,
Language Servers are usually implemented in their native programming languages.
因此,基于LSP的编辑器,如果要同时TypeScript和PHP,
必须有办法同时跟TypeScript语言服务器,和PHP语言服务器通信。
此外,自动完成/转到定义/鼠标悬停展示文档,等等这些功能,比起编辑器而言,可能更加浪费资源,
例如,对文件进行检查时,语言服务器可能需要解析一个很长的文本,将其转换成AST(Abstract Syntax Tree),然后再执行静态检查。
Language features can be resource intensive.
所以最好的办法是,让语言服务器运行在单独的进程中,
编辑器和语言服务器之间,通过进程间通信(RPC)完成交互,这是一种C/S架构(client-server mode)。
上图为VSCode与语言服务器之间的通信过程,
其中,客户端(Language Client)是由VSCode插件实现的(使用TypeScript编写)。
如图对于TypeScript,VSCode通过LSP与TS语言服务器通信,
对于PHP,VSCode与PHP语言服务器通信。
3. 协议 & 规范
3.1 通信协议
编辑器与语言服务器之间,是基于JSON-RPC通信的。
JSON-RPC,是一个开源RPC协议,
规定了RPC请求,响应,以及请求错误的格式,
JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol.
3.2 语言服务器规范
LSP是一个协议,不是具体的实现,它规定了语言服务器应当实现的一些规范条件,
比如,编码格式,数据结构(Text Documents,Position,Range,Location,……),生命周期(Server lifetime),
以及服务器可支持哪些语言特性(Language Features),例如,completion,hover,definition,codelens等等。
具体的语言服务器,不必支持规范中提到的所有语言特性,
它支持的那部分特性集合,称为语言服务器的能力(Capabilities)。
A capability groups a set of language features.
4. 示例
下面我们来实际运行一下,示例来自Language Server Extension Guide,
源码仓库位于lsp-sample。
$ git clone https://github.com/microsoft/vscode-extension-samples.git
$ cd vscode-extension-samples/lsp-sample
$ npm i
使用VSCode打开,这个文件夹,
然后在 server/src/server.ts
第 123
行打个断点,
在Debug面板选择Client + Server
这个调试选项,然后启动调试,
VSCode会弹出一个新的窗口,这个窗口是用来调试VSCode插件用的,它是语言服务器的客户端,
我们在这个新窗口中新建一个文件,index.txt
,然后保存,就会跳到断点位置,
(注意,后缀名必须是 .txt
才可以。)
本示例中,新建以及后续修改.txt
文件,会触发语言服务器中的documents.onDidChangeContent
事件,
语言服务器会对该文件进行校验validateTextDocument
,返回诊断信息。
我们依次输入 A
和 B
,试一试,
会发现输入 B
之后,字符下面会出现一个绿色的曲线,这就是诊断信息。
鼠标移动到上面,会弹出一个悬浮框,
这正是validateTextDocument
中实现的功能,
参考
LSP
github: language-server-protocol
VSCode: Language Server Extension Guide
Language Server Protocol
Implementations: Language Servers
JSON-RPC
LSP: specification
LSP: Capabilities
网友评论