VSCode 使用 rust-analyzer

PrivateRookie發表於2019-08-04

前言

Rust 的 VSCode 官方外掛體驗常常不盡人意,今天逛社群時發現了 rls 2.0 - rust-analyzer,
體驗之後我覺得 rust-analyzer 雖然還有不少瑕疵,但至少比 rls 1.0 要好,希望 Rust 工作組
多投入點精力在提升編輯器體驗吧: )。

安裝

需要 nodejs 10+ 和 npm,可以參考 node.js and npm,不再贅述。
有可能還需要安裝 rust 標準庫

rustup component add rust-src

確保 code 命令在 PATH 環境變數中,並解除安裝 Rust 外掛避免衝突,執行以下命名安裝 rust-analyzer

git clone https://github.com/rust-analyzer/rust-analyzer.git --depth 1
cd rust-analyzer
cargo install-ra

如果安裝沒有出錯,這將會在機器上安裝 rls 和 vscode 外掛。

如果要更新 rust-analyzer,pull 最新程式碼後重跑一次 cargo install-ra 即可。

配置

開啟 VSCode,[[ctrl + ,]] 搜尋 rust 即可看到 rust-analyzer 所有配置。
常用配置有:

{
"rust-analyzer.enableCargoWatchOnStartup": "true", // 開啟專案時自動開啟 cargo watch
"rust-analyzer.highlightingOn": true, // 覆蓋內建語法高亮
"rust-analyzer.lruCapacity": 1000, // 分析器最大快取深度
}

更多配置參考 settings

特性

workspace 符號查詢 [[ctrl + t]]

除了 VSCode 自帶的模糊搜尋外,rust-analyzer 還透過 #* 增強模糊搜尋功能。使用快捷鍵 [[ctrl + t]] 開啟符號搜尋,在搜尋框輸入以下內容,忽略開頭的 # 號符

  • Foo 在當前工作區搜尋名稱為 Foo 的型別
  • foo# 在當前工作區搜尋名為 foo 的函式
  • Foo* 在所有依賴,包括 stdlib 中搜尋名稱為 Foo 的型別
  • foo#** 在所有依賴中搜尋名為 foo 的函式

當前文件符號搜尋 [[ctrl + shift + o]]

提供了完整的符號搜尋能力,詳細使用請參考 VSCode 文件。PS: 我最喜歡的一個特性是在 @ 之後新增 : 就可以對所有符號進行分類,整齊又美觀。

輸入輔助

雖然文件中說 rust-analyzer 擁有如下特性,但在我的 VSCode 似乎不起作用
rust-analyzer 會在輸入特定字元提供輔助:

  • 輸入 let = 時如果 = 跟著一個已知表示式會嘗試自動新增 ;
  • 在註釋中輸入時如果換行會自動在行首新增註釋符號
  • 在鏈式呼叫中輸入 . 會自動縮排

程式碼輔助

rust-analyzer 新增幾個有用的程式碼提示或輔助。

結構體程式碼輔助

如果把游標移動到結構體名稱上,使用 ctrl + . 可以看到出現了 add #[derive]add impl 兩個提示,顧名思義 add #[derive] 是為結構體新增
deriveadd impl 則會自動新增 impl 語句塊。

自動新增缺失 trait 成員方法

加入有一個 trait 和 結構體

trait Foo {
    fn foo(&self);
    fn bar(&self);
    fn baz(&self);
}

struct S;

如果這個結構體要實現這個 trait 你可以在輸入 impl Foo for S {} 看到左邊的輔助提示,按 [[ctrl + .]] 看到 add missing impl members,回車確定後
會自動填充如下程式碼

impl Foo for s {
    fn foo(&self) { unimplemented!() }
    fn bar(&self) { unimplemented!() }
    fn baz(&self) { unimplemented!() }
}

個人覺得這個功能還是非常方便的,特別是實現一些不熟悉的 trait 時不必翻 trait 定義。

路徑匯入

假如有一段這樣的程式碼

impl std::fmt::Debug for Foo {
}

游標移動到 Debug 後使用程式碼輔助會幫你如下重構程式碼

use std::fmt::Debug;

impl Debug for Foo {
}

改變函式可見性

當游標移動到私有函式名時可以透過程式碼輔助快速地將函式改為 pubpub (crate)

填充模式匹配分支

假設有如下列舉體

enum A {
    As,
    Bs,
    Cs(String),
    Ds(String, String),
    Es{x: usize, y: usize}
}

fn main() {
    let a = A::As;
    match a {}
}

在輸入 match a {} 後程式碼輔助會自動幫你展開匹配,如:

fn main() {
    let a = A::As;
    match <|>a {
        A::As => (),
        A::Bs => (),
        A::Cs(_) => (),
        A::Ds(_, _) => (),
        A::Es{x, y} => (),
    }
}

也是一個非常實用的功能

除了上述輔助特性,rust-analyzer 還有更多程式碼輔助特性,有興趣可以參考 Code Actions(Assists)

Magic 填充

這個功能給我的感覺就像使用 IPython 的 %command 魔術命令一樣,酷炫又實用。
假設有如下函式:

foo() -> bool { true }

呼叫函式後跟隨 .if 接著按 [[tab]] 會自動展開為 if foo() {}。所有可展開表示式如下:

  • expr.if->if expr {}
  • expr.match->match expr {}
  • expr.while->while expr {}
  • expr.ref->&expr
  • expr.refm->&mut expr
  • expr.not->!expr
  • expr.dbg->dbg!(expr)

除此之外在表示式內還有如下 snippets

  • pd->println!("{:?}")
  • ppd->println!("{:#?}")

在模組中還有提供了測試方法的 snippets

  • tfn->#[test] fn f(){}

總結:

新的 rls 比原來的 rls 提供了更多貼心的功能,但一些基本功能反而沒有原來的 rls 好,也有可能是缺少 snippets 的原因,
剛開始用還挺不習慣的,但熟悉了只要感覺還是不錯。


本文參考為 rust-analyzer 文件: rust-analyzer-Github

本作品採用《CC 協議》,轉載必須註明作者和本文連結
多少事,從來急。天地轉,光陰迫。

相關文章