LSP-language-server-protocol規範學習

豆皮粉兒們,又見面了,今天這一期,由字節跳動數據平臺的「蟲二」,給你們講一講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)

LSP概述

什麼是LSP

每一個開發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對於語言提供商和工具的提供商都是共贏!

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會爲每種編程語言啓動語言服務器,如下示例顯示IDE如何在一個會話上使用Java和SASS文件。

圖片

LSP的 capability

並非每種語言服務器均可以支持協議定義的全部功能,所以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

LSP的提供者和使用者的庫(SDK)

爲了簡化語言服務器和客戶端的實現,提供了庫或SDK:

  • IDE SDK: 每一個開發工具一般都提供一個用於集成語言服務器的庫。例如,對於JavaScript / TypeScript,有語言客戶端npm模塊[1],用於簡化語言服務器和vs擴展的集成。

  • 用於實現不一樣語言的語言服務器SDK: 一個SDK可用於以特定語言實現語言服務器。例如,要使用Node.js實現語言服務器,可使用語言服務器npm模塊[2]。

References

[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

相關文章
相關標籤/搜索