後端工坊 2026 年 10 月 17 日

2026-10-17 — gopls 加入互動式重構,LSP 提案讓語言伺服器能向使用者提問

primary=https://go.dev/blog/interactive-refactoring primary=https://github.com/microsoft/language-server-protocol/issues/1164

gopls 加入互動式重構,LSP 提案讓語言伺服器能向使用者提問

Go Blog(Hongxiang Jiang) · 2026-10-16

gopls 的重構不再只能靠游標位置猜使用者想做什麼:它現在可以在計算編輯內容之前,先彈出對話框詢問參數。這是 Go 團隊與 Dart 團隊合作、向 Language Server Protocol(LSP)提出的新能力(microsoft/language-server-protocol#1164),目前已在 gopls v0.24.0 與 Go 官方 VS Code 擴充套件 v0.56.0 可用。

原本的問題

LSP 裡幾乎所有程式碼轉換都像沒有參數的函式:編輯器一觸發,伺服器就必須立刻算出編輯。唯一的例外是重新命名,因為它需要一個參數(新名稱),協定才為它另開了 PrepareRename RPC。

伺服器只能從游標位置與外圍語法樹推測意圖。推測不出來時只有兩條路:套用一體適用的預設值,或乾脆不提供這個重構。文章明確指出,限制不在 gopls 算不出編輯,而在 LSP 沒有讓伺服器向使用者要資料的機制。

例如「Add struct tags」過去一律產生 camelCase 的 json tag;要 yaml、db 或 snake_case 就得自己改。有些語言擴充套件的作法是把對話框邏輯寫死在單一編輯器裡,但這會把只遵守標準 LSP、用戶端程式碼很少的 Neovim、Emacs 擋在外面,也違背 LSP 讓語言功能與編輯器解耦的初衷。

核心改動

提案建立一個標準機制,讓語言伺服器在計算文字編輯前先收集使用者輸入。文章提到設計是無狀態的表單協定,並且把互動放在 LSP 的 command 層,所以不限於程式碼編輯。完整規格與否決過的替代方案寫在 LSP Interactive Code Actions 設計文件裡,本文未展開。

以 Add struct tags 為例,流程變成:

  • 游標放在 struct 上,選「Add struct tags」。
  • 第一個對話框預填 json,可改成 json,yaml,db 等組合。
  • 第二個對話框選命名慣例:camelCase、snake_case 或 PascalCase。
  • gopls 套用結果。
舊行為新行為(選 json,db 與 snake_case)
type UserProfile struct {
    ID        int64
    FirstName string
}
type UserProfile struct {
    ID        int64  `json:"id" db:"id"`
    FirstName string  `json:"first_name" db:"first_name"`
}

「Remove struct tags」也改為詢問要刪哪些 key,例如只刪 db 而保留 json,不再整批清掉。

實作與進度

「Add methods to X to implement an interface…」自 gopls v0.23.0 起可用:輸入欄位會即時向 gopls 查詢,補全工作區與標準函式庫的型別名稱(文章舉 maphash.Hasher)。若介面有型別參數,會再逐一詢問具體型別,然後產生帶正確 receiver 名稱與實例化簽名的方法 stub,取代過去複製介面再手改,或用外部工具 impl 的做法。

「Move declaration」目前是預覽,文章說排在之後的 gopls 版本。它會跳出檔案選擇器,可選既有的 .go 檔或新路徑,並把宣告連同只有它使用的未匯出輔助宣告一起搬走,同時更新工作區內的引用並整理兩邊的 import。範例中型別 Foo、它的方法 Print 與只被它用到的常數 bar 一起從 package from 搬到 to,無關的 Baz 留在原處。

另外 v0.24.0 附了一個彩蛋:游標放在名為 dragonSlayer 的套件層級變數上,會出現「Slay the dragon」code action。它的用途是給編輯器實作者一個多步驟對話框的自足測試案例。

影響範圍

  • Go 開發者:升級到 gopls v0.24.0 與 vscode-go v0.56.0 才會看到對話框;舊版的 Add struct tags 仍是固定 camelCase json。
  • Neovim、Emacs 使用者:文章說已有概念驗證的用戶端整合,但不是正式發行功能。要用得上,編輯器端必須實作這套表單協定。
  • LSP 用戶端與其他語言伺服器作者:這是仍在討論的提案,不是已定案的規格。要依賴它,應先追蹤 #1164 的設計文件。

文章列出的後續方向包含 Change Signature(golang/go#38028,需要新參數順序與預設引數運算式)、命名衝突時詢問使用者,以及測試與 benchmark 的 profiling 旗標設定。Move Declaration 對應 golang/go#70583,Implement Interface 對應 golang/vscode-go#1547,Modify Struct Tags 對應 golang/vscode-go#2002。

原始來源:Go Blog:Interactive refactoring in gopls、LSP 提案 #1164


End of article
0
Would love your thoughts, please comment.x
()
x