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
  8<!--
  9TBD: Polish Rust Docs. Zed is a good rust editor, good Rust docs make it look like we care about Rust (we do!)
 10TBD: Users may not know what inlayHints, don't start there.
 11TBD: Provide explicit examples not just `....`
 12-->
 13
 14## Inlay Hints
 15
 16The following configuration can be used to enable inlay hints for rust:
 17
 18```json
 19"inlayHints": {
 20  "maxLength": null,
 21  "lifetimeElisionHints": {
 22  "useParameterNames": true,
 23    "enable": "skip_trivial"
 24  },
 25  "closureReturnTypeHints": {
 26    "enable": "always"
 27  }
 28}
 29```
 30
 31to make the language server send back inlay hints when Zed has them enabled in the settings.
 32
 33Use
 34
 35```json
 36"lsp": {
 37  "rust-analyzer": {
 38    "initialization_options": {
 39      ....
 40    }
 41  }
 42}
 43```
 44
 45to override these settings.
 46
 47See [Inlay Hints](https://rust-analyzer.github.io/manual.html#inlay-hints) in the Rust Analyzer Manual for more information.
 48
 49## Target directory
 50
 51The `rust-analyzer` target directory can be set in `initialization_options`:
 52
 53```json
 54{
 55  "lsp": {
 56    "rust-analyzer": {
 57      "initialization_options": {
 58        "rust": {
 59          "analyzerTargetDir": true
 60        }
 61      }
 62    }
 63  }
 64}
 65```
 66
 67A `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`.
 68
 69## Binary
 70
 71You can configure which `rust-analyzer` binary Zed should use.
 72
 73To use a binary in a custom location, add the following to your `settings.json`:
 74
 75```json
 76{
 77  "lsp": {
 78    "rust-analyzer": {
 79      "binary": {
 80        "path": "/Users/example/bin/rust-analyzer",
 81        "args": []
 82      }
 83    }
 84  }
 85}
 86```
 87
 88To use a binary that is on your `$PATH`, add the following to your `settings.json`:
 89
 90```json
 91{
 92  "lsp": {
 93    "rust-analyzer": {
 94      "binary": {
 95        "path_lookup": true
 96      }
 97    }
 98  }
 99}
100```
101
102## More server configuration
103
104<!--
105TBD: Is it possible to specify RUSTFLAGS? https://github.com/zed-industries/zed/issues/14334
106-->
107
108Rust-analyzer [manual](https://rust-analyzer.github.io/manual.html) describes various features and configuration options for rust-analyzer language server.
109Rust-analyzer in Zed runs with the default parameters.
110
111### Large projects and performance
112
113One of the main caveats that might cause extensive resource usage on large projects, is the combination of the following features:
114
115```
116rust-analyzer.checkOnSave (default: true)
117    Run the check command for diagnostics on save.
118```
119
120```
121rust-analyzer.check.workspace (default: true)
122    Whether --workspace should be passed to cargo check. If false, -p <package> will be passed instead.
123```
124
125```
126rust-analyzer.cargo.allTargets (default: true)
127    Pass --all-targets to cargo invocation
128```
129
130Which 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).
131
132While that works fine on small projects, it does not scale well.
133
134The 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.
135
136Check 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/manual.html#diagnostics).
137
138Consider more `rust-analyzer.cargo.` and `rust-analyzer.check.` and `rust-analyzer.diagnostics.` settings from the manual for more fine-grained configuration.
139Here's a snippet for Zed settings.json (the language server will restart automatically after the `lsp.rust-analyzer` section is edited and saved):
140
141```json5
142"lsp": {
143    "rust-analyzer": {
144        "initialization_options": {
145            // get more cargo-less diagnostics from rust-analyzer,
146            // which might include false-positives (those can be turned off by their names)
147            "diagnostics": {
148                "experimental": {
149                    "enable": true
150                }
151            },
152            // To disable the checking entirely
153            // (ignores all cargo and check settings below)
154            "checkOnSave": false,
155            // To check the `lib` target only.
156            "cargo": {
157                "allTargets": false
158            },
159            // Use `-p` instead of `--workspace` for cargo check
160            "check": {
161              "workspace": false
162            }
163        }
164    }
165}
166```
167
168### Snippets
169
170There's a way get custom completion items from rust-analyzer, that will transform the code according to the snippet body:
171
172```json
173"lsp": {
174    "rust-analyzer": {
175        "initialization_options": {
176            "completion": {
177                "snippets": {
178                    "custom": {
179                        "Arc::new": {
180                            "postfix": "arc",
181                            "body": ["Arc::new(${receiver})"],
182                            "requires": "std::sync::Arc",
183                            "scope": "expr"
184                        },
185                        "Some": {
186                            "postfix": "some",
187                            "body": ["Some(${receiver})"],
188                            "scope": "expr"
189                        },
190                        "Ok": {
191                            "postfix": "ok",
192                            "body": ["Ok(${receiver})"],
193                            "scope": "expr"
194                        },
195                        "Rc::new": {
196                            "postfix": "rc",
197                            "body": ["Rc::new(${receiver})"],
198                            "requires": "std::rc::Rc",
199                            "scope": "expr"
200                        },
201                        "Box::pin": {
202                            "postfix": "boxpin",
203                            "body": ["Box::pin(${receiver})"],
204                            "requires": "std::boxed::Box",
205                            "scope": "expr"
206                        },
207                        "vec!": {
208                            "postfix": "vec",
209                            "body": ["vec![${receiver}]"],
210                            "description": "vec![]",
211                            "scope": "expr"
212                        }
213                    }
214                }
215            }
216        }
217    }
218}
219```