Language Server Protocol

做者:Mattt,原文連接
原文日期:2018-11-19
html

譯者:雨謹
校對:numbbbbbpmst
定稿:Forelax前端

上個月,蘋果公司 在 Swift.org 論壇上宣佈,正在着手爲 Swift 和 C 語言支持 Language Server Protocol(語言服務器協議,LSP)。ios

對於蘋果公司而言,爲全部 Swift 開發者 —— 包括非蘋果平臺上的 —— 提供高質量的工具支持很是重要。咱們但願與開源社區合做,將精力集中在構建 Xcode 和其餘編輯器、其餘平臺能夠共享的公共基礎設施上。爲實現這一目標,[……],咱們決定支持 LSP。git

Argyrios Kyrtzidis,2018 年 10 月 15 日程序員

這多是蘋果自 2014 年將 Swift 做爲開源軟件發佈以來,爲 Swift 作出的最重要的決定。 這對於 APP 開發者來講是一件大事,對於其餘平臺上的 Swift 開發者來講更是一件大事。github

爲了理解其中的緣由,本週的文章將研究 Language Server Protocol 解決了什麼問題,它是如何工做的,以及它的長期影響多是什麼。編程

更新:sourcekit-lsp 項目如今已經能夠 在 GitHub 上訪問 了。json


想象這樣一個矩陣,每一行表示不一樣的編程語言(Swift、JavaScript、Ruby、Python 等),每一列表示不一樣的代碼編輯器(Xcode、Visual Studio、Vim、Atom 等),這樣每一個單元格表示特定編輯器對一種語言的支持級別。swift

lsp-languages-times-editors.svg

而後,你就發現各類組合造成了一種支離破碎的兼容。有些編輯器和部分語言深度集成,但除此以外幾乎什麼都幹不了;其餘編輯器則比較通用,對不少語言都提供了基本的支持。(IDE 這個術語一般用來描述前者。)後端

舉個奇葩的例子:你不用 Xcode 來開發 APP,卻偏用來幹其餘事情。

爲了更好地支持某一特定的語言,編輯器必須編寫一些集成代碼(integration code)—— 要麼直接寫在項目裏,要麼經過插件。因爲不一樣語言和編輯器的實現機制不同,所以比方說 Vim 改進了對 Ruby 支持,但這並不能讓它更好地支持 Python,也不能讓 Ruby 在 Atom 上運行地更好。最終的結果是:大量精力浪費在了不一樣技術的兼容上。

咱們上面描述的狀況一般被稱爲 M × N 問題,即最終的集成方案數量爲編譯器數量 M 與語言數量 N 的乘積。Language Server Protocol 所作的事情就是將 M × N 問題變成 M + N 問題

編輯器沒必要實現對每種語言的支持,只需支持 LSP 便可。以後,它就能同等程度地支持全部支持 LSP 的語言。

lsp-languages-plus-editors.svg

Tomohiro Matsuyama 在 2010 年寫的 "Emacs は死んだ" ("Emacs 已死") 這篇文章就對這種問題作出了一個很好的論述。Matsuyama 描述了 Emacs 腳本語言的侷限性(不支持多線程、底層 API 過少、用戶基數過小),他認爲編寫插件的首選方法應該是與外部程序進行交互,而不是原生實現。

Language Server Protocol 爲支持的語言提供了一套通用的功能集,包括:

  • 語法高亮(Syntax Highlighting)
  • 自動格式化(Automatic Formatting)
  • 自動補全(Autocomplete)
  • 語法(Syntax)
  • 工具提示(Tooltips)
  • 內聯診斷(Inline Diagnostics)
  • 跳轉到定義(Jump to Definition)
  • 項目內查找引用(Find References in Project)
  • 高級文本和符號搜索(Advanced Text and Symbol Search)

各類工具和編輯器能夠將精力用於提高可用性和提供更高級的功能,而不是爲每種新技術再造個輪子。

Language Server Protocol 的工做原理

若是你是一個 iOS 程序員,那麼必定很熟悉 serverprotocol 這兩個術語在 Web 應用程序的 HTTP + JSON 通訊場景下的含義。實際上 Language Server Protocol 差很少也是這麼工做的。

對於 LSP,client 是指編輯器 —— 或者更寬泛一點,是指工具,server 是指本地獨立進程裏運行的一個外部程序。

至於名字中包含 protocol,是由於 LSP 相似於一個精簡版的 HTTP:

  • 每一個消息都由報頭部分和內容部分組成。
  • 報頭部分包含一個必填的 Content-Length 字段,用於說明內容部分的大小(以字節爲單位),以及一個可選的 Content-Type 字段(默認值爲 application/vscode-jsonrpc; charset=utf-8)。
  • 內容部分使用 JSON-RPC 描述請求、響應和通知的結構。

每當工具中發生了什麼事情,好比用戶須要跳轉到符號的定義,工具就會向 server 發送一個請求。server 接收到該請求,而後返回適當的響應。

class Parent {}
class Child: Parent {}
複製代碼

lsp-jump-to-definition.gif

如下是 LSP 如何在幕後實現這種交互:

首先,當用戶打開 Swift 代碼時,若 Swift language server 並未運行,編輯器將在一個獨立進程中啓動它,並執行一些額外的配置。

當用戶執行 "跳轉到定義(jump to definition)" 指令時,編輯器向 Swift language server 發送如下請求:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "textDocument/definition",
  "params": {
    "textDocument": {
      "uri": "file:///Users/NSHipster/Example.swift"
    },
    "position": {
      "line": 1,
      "character": 13
    }
  }
}
複製代碼

收到這個請求後,Swift language server 使用 SourceKit 等編譯器工具來標識相應的代碼實體,並在代碼的上一行找到其聲明的位置。而後 language server 用如下消息進行響應:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "uri": "file:///Users/NSHipster/Example.swift",
    "range": {
      "start": {
        "line": 0,
        "character": 6
      },
      "end": {
        "line": 0,
        "character": 12
      }
    }
  }
}
複製代碼

最後,編輯器導航到文件(在本例中,該文件已經打開),將光標移動到該範圍,並高亮顯示出來。

這種方法的美妙之處在於,編輯器完成全部這些操做時,除了 .swift 文件與 Swift 代碼相關之外,對 Swift 編程語言一無所知。編輯器須要作的就是與 language server 對話並更新 UI。並且編輯器知道如何作到這一點後,就能夠遵循相同的過程,與任何帶有 language server 的語言所編寫的代碼進行交互。

Clang / LLVM 裏的 Language Server Protocol

若是你以爲以前的 M + N 圖有點眼熟,那多是由於 LLVM 也採用了一樣的方法。

LLVM 的核心是中間表示(intermediate representation,IR)。LLVM 所支持的語言使用 編譯器前端(compiler frontend) 生成 IR,再使用 編譯器後端(compiler backend) 將 IR 生成所支持平臺的機器碼。

lsp-llvm-ir.svg

若是你想了解 Swift 代碼編譯的更多細節,請查看 咱們關於 SwiftSyntax 的文章

Clang 是 C 語言的 LLVM 編譯器前端。Swift 與 Objective-C 的互操做性(inter-operability)就是靠它實現的。在最近的 5.0.0 版本中,Clang 添加了一個名爲 Clangd 的新工具,它是 LLVM 對 Language Server Protocol 的實現。

2018 年 4 月,蘋果公司向 LLVM 郵件組宣佈,將把開發的重心從 libclang 轉向 Clangd,以其做爲建立交互工具的主要方式。

如今你可能會想,「那又怎樣?」 蘋果公司是 LLVM 項目最重要的支持者之一,該項目創始人 Chris Lattner 已經在蘋果公司工做了十多年。蘋果公司決定從不透明的 Clang 工具切換到另外一個,彷佛是一個實現細節了(能夠這麼說)。

這個官宣頗有趣的一點是,Clangd 彷佛徹底是在蘋果之外開發的,谷歌和其餘公司也作出了重大貢獻。這個官宣標誌着將來工具開發方向的重大轉變 —— 六個月後 Swift.org 論壇將證明這一點。

蘋果支持 Language Server Protocol 的潛在影響

根據蘋果公司 10 月份發佈的 LSP 公告,咱們預計在將來幾周內(撰寫本文時,最先 11 月中旬)將看到該項目的首批代碼。

要感覺這些發展的所有影響還須要一些時間,但請相信我:你的耐心是值得的。我相信如下是 LSP 在將來幾個月和幾年將會發生的一些事情。

Swift 變成一種更加通用的編程語言

雖然 Swift 主要用於 APP 開發,但它從一開始就被設計成一種功能強大的通用編程語言。在 Swift for TensorFlowSwiftNIO 和其餘項目中,咱們正開始看到 Swift 承諾的在 App Store 以外的使用。

到目前爲止,阻礙 Swift 被主流採用的最大因素之一是它對 Xcode 的依賴。

人們會有不少質疑,當有那麼多優秀的、門檻低不少的替代方案可選的狀況下,爲何還要讓 Web 開發者或機器學習工程師僅僅爲了嘗試 Swift 而去下載 Xcode?支持 Language Server Protocol 可讓蘋果生態圈之外的人更容易地使用他們熟悉工具去感覺 Swift。

Xcode 變得更好

支持 LSP 不只僅是讓 Swift 在其餘編輯器中運行地更好,Xcode 也將受益不淺。

看看蘋果 Swift 項目負責人 Ted Kremenek 的 這篇論壇帖子:

@akyrtzi 所描述的 LSP 服務將比今天的 SourceKit 更強大。

LSP 對 Xcode 團隊來講是一個機遇,讓他們使用一種新的方法實現 Swift 集成,並能夠將其應用在語言和工具自 1.0 版本發佈以來四年中的全部改進上。

Xcode(最終)變得更強大

LSP 的好處並不限於 Swift 和 Objective-C,Argyrios 在那個帖子的另外一個留言中指出

Xcode 使用咱們新的 LSP 服務,這意味着它也可使用其餘 LSP 服務,咱們對此很感興趣,不過目前暫無具體計劃。

目前的工做重點是改進 Swift。可是,一旦實現了這一點,就應該能相對簡單地將這些優化轉移到支持 LSP 的其餘語言中。


軟件的架構反映了建立它的組織的結構和價值。在某種程度上,反之亦然。

經過讓 Xcode 支持開放的 Language Server Protocol 標準,蘋果正在履行其在蘋果生態系統以外的平臺上實現 Swift 成功的承諾。我認爲這是可行的:工具(或缺乏工具)一般是技術得到人心的關鍵決定因素。但或許更重要的是,我認爲這一決定代表,公司內部(至少是一小部分)對合做和透明度的意願有所加強。

本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 swift.gg

相關文章
相關標籤/搜索