VSCode 建議你啟用 gopls,它到底是個什麼東東?

要談 gopls,得先聊聊 LSP。

LSP 是什麼

LSP,全稱 Language Server Protocol,即語言服務器協議,這是微軟創建的一個協議(目前已有 Codenvy,Red Hat 和 Sourcegraph 等公司一起支持它的發展)。定義了在編輯器或 IDE 中與語言服務器之間使用的協議,該語言服務器提供諸如自動完成,轉到定義,查找所有引用等語言功能。語言服務器索引格式(LSIF,其發音類似於“ else if”)的目標是支持開發工具或 Web UI 中的富代碼導航,而不需要源代碼的本地副本。

目前該協議得到了編輯器和語言社區的廣泛支持。

LSP 的官方網站:https://microsoft.github.io/language-server-protocol/,GitHub 地址:https://github.com/Microsoft/language-server-protocol。目前最新版本(2020-09-06):3.15。

LSP 解決了什麼問題

為編程語言添加諸如自動完成、轉到定義或鼠標懸停出現文檔之類的功能需要付出大量的努力。傳統上,這項工作必須為每個開發工具重複進行,因為每個工具為實現相同的特性提供不同的 api。

語言服務器(Language Server)旨在提供特定語言的智能功能,並通過支持進程間通訊協議與開發工具進行通信。

語言服務器協議(LSP)背後的思想是為這些服務器和開發工具的通信方式提供標準化協議支持。通過這種方式,可以在多個開發工具中重用單個 Language Server,而這些工具反過來可以用最少的工作支持多種語言。

例如,之前需要為 VSCode 構建 Go 插件、為 Sublime Text 構建 Go 插件、為 Vim 構建 Go 插件、為 Sourcegraph 構建 Go 插件,很多重複的工作。現在,對於每種語言,LSP 允許語言社區將精力集中在一個高性能語言服務器上,這個服務器可以提供代碼完成,懸停文檔提示、跳轉到定義、查找引用等功能,而編輯器和客戶端社區可以專注於構建一個單一的、高性能的、直觀的和慣用的擴展,這個擴展可以與任何語言服務器通信,即時提供深入的語言支持。

LSP 是語言提供商和工具供應商的雙贏!

LSP 的工作原理

語言服務器(Language Server)作為單獨的進程運行,開發工具在 LSP 基礎上通過 JSON-RPC 與服務器通信。下面是一個開發工具和語言服務器在進行編輯時如何通信的例子:

VSCode 建議你啟用 gopls,它到底是個什麼東東?

圖片來自 LSP 官網,演示了協議如何在文檔引用(uri)和文檔位置級別與語言服務器通信。這些數據類型與編程語言無關,適用於所有編程語言。

  • 用戶在開發工具中打開一個文件(稱為文檔):開發工具通知語言服務器文檔已打開(textDocument/didOpen)。從現在開始,關於文檔內容的真實信息不再存儲在文件系統中,而是由開發工具保存在內存中。現在必須在開發工具和語言服務器之間同步內容。
  • 用戶進行編輯:該開發工具通知服務器文檔更改(textDocument/didChange),並由語言服務器更新文檔的語言表示形式。在這種情況下,語言服務器會分析這些信息,並將檢測到的錯誤和警告通知開發工具(textDocument/publishDiagnostics)。
  • 在打開的文檔中,用戶就一個符號(symbol)執行 Go to Definition:該開發工具發送一個帶有兩個參數的 “textdocument/Definition” 請求:(1)文檔 URI 和(2)發出 “Go to Definition” 請求的文本位置,發送到服務器。服務器的響應包含文檔 URI 和該符號在該文檔中的定義位置。
  • **用戶關閉文檔(文件) **:開發工具發出 “textDocument/didClose” 的通知,告知語言服務器文檔現在不在內存中了。文件系統上的當前內容現在是最新的。

看一個具體的 “textDocument/definition” 示例,以 Go 語言為例,請求如下:

<code>{
    "jsonrpc": "2.0",
    "id" : 1,
    "method": "textDocument/definition",
    "params": {
        "textDocument": {
            "uri": "/Users/xuxinhua/project/golang/lsp/use.go"
        },
        "position": {
            "line": 3,
            "character": 12
        }
    }
}
/<code>

對此請求的響應:

<code>{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "uri": "/Users/xuxinhua/project/golang/lsp/provide.go",
        "range": {
            "start": {
                "line": 0,
                "character": 4
            },
            "end": {
                "line": 0,
                "character": 11
            }
        }
    }
}
/<code>

如果你想要開發一個 Language Server,可以看官方的協議規範。

gopls 是什麼

經過上面對 LSP 的介紹,你應該猜到 gopls(讀音:go please) 是什麼了吧?!沒錯,gopls 是 LSP 的一個語言端(Server)實現,是針對 Go 語言的 LSP 實現。

在 LSP 官網列出了相關的實現,包括三個部分。

1、Language Servers:列出各個語言的 LSP 實現

其中 Go 語言的實現有兩個:(Sourcegraph 的不再維護,因為集中維護一個會更好)

VSCode 建議你啟用 gopls,它到底是個什麼東東?

在另一個由 Sourcegraph 維護的網站 https://langserver.org/ 中,不但列出了實現 LSP 的語言,而且給出了它們對協議的實現完整性。

VSCode 建議你啟用 gopls,它到底是個什麼東東?

也就是說 gopls 是 Go 官方維護的、對 LSP 的實現,即一個 Go 語言的官方 Language Server

2、LSP Clients:列出支持 LSP 的開發工具

包括 VSCode、Sublime Text、Atom、Emacs、Vim 和 Eclipse 等很多開發工具。在上文提到的兩個網站都有列出。

3、SDKs for LSP:為了方便開發

為了方便開發,還有一些 LSP 的 SDK 可以使用。具體可以查看:https://microsoft.github.io/language-server-protocol/implementors/sdks/。

進一步瞭解 gopls

首先說明下,目前 gopls 還不是穩定版本,處於 alpha 狀態,所以 VSCode 默認沒有啟用它。項目地址:https://github.com/golang/tools/tree/master/gopls。

目前 gopls 支持的特性包括:

  • Autocompletion
  • Jump to definition
  • Signature help
  • Hover
  • Document symbols
  • References
  • Rename

目前已知存在如下的問題:

  1. Editing multiple modules in one editor window: #32394[1]
  2. Type checking does not work in cgo packages: #35721[2]
  3. Does not work with build tags: #29202[3]
  4. Find references and rename only work in a single package: #32877[4]

當前 gopls 的工作重點是確保穩定性(期待發布 1.0 版本),之前一直受詬罵的是資源佔用,目前已經好太多了。

有如下編輯器支持 gopls,你可以根據自己喜愛的編輯器查看相應的安裝、配置說明。

  • VSCode[5]
  • Vim / Neovim Vim/Neovim[6]
  • Emacs[7]
  • Acme[8]
  • Sublime Text[9]
  • Atom[10]

玩轉 VSCode 的文章會詳細介紹在 VSCode 中使用 gopls。同時,後續在 VSCode 開發其他語言項目時,也會介紹相應語言的 LSP。

參考資料

[1]

#32394: https://github.com/golang/go/issues/32394

[2]

#35721: https://github.com/golang/go/issues/35721

[3]

#29202: https://github.com/golang/go/issues/29202

[4]

#32877: https://github.com/golang/go/issues/32877

[5]

VSCode: https://github.com/golang/tools/blob/master/gopls/doc/vscode.md

[6]

Vim / Neovim Vim/Neovim: https://github.com/golang/tools/blob/master/gopls/doc/vim.md

[7]

Emacs: https://github.com/golang/tools/blob/master/gopls/doc/emacs.md

[8]

Acme: https://github.com/golang/tools/blob/master/gopls/doc/acme.md

[9]

Sublime Text: https://github.com/golang/tools/blob/master/gopls/doc/subl.md

[10]

Atom: https://github.com/golang/tools/blob/master/gopls/doc/atom.md


分享到:


相關文章: