Ruby LSP

Ruby LSP logo

Ruby LSP 是 語言伺服器協定 的 Ruby 實作,用於改進編輯器中的豐富功能。它是更廣泛目標的一部分,旨在為 Ruby 開發人員提供最先進的體驗,使用現代標準實現跨編輯器的功能、文件和除錯。

想討論 Ruby 開發人員體驗嗎?考慮加入公開的 Ruby DX Slack 工作區

目錄

使用方式

搭配 VS Code

如果使用 VS Code,您只需要安裝 Ruby LSP 擴充功能,即可在編輯器中獲得額外功能。請勿手動安裝 ruby-lsp gem。

有關使用和設定擴充功能的詳細資訊,請參閱擴充功能的 README.md

搭配其他編輯器

請參閱 編輯器,以取得社群提供的關於設定 Ruby LSP 的說明,目前包括 Emacs、Neovim、Sublime Text 和 Zed。

可以使用以下方式安裝 gem

gem install ruby-lsp

並且可以透過執行 ruby-lsp 來啟動語言伺服器(不使用 bundle exec,以便正確掛鉤到專案的相依性)。

組合式 Ruby LSP 套件

Ruby LSP 可執行檔會產生一個組合套件,目的是不需要使用者將 ruby-lsp gem 新增至他們的 Gemfile,同時能夠掛鉤到專案相依性。了解更多

相依性相容性

如果專案中存在 RuboCop,Ruby LSP 可以提供更好的體驗。雖然使用它是可選的,但如果您選擇包含 RuboCop,請確保它的版本為 1.4.0 或更高版本。

附加元件

Ruby LSP 提供了一個附加元件系統,允許其他 gem 使用更多的編輯器功能來增強基本功能。這是諸如以下附加元件的運作機制:

此外,某些工具可能會直接包含 Ruby LSP 附加元件,例如:

其他社群驅動的附加元件可以在 rubygems 中找到,方法是搜尋 ruby-lsp 前綴。

有關如何建立附加元件的說明,請參閱附加元件文件

通用功能

請注意,本節中的任何功能都不是 Ruby 特有的;它們適用於所有程式語言。熟悉它們將增強您有效使用編輯器的能力。

如果您正在使用 VS Code,我們建議您參考他們優秀的指南和文件,以了解更多有關編輯器的理念和功能集。

懸停

懸停功能會在游標懸停在目標常數或方法上時,顯示目標常數或方法的註解或文件。

在 VS Code 中,如果您在按住 Command 的同時懸停,它也會傳送 definition 請求來尋找可能的目標來源。如果只找到一個來源(例如,該類別未在多個位置重新開啟),它將顯示目標的原始碼。

跳到定義

跳到定義功能允許使用者導覽至目標常數或方法的定義,無論它們是在您的專案或其相依性中定義的。

在 VS Code 中,此功能可以透過下列其中一種方法觸發:

  • 在目標上按一下滑鼠右鍵,然後選取 跳到定義
  • 將游標放在目標上,然後按 F12
  • Command + 按一下目標

具有一個定義

使用者會直接被帶到原始碼。

具有多個定義

使用者會看到一個下拉式選單,其中包含所有來源,以及側邊的預覽視窗。

完成

當使用者鍵入的文字與某些已索引的元件相符時,完成功能會為使用者提供完成候選項目。這有助於減少輸入完整方法名稱或常數的需求,從而加快程式碼編寫速度。它還允許開發人員發現可用的常數或方法。

只有在知道接收者的型別時,才能提供方法呼叫的完成。例如,當輸入 foo. 時,只有在知道 foo 的型別時,才有可能顯示方法完成候選項目。由於 Ruby LSP 不要求使用者採用型別系統,因此只有在即使沒有註解也能確定型別時,才能使用方法的完成功能(例如:在常值、常數、使用 new 直接實例化的物件上呼叫的方法)。

如果您想要更精確的完成功能,請考慮採用型別系統

簽名輔助

簽名輔助通常會在使用者輸入完方法後立即出現,提供有關方法參數的提示。此功能對於理解預期的參數和提高程式碼的準確性非常寶貴。

程式碼鏡頭

程式碼鏡頭是根據程式碼的上下文自動新增的按鈕。Ruby LSP 支援單元測試的程式碼鏡頭,允許您使用 VS Code 的測試總管執行測試、在終端機中執行測試或啟動除錯工具。

程式碼鏡頭請求需要在編輯器中實作特定的命令才能運作。對於 VS Code,這包含在 Ruby LSP 擴充功能中。如果您使用不同的編輯器,請查看編輯器的文件,了解如何定義所需的命令。

Code lens demo

文件符號

文件符號允許使用者在目前檔案中模糊搜尋宣告。它也用於填寫麵包屑和概要。

Document symbol demo

工作區符號

工作區符號是文件符號的專案範圍版本。它允許使用者在整個專案中模糊搜尋任何宣告。

Workspace symbol demo

文件連結會使神奇的 source 連結可點擊。這用於連結兩個宣告以方便使用。請注意,只有在宣告正上方,而不是程式碼中的任何位置,才會處理連結。

Document link demo

文件醒目提示

文件醒目提示會顯示游標下方實體的出現次數和宣告。

Document highlight demo

摺疊範圍

摺疊範圍允許使用者在相關的原始碼範圍摺疊程式碼。

Folding range demo

語意醒目提示

語意醒目提示消除了語言的歧義,以實現一致的編輯器醒目提示。例如,僅使用 TextMate 文法,就可能混淆沒有接收者或括號的局部變數和方法呼叫,通常會導致不正確的醒目提示。

Ruby LSP 的語意醒目提示策略是傳回盡可能少的權杖,以確保精確的醒目提示。處理大量權杖對於編輯器來說是昂貴的,可能會導致延遲。

語意醒目提示只是告知編輯器檔案中存在哪些類型的權杖。例如,Ruby LSP 會告訴編輯器「這是一個局部變數」或「這是一個方法呼叫」。但是,這並不意味著主題一定會使用該資訊,或者它們支援語意醒目提示。

Ruby 擴充功能包擴充功能包含 Spinel 主題,該主題透過充分利用 Ruby LSP 的所有語意資訊,專為 Ruby 語言量身打造。

如果您希望為其他主題新增更好的 Ruby 支援,請參閱 主題的語意醒目提示文件

Semantic highlighting demo

診斷

診斷是基於程式碼的目前狀態浮現的 linting、錯誤、警告和任何其他類型的資訊。Ruby LSP 原生支援語法錯誤,並且也支援顯示 linting 錯誤。

您可以設定要使用哪些 linters,只要它們具有適用於 Ruby LSP 的整合即可。檢查可用的組態設定

Diagnostic demo

格式化

格式化功能允許在儲存時自動格式化文件,或者如果編輯器支援,也可以手動格式化。

Formatting demo

程式碼動作

快速修復

Ruby LSP 支援透過快速修復來修正違規問題。

Quickfix demo

重構

Ruby LSP 支援一些程式碼重構,例如提取變數、提取方法和切換區塊樣式。

Refactors demo

內嵌提示

內嵌提示會明確地向使用者顯示隱含資訊。目標是讓隱含的行為更容易被發現和看見。

預設情況下,僅顯示隱含的 rescue 提示。VS Code 使用者可以使用以下設定來自訂內嵌提示行為。

{
    // Enable all hints
    "rubyLsp.featuresConfiguration.inlayHint.enableAll": true,
    // Enable implicit rescue (defaults to true)
    "rubyLsp.featuresConfiguration.inlayHint.implicitRescue": true,
    // Enable implicit hash values (omitted hash values)
    "rubyLsp.featuresConfiguration.inlayHint.implicitHashValue": true
  }

若要設定其他編輯器,請參閱初始化選項

Inlay hint demo

輸入時格式化

輸入時格式化會在使用者輸入時將變更套用到程式碼。例如,當斷行時,Ruby LSP 會自動完成 end 標記。

在 VS Code 中,輸入時格式化預設為停用。您可以使用 "editor.formatOnType": true 來啟用它。

On type formatting demo

範圍格式化

範圍格式化允許使用者格式化編輯器中的選取範圍,而無需格式化整個檔案。它也是啟用貼上時格式化功能的功能。

在 VS Code 中,貼上時格式化預設為停用。您可以使用 "editor.formatOnPaste": true 來啟用它。

目前,只有 Syntax Tree 格式化工具支援部分格式化檔案。支援 RuboCop 或 Standard 的範圍格式化需要公開新的 API,以便 Ruby LSP 可以通知格式化工具選取範圍的基本縮排。此外,格式化工具只能套用對文件部分有意義的更正。

Range formatting demo

選取範圍

選取範圍(或智慧型範圍)會根據程式碼的結構展開或縮小選取範圍。在 VS Code 中,可以使用 CTRL + SHIFT + LEFT/RIGHT ARROW 分別觸發展開/縮小。

Selection range demo

顯示語法樹

顯示語法樹會顯示目前 Ruby 文件的抽象語法樹 (AST)。此自訂功能可以顯示整個文件的 AST 或選取範圍的 AST。

此功能不是語言伺服器規範的一部分。它是一個自訂功能,實作於 Ruby LSP 的 VS Code 擴充功能中。其他編輯器可以實作類似的方法來實現相同的功能。

Show syntax tree demo

ERB 支援

Ruby LSP 可以處理 ERB 檔案,並處理檔案中嵌入的 Ruby 和主機語言部分。對於嵌入的 Ruby 部分,Ruby LSP 會回應您在一般 Ruby 檔案中通常看到的所有 Ruby 功能。對於主機語言的功能,例如 HTML,Ruby LSP 會將請求委派給註冊以處理該檔案類型的語言服務。

請求委派尚未正式化為 LSP 規範的一部分。因此,這需要在用戶端(編輯器)端使用自訂程式碼。Ruby LSP VS Code 擴充功能附帶了該自訂實作,但其他編輯器需要實作相同的功能才能支援這些功能。

某些 JavaScript 功能的委派部分起作用。例如,onclick 屬性內的完成功能有時會顯示不正確的候選項。我們認為這可能是一般請求委派的限制,並且我們已經與 VS Code 開啟了討論,以更好地理解它。

ERB features demo

推測類型

推測類型是一項功能,Ruby LSP 會嘗試根據接收者的識別碼來識別接收者的類型。例如

# The receiver identifier here is `user` and so the Ruby LSP will assign to it the `User` type if that class exists
user.name

# Similarly, the receiver identifier here is `post` and so the LSP searches for the `Post` class
@post.like!

此實驗的目標是了解我們是否可以為您已有的程式碼獲得更好的準確性。假設是合理數量的程式碼已經使用了範例中的模式,並且在這些情況下,我們可以獲得更好的結果。

但是,識別碼不是正確類型註解的理想媒介。不可能表達任何複雜的東西,例如聯合、交集或泛型。此外,透過簡單地將變數命名為與其實際類型不符的類型名稱,很容易欺騙類型推測。

pathname = something_that_returns_an_integer
# This will show methods available in `Pathname`, despite the variable being an Integer
pathname.a

我們不建議僅為了獲得更好的準確性而重新命名方法、實例變數或區域變數 - 可讀性應該永遠是第一優先。例如

# It would not be a good idea to name every string "string" for the sake of getting better accuracy.
# Using descriptive names will outweigh the benefits of the more accurate editor experience

# don't
string = something.other_thing

# do
title = something.other_thing
name = foo

也就是說,此功能還可以用於快速探索類別中可用的方法。只需輸入類別的小寫名稱,完成功能即可顯示可用的方法。

# Any class name as an identifier
pathname.a
integer.a
file.a

為了推測類型,Ruby LSP 會先嘗試根據接收者的識別碼和目前的巢狀結構解析常數。如果這樣無法識別任何有效的類型,則會退回以非限定類型名稱的第一個相符項為基礎進行比對。例如

module Admin
  class User
  end

  # Will match to `Admin::User` because the `user` reference is inside the `Admin` namespace
  user.a
end

module Blog
  class User
  end

  # Will match to `Blog::User` because the `user` reference is inside the `Blog` namespace
  user.a
end

# Will match to the first class that has the unqualified name of `User`. This may return `Admin::User` or `Blog::User`
# randomly
user.a

重新命名符號

重新命名允許開發人員重新命名整個專案中游標下實體的所有出現位置。在 VS Code 中,可以透過右鍵單擊要重新命名的實體或在其上按下 F2 來觸發重新命名。您也可以在輸入所需的新名稱後按下 CTRL/CMD + Enter 來預覽將套用的編輯。

Rename demo

尋找參考

尋找參考請求允許使用者查看參考清單或跳到參考位置。請注意,目前僅支援常數,但計劃支援方法、實例變數和區域變數。

References demo

VS Code 功能

以下功能都是為 VS Code 自訂的。

相依性檢視

Ruby LSP 提供自訂的相依性檢視面板,允許使用者瀏覽其專案的相依性。

Dependencies view demo

Rails 產生器整合

Ruby LSP 與 Rails 產生器整合,可以透過 UI 呼叫。所有產生的檔案都會自動開啟並使用專案的格式化設定進行格式化。

Generator demo

除錯用戶端

Ruby LSP 附帶 debug gem 的用戶端。該用戶端允許 程式碼鏡頭等功能,並啟用用於啟動具有視覺除錯器的進程或附加到現有伺服器的啟動組態。

版本管理器整合

當處理具有不同 Ruby 版本的許多專案時,Ruby LSP 需要知道正在使用哪個 Ruby 版本以及 Gem 安裝在哪裡,以便支援自動相依性偵測和索引。

我們支援與以下版本管理器的自訂整合,以便在無需任何使用者操作的情況下自動切換版本

此外,如果自訂整合不足,我們還提供以下跳脫方法

  • custom:定義自訂 shell 指令碼以在任何專案上啟動 Ruby 環境
  • none:不執行任何操作,並依賴 VS Code 繼承的環境

大多數版本管理器都有一些 shell 元件,以便在終端中變更使用者的環境並指向正確的 Ruby 版本。因此,VS Code 擴充功能必須從執行它的 NodeJS 處理程序中叫用使用者的 shell - 否則版本管理器將無法用於整合。

這有時會導致 Ruby 環境啟動問題。例如,某些 shell 外掛程式期望終端設定的變數存在,如果不存在則會失敗。執行擴充功能的 NodeJS 處理程序將不會設定這些變數,因此很可能會失敗。

由於作業系統、shell、外掛程式和版本管理器的不同組合數量,找到這個問題的通用解決方案並不容易。最重要的是,人們以不同的方式設定他們的 shell 環境。例如,某些使用者可能會在 ~/.zshrc 中來源其版本管理器,而其他使用者則會在 ~/.zshenv~/.zprofile 中來源。

如果遇到問題,請記住 shell 設定可能會干擾,請檢查疑難排解,如果列出的解決方案都無效,請回報問題

測試瀏覽器

Ruby LSP 會使用目前檔案的測試來填入 VS Code 的測試瀏覽器檢視。有關其他示範,請參閱程式碼鏡頭

Ruby LSP 有意不索引程式碼庫中的每個單一測試以顯示在測試瀏覽器中。在大型程式碼庫中,嘗試這樣做會導致效能問題、過多的記憶體使用量和瀏覽困難(由於測試數量)。我們可能會在未來重新考慮這一點,但這需要確保它符合我們的效能要求

Test explorer demo

實驗性功能

Ruby LSP 也提供一些實驗性功能,這些功能預設為停用。如果您對這些功能有任何意見回饋,可以在 DX Slack 上告知我們,或透過建立 issue 的方式提出。

祖先層級請求 (Ancestors Hierarchy Request)

祖先層級請求功能旨在提供對 Ruby 程式碼中繼承層級的更好理解。此功能可幫助開發人員追蹤類別和模組的沿襲,使其更容易:

  • 視覺化類別和模組的繼承層級。
  • 快速瀏覽繼承鏈。

為什麼它是實驗性的?

此功能由 Type Hierarchy Supertypes LSP 請求支援。在實作過程中,我們在將其應用於 Ruby 時遇到了一些模糊之處。例如:

  • 列表應該只包含類別 (純繼承鏈),還是應該包含模組 (目前的行為)?
  • 單例類別的繼承鏈應該如何觸發和顯示?
  • 如果一個類別或模組被多次重新開啟,它會在列表中出現多次。在實際應用中,這可能會使列表變得非常長。

我們建立了一個issue,以尋求 LSP 維護者的澄清。我們將根據他們的回應和您的意見回饋調整此功能的設計和行為。

Copilot 聊天參與者

Ruby LSP 包含一個 Copilot 聊天參與者,它具有 Ruby 和 Rails 命令的內建知識,可幫助您有效率地建構這些命令。

Chat participant demo

設定

設定程式碼索引

預設情況下,Ruby LSP 會為目前專案中定義的所有 Ruby 檔案及其所有相依性建立索引,包括預設 gem,但以下情況除外:

  • 僅在 :development 群組下出現的 gem
  • test/**/*.rb 下的所有 Ruby 檔案

此行為可以覆寫和調整。瞭解如何為 VS Code 設定它。

請注意,依賴索引的行為 (例如定義、懸停、完成或工作區符號) 會受到設定變更的影響。

使用 .index.yml 檔案的舊方法已被棄用,並將在未來的版本中移除。

# Exclude files based on a given pattern. Often used to exclude test files or fixtures
excluded_patterns:
  - "**/spec/**/*.rb"

# Include files based on a given pattern. Can be used to index Ruby files that use different extensions
included_patterns:
  - "**/bin/*"

# Exclude gems by name. If a gem is never referenced in the project's code and is only used as a tool, excluding it will
# speed up indexing and reduce the amount of results in features like definition or completion
excluded_gems:
  - rubocop
  - pathname

# Include gems by name. Normally used to include development gems that are excluded by default
included_gems:
  - prism

其他資源


目錄