豆皮粉儿们,又见面了,今天这一期,由字节跳动数据平台的“虫二”,给你们讲一讲LSP-language-server-protocol。c++
本文做者:虫二git
LSP-language-server-protocol规范学习github
官方文档: microsoft.github.io/language-se…npm
vscode LSP文档(可中文阅读): docs.microsoft.com/zh-cn/visua…编程
yuge最近在学习WebIDE的实现机制,须要实现相似IDE的智能提示、语法检查和解析、悬停文档等交互体验;因为无法直接嵌入进来VSCode,因而想学习相关方面的实现,目标是利用Monaco和LSP实现一个IDE。后端
LSP(Language Server Protocol) 语言服务协议,该协议定义了在编辑器或IDE与语言服务器之间使用的协议,该语言服务器提供了例如自动补全,转到定义,查找全部引用等的功能;语言服务器索引格式的目标是支持在开发工具中进行丰富的代码导航或者一个无需本地源码副本的WebUI。服务器
分如下几个方面markdown
什么是LSPapp
LSP如何工做编程语言
IDE 和语言服务器如何交互
LSP的功能
LSP的提供者和使用者的库(SDK)
每一个开发IDE,都要为语言实现类如自动补全,转动定义,悬停在单词上提供文档的功能,传统上,须要个IDE根据本身的API实现上述工做,即便是相同的功能,也要根据不一样IDE实现一遍重复的功能,代码却不一样。例如,Eclipse CDT 插件(在 Eclipse IDE 中支持 C/C++)是用 Java 编写的,由于 Eclipse IDE 自己是用 Java 编写的。按照此方法,这意味着在 Visual Studio 代码的 TypeScript 中实现 C/C++ 域模型,在 Visual Studio 的 C# 中实现单独的域模型。
若是开发工具能够重用现有的特定于语言的库,则建立特定于语言的域模型也容易得多。可是,这些库一般在编程语言自己中实现(例如,好的 C/C++域模型在 C/C++中实现)。将 C/C++ 库集成到用 TypeScript 编写的编辑器中,在技术上是可能的,但很难作到。
一个语言服务器旨在提供某个语言的智能化,并经过支持进程间通讯的协议与开发工具进行通讯。
LSP设计的目标是使该语言服务器和开发工具进行标准化的通讯,这个语言服务能够在多个开发工具中重复使用,从而以最小的改动支持多种语言。语言服务器后端能够用PHP,Python或Java编写,LSP能够轻松地将其集成到各类工具中,该协议提供通用抽象级别的协议,以便工具能够提供丰富的语言服务,从而无需彻底理解特定于底层域模型的细微差异。
LSP对于语言提供商和工具的提供商都是共赢!
语言服务器会做为单独的进程运行,同时开发工具使用基于JSON-RPC的语言协议与服务器进行通讯。
如下是一个开发工具和语言服务器在运行编辑期间的通讯示例:
用户在IDE中打开文件时: IDE会通知语言服务器文件已打开(textDocument/didOpen),此时文档的内容不会存在于真实的文件系统中,而是保存在IDE内存中。必须在IDE和语言服务器之间同步内容。
用户编辑文件时:IDE会通知语言服务器文件更新(textDocument/didChange),而且语言服务器会更新文件的语言表示。以后语言服务器会分析此消息,并将检测到的错误和警告,响应(textDocument/publishDiagnostics)通知IDE。
用户执行"Goto Definition" 指令时: IDE发送带有参数的请求(textDocument/definition), params: {documentURI, position} 到语言服务器,语言服务器以文档URI和definition的Location做为响应。
如下是一个c++ 语言的例子
用户关闭文件时: IDE通知语言服务器文件关闭(textDocument/didClose), 文件已经不在内存中了,此时当前内容在文件系统中就是最新的。
上述示例说明了协议如何在文档引用(URI)和文档位置级别与语言服务器进行通讯。这些数据类型与编程语言无关,适用于全部编程语言。数据类型不在编程语言域模型的级别,后者一般会提供抽象语法树和编译器符号(例如,解析的类型,名称空间等)。事实是,数据类型简单且编程语言无关,从而大大简化了协议。与标准化抽象语法树和跨不一样编程语言的编译器符号相比,标准化文本文档URI或光标位置要容易得多。
当用户使用不一样的语言时,IDE会为每种编程语言启动语言服务器,如下示例显示IDE如何在一个会话上使用Java和SASS文件。
并非每种语言服务器均可以支持协议定义的全部功能,所以LSP提供了capabilities,一个capabilities能够将一组语言capability组合在一块儿,IDE和语言服务器使用能力宣布其支持的功能。
例如,语言服务器宣布能够处理textDocument/definition 的请求,但可能不会处理workspace/symbol的请求。一样,IDE宣布在保存文档以前提供 about to save(即将保存)通知功能,以便服务器能够计算文本编辑器在保存以前对已编辑的文档进行格式化。
须要注意:语言服务器到特定IDE的实现集成不是由语言服务器协议定义的,而是由IDE实现者决定
如下是Visual Studio提供的功能
MessageHas Support in Visual StudioSWIDE | ||
initialize | yes | |
initialized | yes | |
shutdown | yes | |
exit | yes | |
$/cancelRequest | yes | |
window/showMessage | yes | |
window/showMessageRequest | yes | |
window/logMessage | yes | |
telemetry/event | ||
client/registerCapability | ||
client/unregisterCapability | ||
workspace/didChangeConfiguration | yes | |
workspace/didChangeWatchedFiles | yes | |
workspace/symbol | yes | |
workspace/executeCommand | yes | |
workspace/applyEdit | yes | |
textDocument/publishDiagnostics | yes | |
textDocument/didOpen | yes | |
textDocument/didChange | yes | |
textDocument/willSave | ||
textDocument/willSaveWaitUntil | ||
textDocument/didSave | yes | |
textDocument/didClose | yes | |
textDocument/completion | yes | |
completion/resolve | yes | |
textDocument/hover | yes | |
textDocument/signatureHelp | yes | |
textDocument/references | yes | |
textDocument/documentHighlight | yes | |
textDocument/documentSymbol | yes | |
textDocument/formatting | yes | |
textDocument/rangeFormatting | yes | |
textDocument/onTypeFormatting | ||
textDocument/definition | yes | |
textDocument/codeAction | yes | |
textDocument/codeLens | ||
codeLens/resolve | ||
textDocument/documentLink | ||
documentLink/resolve | ||
textDocument/rename | yes |
为了简化语言服务器和客户端的实现,提供了库或SDK:
IDE SDK: 每一个开发工具一般都提供一个用于集成语言服务器的库。例如,对于JavaScript / TypeScript,有语言客户端npm模块[1],用于简化语言服务器和vs扩展的集成。
用于实现不一样语言的语言服务器SDK: 一个SDK可用于以特定语言实现语言服务器。例如,要使用Node.js实现语言服务器,可使用语言服务器npm模块[2]。
[1]
npm模块: www.npmjs.com/package/vsc…
[2]
语言服务器npm模块: www.npmjs.com/package/vsc…
[3]
语LSP-language-server-protocol规范学习: mp.weixin.qq.com/s/leNgwb0fT…
The End