1# Rust
2
3Rust support is available natively in Zed.
4
5- Tree-sitter: [tree-sitter/tree-sitter-rust](https://github.com/tree-sitter/tree-sitter-rust)
6- Language Server: [rust-lang/rust-analyzer](https://github.com/rust-lang/rust-analyzer)
7- Debug Adapter: [CodeLLDB](https://github.com/vadimcn/codelldb) (primary), [GDB](https://sourceware.org/gdb/) (secondary, not available on Apple silicon)
8
9<!--
10TBD: Polish Rust Docs. Zed is a good rust editor, good Rust docs make it look like we care about Rust (we do!)
11TBD: Users may not know what inlayHints, don't start there.
12TBD: Provide explicit examples not just `....`
13-->
14
15## Inlay Hints
16
17The following configuration can be used to change the inlay hint settings for `rust-analyzer` in Rust:
18
19```json
20{
21 "lsp": {
22 "rust-analyzer": {
23 "initialization_options": {
24 "inlayHints": {
25 "maxLength": null,
26 "lifetimeElisionHints": {
27 "enable": "skip_trivial",
28 "useParameterNames": true
29 },
30 "closureReturnTypeHints": {
31 "enable": "always"
32 }
33 }
34 }
35 }
36 }
37}
38```
39
40See [Inlay Hints](https://rust-analyzer.github.io/book/features.html#inlay-hints) in the Rust Analyzer Manual for more information.
41
42## Target directory
43
44The `rust-analyzer` target directory can be set in `initialization_options`:
45
46```json
47{
48 "lsp": {
49 "rust-analyzer": {
50 "initialization_options": {
51 "rust": {
52 "analyzerTargetDir": true
53 }
54 }
55 }
56 }
57}
58```
59
60A `true` setting will set the target directory to `target/rust-analyzer`. You can set a custom directory with a string like `"target/analyzer"` instead of `true`.
61
62## Binary
63
64You can configure which `rust-analyzer` binary Zed should use.
65
66By default, Zed will try to find a `rust-analyzer` in your `$PATH` and try to use that. If that binary successfully executes `rust-analyzer --help`, it's used. Otherwise, Zed will fall back to installing its own `rust-analyzer` version and using that.
67
68If you want to disable Zed looking for a `rust-analyzer` binary, you can set `ignore_system_version` to `true` in your `settings.json`:
69
70```json
71{
72 "lsp": {
73 "rust-analyzer": {
74 "binary": {
75 "ignore_system_version": true
76 }
77 }
78 }
79}
80```
81
82If you want to use a binary in a custom location, you can specify a `path` and optional `arguments`:
83
84```json
85{
86 "lsp": {
87 "rust-analyzer": {
88 "binary": {
89 "path": "/Users/example/bin/rust-analyzer",
90 "arguments": []
91 }
92 }
93 }
94}
95```
96
97This `"path"` has to be an absolute path.
98
99## Alternate Targets
100
101If want rust-analyzer to provide diagnostics for a target other than you current platform (e.g. for windows when running on macOS) you can use the following Zed lsp settings:
102
103```json
104{
105 "lsp": {
106 "rust-analyzer": {
107 "initialization_options": {
108 "cargo": {
109 "target": "x86_64-pc-windows-msvc"
110 }
111 }
112 }
113 }
114}
115```
116
117If you are using `rustup` and you can find a list of available target triples (`aarch64-apple-darwin`, `x86_64-unknown-linux-gnu`, etc) by running:
118
119```sh
120rustup target list --installed
121```
122
123## LSP tasks
124
125Zed provides tasks using tree-sitter, but rust-analyzer has an LSP extension method for querying file-related tasks via LSP.
126This is enabled by default and can be configured as
127
128```json
129"lsp": {
130 "rust-analyzer": {
131 "enable_lsp_tasks": true,
132 }
133}
134```
135
136## Manual Cargo Diagnostics fetch
137
138By default, rust-analyzer has `checkOnSave: true` enabled, which causes every buffer save to trigger a `cargo check --workspace --all-targets` command.
139If disabled with `checkOnSave: false` (see the example of the server configuration json above), it's still possible to fetch the diagnostics manually, with the `editor: run/clear/cancel flycheck` commands in Rust files to refresh cargo diagnostics; the project diagnostics editor will also refresh cargo diagnostics with `editor: run flycheck` command when the setting is enabled.
140
141## More server configuration
142
143<!--
144TBD: Is it possible to specify RUSTFLAGS? https://github.com/zed-industries/zed/issues/14334
145-->
146
147Rust-analyzer [manual](https://rust-analyzer.github.io/book/) describes various features and configuration options for rust-analyzer language server.
148Rust-analyzer in Zed runs with the default parameters.
149
150### Large projects and performance
151
152One of the main caveats that might cause extensive resource usage on large projects, is the combination of the following features:
153
154```
155rust-analyzer.checkOnSave (default: true)
156 Run the check command for diagnostics on save.
157```
158
159```
160rust-analyzer.check.workspace (default: true)
161 Whether --workspace should be passed to cargo check. If false, -p <package> will be passed instead.
162```
163
164```
165rust-analyzer.cargo.allTargets (default: true)
166 Pass --all-targets to cargo invocation
167```
168
169Which would mean that every time Zed saves, a `cargo check --workspace --all-targets` command is run, checking the entire project (workspace), lib, doc, test, bin, bench and [other targets](https://doc.rust-lang.org/cargo/reference/cargo-targets.html).
170
171While that works fine on small projects, it does not scale well.
172
173The alternatives would be to use [tasks](../tasks.md), as Zed already provides a `cargo check --workspace --all-targets` task and the ability to cmd/ctrl-click on the terminal output to navigate to the error, and limit or turn off the check on save feature entirely.
174
175Check on save feature is responsible for returning part of the diagnostics based on cargo check output, so turning it off will limit rust-analyzer with its own [diagnostics](https://rust-analyzer.github.io/book/diagnostics.html).
176
177Consider more `rust-analyzer.cargo.` and `rust-analyzer.check.` and `rust-analyzer.diagnostics.` settings from the manual for more fine-grained configuration.
178Here's a snippet for Zed settings.json (the language server will restart automatically after the `lsp.rust-analyzer` section is edited and saved):
179
180```json
181{
182 "lsp": {
183 "rust-analyzer": {
184 "initialization_options": {
185 // get more cargo-less diagnostics from rust-analyzer,
186 // which might include false-positives (those can be turned off by their names)
187 "diagnostics": {
188 "experimental": {
189 "enable": true
190 }
191 },
192 // To disable the checking entirely
193 // (ignores all cargo and check settings below)
194 "checkOnSave": false,
195 // To check the `lib` target only.
196 "cargo": {
197 "allTargets": false
198 },
199 // Use `-p` instead of `--workspace` for cargo check
200 "check": {
201 "workspace": false
202 }
203 }
204 }
205 }
206}
207```
208
209### Multi-project workspaces
210
211If you want rust-analyzer to analyze multiple Rust projects in the same folder that are not listed in `[members]` in the Cargo workspace,
212you can list them in `linkedProjects` in the local project settings:
213
214```json
215{
216 "lsp": {
217 "rust-analyzer": {
218 "initialization_options": {
219 "linkedProjects": ["./path/to/a/Cargo.toml", "./path/to/b/Cargo.toml"]
220 }
221 }
222 }
223}
224```
225
226### Snippets
227
228There's a way get custom completion items from rust-analyzer, that will transform the code according to the snippet body:
229
230```json
231{
232 "lsp": {
233 "rust-analyzer": {
234 "initialization_options": {
235 "completion": {
236 "snippets": {
237 "custom": {
238 "Arc::new": {
239 "postfix": "arc",
240 "body": ["Arc::new(${receiver})"],
241 "requires": "std::sync::Arc",
242 "scope": "expr"
243 },
244 "Some": {
245 "postfix": "some",
246 "body": ["Some(${receiver})"],
247 "scope": "expr"
248 },
249 "Ok": {
250 "postfix": "ok",
251 "body": ["Ok(${receiver})"],
252 "scope": "expr"
253 },
254 "Rc::new": {
255 "postfix": "rc",
256 "body": ["Rc::new(${receiver})"],
257 "requires": "std::rc::Rc",
258 "scope": "expr"
259 },
260 "Box::pin": {
261 "postfix": "boxpin",
262 "body": ["Box::pin(${receiver})"],
263 "requires": "std::boxed::Box",
264 "scope": "expr"
265 },
266 "vec!": {
267 "postfix": "vec",
268 "body": ["vec![${receiver}]"],
269 "description": "vec![]",
270 "scope": "expr"
271 }
272 }
273 }
274 }
275 }
276 }
277 }
278}
279```
280
281## Debugging
282
283Zed supports debugging Rust binaries and tests out of the box. Run {#action debugger::Start} ({#kb debugger::Start}) to launch one of these preconfigured debug tasks.
284
285For more control, you can add debug configurations to `.zed/debug.json`. See the examples below.
286
287### Build binary then debug
288
289```json
290[
291 {
292 "label": "Build & Debug native binary",
293 "build": {
294 "command": "cargo",
295 "args": ["build"]
296 },
297 "program": "$ZED_WORKTREE_ROOT/target/debug/binary",
298 // sourceLanguages is required for CodeLLDB (not GDB) when using Rust
299 "sourceLanguages": ["rust"],
300 "request": "launch",
301 "adapter": "CodeLLDB"
302 }
303]
304```
305
306### Automatically locate a debug target based on build command
307
308When you use `cargo build` or `cargo test` as the build command, Zed can infer the path to the output binary.
309
310```json
311[
312 {
313 "label": "Build & Debug native binary",
314 "adapter": "CodeLLDB",
315 "build": {
316 "command": "cargo",
317 "args": ["build"]
318 },
319 // sourceLanguages is required for CodeLLDB (not GDB) when using Rust
320 "sourceLanguages": ["rust"]
321 }
322]
323```