第107章 Zed 编辑器 Rust 语言支持详解
Zed 原生支持 Rust。
- Tree-sitter:tree-sitter/tree-sitter-rust
- Language Server:rust-lang/rust-analyzer
- Debug Adapter:CodeLLDB(主要),GDB(次要,不适用于 Apple silicon 芯片)
嵌入提示
可以使用以下配置来更改 Rust 中 rust-analyzer 的嵌入提示设置:
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
"inlayHints": {
"maxLength": null,
"lifetimeElisionHints": {
"enable": "skip_trivial",
"useParameterNames": true
},
"closureReturnTypeHints": {
"enable": "always"
}
}
}
}
}
}
更多信息请参见 Rust Analyzer 手册中的嵌入提示章节。
目标目录
可以通过 initialization_options 设置 rust-analyzer 的目标目录:
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
"rust": {
"analyzerTargetDir": true
}
}
}
}
}
设置 true 会将目标目录设为 target/rust-analyzer。也可以将 true 替换为类似 "target/analyzer" 的字符串以指定自定义目录。
二进制文件
可以配置 Zed 应使用的 rust-analyzer 二进制文件。
默认情况下,Zed 会尝试在 $PATH 中查找并使用 rust-analyzer。如果该二进制文件成功执行了 rust-analyzer --help,则直接使用它。否则,Zed 会回退到安装其自带的稳定版 rust-analyzer 并使用该版本。
如果不想安装预发布版的 rust-analyzer,而是想用稳定版,可以在 settings.json 中把 pre_release 设为 true 来指示 Zed 这样做:
{
"lsp": {
"rust-analyzer": {
"fetch": {
"pre_release": true
}
}
}
}
如果不想让 Zed 查找 rust-analyzer 二进制文件,可以在 settings.json 中把 ignore_system_version 设为 true:
{
"lsp": {
"rust-analyzer": {
"binary": {
"ignore_system_version": true
}
}
}
}
如果想使用自定义位置的二进制文件,可以指定 path 和可选的 arguments:
{
"lsp": {
"rust-analyzer": {
"binary": {
"path": "/Users/example/bin/rust-analyzer",
"arguments": []
}
}
}
}
这个 "path" 必须是绝对路径。
其他目标
如果希望 rust-analyzer 为当前平台以外的目标(例如在 macOS 上运行时提供 Windows 的目标)提供诊断信息,可以使用以下 Zed LSP 设置:
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
"cargo": {
"target": "x86_64-pc-windows-msvc"
}
}
}
}
}
如果正在使用 rustup,可以通过运行以下命令来查找可用目标三元组(如 aarch64-apple-darwin、x86_64-unknown-linux-gnu 等)的列表:
rustup target list --installed
LSP 任务
Zed 通过 tree-sitter 提供任务,但 rust-analyzer 有一个 LSP 扩展方法,可通过 LSP 查询与文件相关的任务。 此功能默认启用,配置方式如下:
"lsp": {
"rust-analyzer": {
"enable_lsp_tasks": true,
}
}
手动获取 Cargo 诊断信息
默认情况下,rust-analyzer 开启了 checkOnSave: true,每次保存缓冲区时都会触发一次 cargo check --workspace --all-targets 命令。
如果通过 checkOnSave: false 禁用该功能(参见上文服务端配置 JSON 示例),仍可手动获取诊断信息:在 Rust 文件中使用 editor: run/clear/cancel flycheck 命令刷新 cargo 诊断;启用相关设置后,项目诊断编辑器也会通过 {#action editor::RunFlycheck} 命令刷新 cargo 诊断。
更多服务端配置
rust-analyzer 的手册介绍了该语言服务器的各种功能和配置选项。Zed 中的 rust-analyzer 以默认参数运行。
大型项目与性能
在大型项目中,以下几个配置项组合在一起,可能会造成大量资源消耗:
rust-analyzer.checkOnSave(默认:true)
保存时运行 check 命令获取诊断信息。
rust-analyzer.check.workspace(默认:true)
是否向 cargo check 传入 --workspace 参数。若为 false,则改传 -p <package>。
rust-analyzer.cargo.allTargets(默认:true)
在 cargo 调用时传入 --all-targets 参数
这意味着每次在 Zed 中保存时,都会运行一次 cargo check --workspace --all-targets,检查整个项目(workspace)的 lib、doc、test、bin、bench 以及其他 target。
这对小项目没什么问题,但在大项目上扩展性较差。
替代方案是使用任务(tasks)——Zed 已经内置了 cargo check --workspace --all-targets 任务,支持 cmd/ctrl+点击终端输出中的错误信息直接跳转——同时可以限制或彻底关闭保存时检查功能。
保存时检查功能负责返回基于 cargo check 输出的部分诊断信息,关闭后 rust-analyzer 将只提供其自身的诊断。
你还可以查阅手册中更详细的 rust-analyzer.cargo.、rust-analyzer.check. 和 rust-analyzer.diagnostics. 设置,以便进行更精细的配置。
下面是 Zed 的 settings.json 配置片段(编辑并保存 lsp.rust-analyzer 部分后,语言服务器会自动重启):
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
// 从 rust-analyzer 获取更多无 cargo 依赖的诊断信息,
// 其中可能包含误报(可通过名称单独关闭)
"diagnostics": {
"experimental": {
"enable": true
}
},
// 若要完全禁用检查
// (忽略下方所有 cargo 和 check 设置)
"checkOnSave": false,
// 仅检查 `lib` 目标。
"cargo": {
"allTargets": false
},
// cargo check 使用 `-p` 而非 `--workspace`
"check": {
"workspace": false
}
}
}
}
}
多项目工作区
如果你希望 rust-analyzer 分析同一文件夹下的多个 Rust 项目,但这些项目并未列在 Cargo 工作区的 [members] 中,
你可以在本地项目设置的 linkedProjects 中列出它们:
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
"linkedProjects": ["./path/to/a/Cargo.toml", "./path/to/b/Cargo.toml"]
}
}
}
}
代码片段
rust-analyzer 提供了一种获取自定义补全项的方法,补全内容会按照代码片段主体对代码进行转换:
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
"completion": {
"snippets": {
"custom": {
"Arc::new": {
"postfix": "arc",
"body": ["Arc::new(${receiver})"],
"requires": "std::sync::Arc",
"scope": "expr"
},
"Some": {
"postfix": "some",
"body": ["Some(${receiver})"],
"scope": "expr"
},
"Ok": {
"postfix": "ok",
"body": ["Ok(${receiver})"],
"scope": "expr"
},
"Rc::new": {
"postfix": "rc",
"body": ["Rc::new(${receiver})"],
"requires": "std::rc::Rc",
"scope": "expr"
},
"Box::pin": {
"postfix": "boxpin",
"body": ["Box::pin(${receiver})"],
"requires": "std::boxed::Box",
"scope": "expr"
},
"vec!": {
"postfix": "vec",
"body": ["vec![${receiver}]"],
"description": "vec![]",
"scope": "expr"
}
}
}
}
}
}
}
}
调试
Zed 通过 CodeLLDB 和 GDB 开箱即用地支持调试 Rust 二进制文件和测试。运行 {#action debugger::Start}({#kb debugger::Start})可启动其中一个预设的调试任务。
如需更多控制权,你可以在 .zed/debug.json 中添加调试配置。参见下方示例。
先构建二进制再调试
[
{
"label": "Build & Debug native binary",
"build": {
"command": "cargo",
"args": ["build"]
},
"program": "$ZED_WORKTREE_ROOT/target/debug/binary",
// 使用 Rust 时 CodeLLDB(非 GDB)需要设置 sourceLanguages
"sourceLanguages": ["rust"],
"request": "launch",
"adapter": "CodeLLDB"
}
]
根据构建命令自动定位调试目标
如果你用 cargo build 或 cargo test 作为构建命令,Zed 可以自动推断输出二进制的路径。
[
{
"label": "Build & Debug native binary",
"adapter": "CodeLLDB",
"build": {
"command": "cargo",
"args": ["build"]
},
// 使用 Rust 时 CodeLLDB(非 GDB)需要设置 sourceLanguages
"sourceLanguages": ["rust"]
}
]