Gopls:基於 Web 的功能

LSP 的 window.showDocument 請求允許伺服器指示客戶端在編輯器中開啟檔案或在瀏覽器中開啟網頁。這是 gopls 透過 Web 介面報告程式資訊的多個功能的依據。

我們認識到,Web 介面並非適合所有人:一些使用者偏好全屏編輯器佈局,不喜歡切換視窗;另一些使用者可能只在沒有視窗系統的純文字終端中工作,或許是透過遠端 SSH 或在 Linux 控制檯上。不幸的是,LSP 缺乏幾種自然的擴充套件能力,包括伺服器定義功能的許可權。

  • 可以 泛化 References 查詢 並使用相似 UI 元素顯示結果的查詢;
  • 可以 生成文字流(類似於典型的 shell 命令或編譯器),客戶端可以將其重定向到編輯器常用的類終端 UI 元素中的命令;或
  • 像 Rename 一樣,需要 提示使用者 獲取額外資訊的重構操作。

在 LSP 提供實現這些功能的標準方法之前,基於 Web 的 UI 可以幫助彌補這些不足。

Gopls 的 Web 伺服器監聽 localhost 埠。為了安全起見,其所有端點都包含一個隨機字串,用作身份驗證令牌。客戶端在獲得伺服器提供的身份驗證 URL 後,將能夠訪問您的原始碼,但您機器上執行的任意程序將無法訪問。重新啟動 gopls 程序會導致此金鑰更改,使所有現有舊 URL 無效;現有頁面將顯示一個橫幅,表明它們已斷開連線。

待辦:合併 Web 伺服器和除錯伺服器;請參閱 https://golang.org.tw/issue/68229

Gopls 支援 Web 瀏覽器和客戶端編輯器之間的雙向通訊。所有基於 Web 的報告都包含指向您原始碼中宣告的連結。單擊其中一個連結會導致 gopls 向您的編輯器傳送一個 showDocument 請求,以在相應行開啟相關的原始檔。即使您的原始碼已被修改但未儲存,此功能也有效。(VS Code 使用者:如果您希望編輯器在處理此事件時將其視窗置頂,請點贊 microsoft/vscode#208093。)

source.doc:瀏覽程式包文件

在任何 Go 原始檔中,程式碼操作請求都會返回一個“瀏覽程式包文件”的命令。此命令會開啟一個瀏覽器視窗,顯示當前 Go 程式包的文件,其設計與 https://pkg.go.dev 類似。

這使您可以預覽程式包的文件,即使是內部但可能未公開的程式包。重新載入頁面會更新文件以反映您的更改。無需儲存已修改的 Go 原始檔。

單擊程式包級別符號或方法的連結(在 pkg.go.dev 中通常會帶您進入原始碼檢視器,例如 GitHub 或 Google Code Search)會導致您的編輯器導航到相關的原始檔和行。

客戶端支援 (Client support)

  • VS Code:使用“Source Action… > Browse documentation for package P”選單。
  • Emacs + eglot:在 go-mode 中使用 M-x go-browse-doc
  • Vim + coc.nvim: ??

source.freesymbols:瀏覽自由符號

在研究程式碼時,無論是為了理解程式碼還是評估不同的組織或重構方式,通常都需要了解給定程式碼塊的“輸入”,因為您可能正在考慮將其提取到一個獨立的函式中,並想知道它需要什麼引數,或者只是為了理解長函式中的一個部分如何與前面的部分相關聯。

如果您選擇一段程式碼並呼叫“Browse free symbols” 程式碼操作,您的編輯器將開啟一個瀏覽器,顯示所選內容的自由符號報告。如果一個符號在選擇範圍內被引用但定義在範圍之外,則該符號是“自由”的。本質上,這些是所選程式碼塊的輸入。

報告將符號分為匯入、本地和程式包級別符號。匯入的符號按程式包分組,並連結到該程式包的文件,如上所述。其餘每個符號都顯示為一個連結,該連結會導致您的編輯器導航到其宣告。

待辦:解釋點路徑。

客戶端支援 (Client support)

  • VS Code:使用“Source Action… > Browse free symbols”選單。
  • Emacs + eglot:在 go-mode 中使用 M-x go-browse-freesymbols
  • Vim + coc.nvim: ??

source.assembly:瀏覽彙編

當您最佳化程式碼效能或調查意外崩潰時,有時檢查編譯器為給定 Go 函式生成的彙編程式碼會很有幫助。

如果您將游標或選區放在函式 f 內,gopls 會提供“Browse assembly for f” 程式碼操作。這將開啟一個基於 Web 的列表,顯示該函式以及其中巢狀的任何函式的彙編程式碼。

每次編輯原始碼並重新載入頁面時,當前程式包都會重新編譯並更新列表。無需儲存已修改的檔案。

編譯器的目標架構與 gopls 分析檔案時使用的架構相同:通常是您機器的 GOARCH,但當檢視帶有構建標籤(例如名為 foo_amd64.go 或包含註釋 //go:build amd64 的檔案)的檔案時,標籤會決定架構。

每條指令都會顯示一個連結,該連結會根據除錯資訊,使您的編輯器導航到負責該指令的原始碼行。

上圖顯示了 time.NewTimer 的 arm64 彙編列表。請注意,指示的指令連結到 syncTimer 函式內部的原始碼位置,因為編譯器內聯了從 NewTimersyncTimer 的呼叫。

目前不支援為泛型函式、程式包初始化器(func init)或測試程式包中的函式瀏覽彙編。(歡迎貢獻!)

客戶端支援 (Client support)

  • VS Code:使用“Source Action… > Browse GOARCH assembly for f”選單。
  • Emacs + eglot:在 go-mode 中使用 M-x go-browse-assembly
  • Vim + coc.nvim: ??

source.splitPackage:拆分程式包為元件

基於 Web 的“Split package”工具可以幫助您將一個複雜的程式包拆分成兩個或多個元件,確保這些元件之間的依賴關係是無環的。

按照頁面上的說明選擇一組命名元件,將每個宣告分配給最合適的元件,然後視覺化由一個符號到另一個符號的引用所產生的元件之間的依賴關係。

下圖顯示了該工具在 fmt 程式包上的操作,該程式包(原則上)可以拆分成三個子程式包:一個用於格式化(Printf 及其相關函式),一個用於掃描(Scanf),以及一個用於它們之間的共同依賴。

(嘗試在這個程式包上玩這個工具:這是一個有益的練習。下圖顯示瞭解決方案。)

該工具目前不執行程式碼轉換(將宣告移到新程式包,重新命名符號以根據需要匯出它們),但我們希望在未來的版本中新增此功能。

客戶端支援 (Client support)

  • VS Code:使用“Source Action… > Split package P”選單。

本文件的原始碼可以在 golang.org/x/tools/gopls/doc 下找到。