rust.md

  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.
139For lager projects this might introduce excessive wait times, so a more fine-grained triggering could be enabled by altering the
140
141```json
142"diagnostics": {
143  "cargo": {
144    // When enabled, Zed disables rust-analyzer's check on save and starts to query
145    // Cargo diagnostics separately.
146    "fetch_cargo_diagnostics": false
147  }
148}
149```
150
151default settings.
152
153This will stop rust-analyzer from running `cargo check ...` on save, yet still allow to run
154`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.
155
156## More server configuration
157
158<!--
159TBD: Is it possible to specify RUSTFLAGS? https://github.com/zed-industries/zed/issues/14334
160-->
161
162Rust-analyzer [manual](https://rust-analyzer.github.io/book/) describes various features and configuration options for rust-analyzer language server.
163Rust-analyzer in Zed runs with the default parameters.
164
165### Large projects and performance
166
167One of the main caveats that might cause extensive resource usage on large projects, is the combination of the following features:
168
169```
170rust-analyzer.checkOnSave (default: true)
171    Run the check command for diagnostics on save.
172```
173
174```
175rust-analyzer.check.workspace (default: true)
176    Whether --workspace should be passed to cargo check. If false, -p <package> will be passed instead.
177```
178
179```
180rust-analyzer.cargo.allTargets (default: true)
181    Pass --all-targets to cargo invocation
182```
183
184Which 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).
185
186While that works fine on small projects, it does not scale well.
187
188The 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.
189
190Check 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).
191
192Consider more `rust-analyzer.cargo.` and `rust-analyzer.check.` and `rust-analyzer.diagnostics.` settings from the manual for more fine-grained configuration.
193Here's a snippet for Zed settings.json (the language server will restart automatically after the `lsp.rust-analyzer` section is edited and saved):
194
195```json
196{
197  "lsp": {
198    "rust-analyzer": {
199      "initialization_options": {
200        // get more cargo-less diagnostics from rust-analyzer,
201        // which might include false-positives (those can be turned off by their names)
202        "diagnostics": {
203          "experimental": {
204            "enable": true
205          }
206        },
207        // To disable the checking entirely
208        // (ignores all cargo and check settings below)
209        "checkOnSave": false,
210        // To check the `lib` target only.
211        "cargo": {
212          "allTargets": false
213        },
214        // Use `-p` instead of `--workspace` for cargo check
215        "check": {
216          "workspace": false
217        }
218      }
219    }
220  }
221}
222```
223
224### Multi-project workspaces
225
226If you want rust-analyzer to analyze multiple Rust projects in the same folder that are not listed in `[members]` in the Cargo workspace,
227you can list them in `linkedProjects` in the local project settings:
228
229```json
230{
231  "lsp": {
232    "rust-analyzer": {
233      "initialization_options": {
234        "linkedProjects": ["./path/to/a/Cargo.toml", "./path/to/b/Cargo.toml"]
235      }
236    }
237  }
238}
239```
240
241### Snippets
242
243There's a way get custom completion items from rust-analyzer, that will transform the code according to the snippet body:
244
245```json
246{
247  "lsp": {
248    "rust-analyzer": {
249      "initialization_options": {
250        "completion": {
251          "snippets": {
252            "custom": {
253              "Arc::new": {
254                "postfix": "arc",
255                "body": ["Arc::new(${receiver})"],
256                "requires": "std::sync::Arc",
257                "scope": "expr"
258              },
259              "Some": {
260                "postfix": "some",
261                "body": ["Some(${receiver})"],
262                "scope": "expr"
263              },
264              "Ok": {
265                "postfix": "ok",
266                "body": ["Ok(${receiver})"],
267                "scope": "expr"
268              },
269              "Rc::new": {
270                "postfix": "rc",
271                "body": ["Rc::new(${receiver})"],
272                "requires": "std::rc::Rc",
273                "scope": "expr"
274              },
275              "Box::pin": {
276                "postfix": "boxpin",
277                "body": ["Box::pin(${receiver})"],
278                "requires": "std::boxed::Box",
279                "scope": "expr"
280              },
281              "vec!": {
282                "postfix": "vec",
283                "body": ["vec![${receiver}]"],
284                "description": "vec![]",
285                "scope": "expr"
286              }
287            }
288          }
289        }
290      }
291    }
292  }
293}
294```
295
296## Debugging
297
298Zed 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.
299
300For more control, you can add debug configurations to `.zed/debug.json`. See the examples below.
301
302### Build binary then debug
303
304```json
305[
306  {
307    "label": "Build & Debug native binary",
308    "build": {
309      "command": "cargo",
310      "args": ["build"]
311    },
312    "program": "$ZED_WORKTREE_ROOT/target/debug/binary",
313    // sourceLanguages is required for CodeLLDB (not GDB) when using Rust
314    "sourceLanguages": ["rust"],
315    "request": "launch",
316    "adapter": "CodeLLDB"
317  }
318]
319```
320
321### Automatically locate a debug target based on build command
322
323When you use `cargo build` or `cargo test` as the build command, Zed can infer the path to the output binary.
324
325```json
326[
327  {
328    "label": "Build & Debug native binary",
329    "adapter": "CodeLLDB",
330    "build": {
331      "command": "cargo",
332      "args": ["build"]
333    },
334    // sourceLanguages is required for CodeLLDB (not GDB) when using Rust
335    "sourceLanguages": ["rust"]
336  }
337]
338```