mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
472 lines
8.3 KiB
Markdown
472 lines
8.3 KiB
Markdown
This documents is an index of features that rust-analyzer language server
|
|
provides. Shortcuts are for the default VS Code layout. If there's no shortcut,
|
|
you can use <kbd>Ctrl+Shift+P</kbd> to search for the corresponding action.
|
|
|
|
### Workspace Symbol <kbd>ctrl+t</kbd>
|
|
|
|
Uses fuzzy-search to find types, modules and function by name across your
|
|
project and dependencies. This **the** most useful feature, which improves code
|
|
navigation tremendously. It mostly works on top of the built-in LSP
|
|
functionality, however `#` and `*` symbols can be used to narrow down the
|
|
search. Specifically,
|
|
|
|
- `Foo` searches for `Foo` type in the current workspace
|
|
- `foo#` searches for `foo` function in the current workspace
|
|
- `Foo*` searches for `Foo` type among dependencies, including `stdlib`
|
|
- `foo#*` searches for `foo` function among dependencies.
|
|
|
|
That is, `#` switches from "types" to all symbols, `*` switches from the current
|
|
workspace to dependencies.
|
|
|
|
### Document Symbol <kbd>ctrl+shift+o</kbd>
|
|
|
|
Provides a tree of the symbols defined in the file. Can be used to
|
|
|
|
* fuzzy search symbol in a file (super useful)
|
|
* draw breadcrumbs to describe the context around the cursor
|
|
* draw outline of the file
|
|
|
|
### On Typing Assists
|
|
|
|
Some features trigger on typing certain characters:
|
|
|
|
- typing `let =` tries to smartly add `;` if `=` is followed by an existing expression.
|
|
- Enter inside comments automatically inserts `///`
|
|
- typing `.` in a chain method call auto-indents
|
|
|
|
### Extend Selection
|
|
|
|
Extends the current selection to the encompassing syntactic construct
|
|
(expression, statement, item, module, etc). It works with multiple cursors. This
|
|
is a relatively new feature of LSP:
|
|
https://github.com/Microsoft/language-server-protocol/issues/613, check your
|
|
editor's LSP library to see if this feature is supported.
|
|
|
|
### Go to Definition
|
|
|
|
Navigates to the definition of an identifier.
|
|
|
|
### Go to Implementation
|
|
|
|
Navigates to the impl block of structs, enums or traits. Also implemented as a code lens.
|
|
|
|
### Go to Type Defintion
|
|
|
|
Navigates to the type of an identifier.
|
|
|
|
### Commands <kbd>ctrl+shift+p</kbd>
|
|
|
|
#### Run
|
|
|
|
Shows popup suggesting to run a test/benchmark/binary **at the current cursor
|
|
location**. Super useful for repeatedly running just a single test. Do bind this
|
|
to a shortcut!
|
|
|
|
#### Parent Module
|
|
|
|
Navigates to the parent module of the current module.
|
|
|
|
#### Matching Brace
|
|
|
|
If the cursor is on any brace (`<>(){}[]`) which is a part of a brace-pair,
|
|
moves cursor to the matching brace. It uses the actual parser to determine
|
|
braces, so it won't confuse generics with comparisons.
|
|
|
|
#### Join Lines
|
|
|
|
Join selected lines into one, smartly fixing up whitespace and trailing commas.
|
|
|
|
#### Show Syntax Tree
|
|
|
|
Shows the parse tree of the current file. It exists mostly for debugging
|
|
rust-analyzer itself.
|
|
|
|
#### Status
|
|
|
|
Shows internal statistic about memory usage of rust-analyzer
|
|
|
|
#### Run garbage collection
|
|
|
|
Manually triggers GC
|
|
|
|
#### Start Cargo Watch
|
|
|
|
Start `cargo watch` for live error highlighting. Will prompt to install if it's not already installed.
|
|
|
|
#### Stop Cargo Watch
|
|
|
|
Stop `cargo watch`
|
|
|
|
### Code Actions (Assists)
|
|
|
|
These are triggered in a particular context via light bulb. We use custom code on
|
|
the VS Code side to be able to position cursor. `<|>` signifies cursor
|
|
|
|
- Add `#[derive]`
|
|
|
|
```rust
|
|
// before:
|
|
struct Foo {
|
|
<|>x: i32
|
|
}
|
|
// after:
|
|
#[derive(<|>)]
|
|
struct Foo {
|
|
x: i32
|
|
}
|
|
```
|
|
|
|
- Add `impl`
|
|
|
|
```rust
|
|
// before:
|
|
struct Foo<'a, T: Debug> {
|
|
<|>t: T
|
|
}
|
|
// after:
|
|
struct Foo<'a, T: Debug> {
|
|
t: T
|
|
}
|
|
|
|
impl<'a, T: Debug> Foo<'a, T> {
|
|
<|>
|
|
}
|
|
```
|
|
|
|
- Add missing `impl` members
|
|
|
|
```rust
|
|
// before:
|
|
trait Foo {
|
|
fn foo(&self);
|
|
fn bar(&self);
|
|
fn baz(&self);
|
|
}
|
|
|
|
struct S;
|
|
|
|
impl Foo for S {
|
|
fn bar(&self) {}
|
|
<|>
|
|
}
|
|
|
|
// after:
|
|
trait Foo {
|
|
fn foo(&self);
|
|
fn bar(&self);
|
|
fn baz(&self);
|
|
}
|
|
|
|
struct S;
|
|
|
|
impl Foo for S {
|
|
fn bar(&self) {}
|
|
fn foo(&self) { unimplemented!() }
|
|
fn baz(&self) { unimplemented!() }<|>
|
|
}
|
|
```
|
|
|
|
- Import path
|
|
|
|
```rust
|
|
// before:
|
|
impl std::fmt::Debug<|> for Foo {
|
|
}
|
|
|
|
// after:
|
|
use std::fmt::Debug;
|
|
|
|
impl Debug<|> for Foo {
|
|
}
|
|
```
|
|
|
|
- Change Visibility
|
|
|
|
```rust
|
|
// before:
|
|
<|>fn foo() {}
|
|
|
|
// after:
|
|
<|>pub(crate) fn foo() {}
|
|
|
|
// after:
|
|
<|>pub fn foo() {}
|
|
```
|
|
|
|
- Fill match arms
|
|
|
|
```rust
|
|
// before:
|
|
enum A {
|
|
As,
|
|
Bs,
|
|
Cs(String),
|
|
Ds(String, String),
|
|
Es{x: usize, y: usize}
|
|
}
|
|
|
|
fn main() {
|
|
let a = A::As;
|
|
match a<|> {}
|
|
}
|
|
|
|
// after:
|
|
enum A {
|
|
As,
|
|
Bs,
|
|
Cs(String),
|
|
Ds(String, String),
|
|
Es{x: usize, y: usize}
|
|
}
|
|
|
|
fn main() {
|
|
let a = A::As;
|
|
match <|>a {
|
|
A::As => (),
|
|
A::Bs => (),
|
|
A::Cs(_) => (),
|
|
A::Ds(_, _) => (),
|
|
A::Es{x, y} => (),
|
|
}
|
|
}
|
|
```
|
|
|
|
- Fill struct fields
|
|
|
|
```rust
|
|
// before:
|
|
struct S<'a, D> {
|
|
a: u32,
|
|
b: String,
|
|
c: (i32, i32),
|
|
d: D,
|
|
r: &'a str,
|
|
}
|
|
|
|
fn main() {
|
|
let s = S<|> {}
|
|
}
|
|
|
|
// after:
|
|
struct S<'a, D> {
|
|
a: u32,
|
|
b: String,
|
|
c: (i32, i32),
|
|
d: D,
|
|
r: &'a str,
|
|
}
|
|
|
|
fn main() {
|
|
let s = <|>S {
|
|
a: (),
|
|
b: (),
|
|
c: (),
|
|
d: (),
|
|
r: (),
|
|
}
|
|
}
|
|
```
|
|
|
|
- Flip `,`
|
|
|
|
```rust
|
|
// before:
|
|
fn foo(x: usize,<|> dim: (usize, usize)) {}
|
|
// after:
|
|
fn foo(dim: (usize, usize), x: usize) {}
|
|
```
|
|
|
|
- Introduce variable:
|
|
|
|
```rust
|
|
// before:
|
|
fn foo() {
|
|
foo(<|>1 + 1<|>);
|
|
}
|
|
|
|
// after:
|
|
fn foo() {
|
|
let var_name = 1 + 1;
|
|
foo(var_name);
|
|
}
|
|
```
|
|
|
|
- Inline local variable:
|
|
|
|
```rust
|
|
// before:
|
|
fn foo() {
|
|
let a<|> = 1 + 1;
|
|
let b = a * 10;
|
|
}
|
|
|
|
// after:
|
|
fn foo() {
|
|
let b = (1 + 1) * 10;
|
|
}
|
|
```
|
|
|
|
- Remove `dbg!`
|
|
|
|
```rust
|
|
// before:
|
|
fn foo(n: usize) {
|
|
if let Some(_) = dbg!(n.<|>checked_sub(4)) {
|
|
// ...
|
|
}
|
|
}
|
|
|
|
// after:
|
|
fn foo(n: usize) {
|
|
if let Some(_) = n.<|>checked_sub(4) {
|
|
// ...
|
|
}
|
|
}
|
|
```
|
|
|
|
- Replace if-let with match:
|
|
|
|
```rust
|
|
// before:
|
|
impl VariantData {
|
|
pub fn is_struct(&self) -> bool {
|
|
if <|>let VariantData::Struct(..) = *self {
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
// after:
|
|
impl VariantData {
|
|
pub fn is_struct(&self) -> bool {
|
|
<|>match *self {
|
|
VariantData::Struct(..) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- Split import
|
|
|
|
```rust
|
|
// before:
|
|
use algo:<|>:visitor::{Visitor, visit};
|
|
// after:
|
|
use algo::{<|>visitor::{Visitor, visit}};
|
|
```
|
|
|
|
- Flip binary expression
|
|
|
|
```rust
|
|
// before:
|
|
fn foo() {
|
|
if 1 <<|> 2 {
|
|
println!("Who would have thought?");
|
|
}
|
|
}
|
|
// after:
|
|
fn foo() {
|
|
if 2 ><|> 1 {
|
|
println!("Who would have thought?");
|
|
}
|
|
}
|
|
```
|
|
|
|
- Add explicit type
|
|
|
|
```rust
|
|
// before:
|
|
fn foo() {
|
|
let t<|> = (&2, Some(1));
|
|
}
|
|
// after:
|
|
fn foo() {
|
|
let t<|>: (&i32, Option<i32>) = (&2, Some(1));
|
|
}
|
|
```
|
|
|
|
- Move guard expression to match arm body
|
|
```rust
|
|
// before:
|
|
fn f() {
|
|
match x {
|
|
<|>y @ 4 | y @ 5 if y > 5 => true,
|
|
_ => false
|
|
}
|
|
}
|
|
// after:
|
|
fn f() {
|
|
match x {
|
|
y @ 4 | y @ 5 => if y > 5 { <|>true },
|
|
_ => false
|
|
}
|
|
}
|
|
```
|
|
|
|
- Move if condition to match arm guard
|
|
```rust
|
|
// before:
|
|
fn f() {
|
|
let mut t = 'a';
|
|
let chars = "abcd";
|
|
match t {
|
|
'\r' => if chars.clone().next().is_some() {
|
|
t = 'e';<|>
|
|
false
|
|
},
|
|
_ => true
|
|
}
|
|
}
|
|
|
|
// after:
|
|
fn f() {
|
|
let mut t = 'a';
|
|
let chars = "abcd";
|
|
match t {
|
|
'\r' <|>if chars.clone().next().is_some() => {
|
|
t = 'e';
|
|
false
|
|
},
|
|
_ => true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Magic Completions
|
|
|
|
In addition to usual reference completion, rust-analyzer provides some ✨magic✨
|
|
completions as well:
|
|
|
|
Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
|
|
is placed at the appropriate position. Even though `if` is easy to type, you
|
|
still want to complete it, to get ` { }` for free! `return` is inserted with a
|
|
space or `;` depending on the return type of the function.
|
|
|
|
When completing a function call, `()` are automatically inserted. If function
|
|
takes arguments, cursor is positioned inside the parenthesis.
|
|
|
|
There are postifx completions, which can be triggerd by typing something like
|
|
`foo().if`. The word after `.` determines postifx completion, possible variants are:
|
|
|
|
- `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)`
|
|
|
|
There also snippet completions:
|
|
|
|
#### Inside Expressions
|
|
|
|
- `pd` -> `println!("{:?}")`
|
|
- `ppd` -> `println!("{:#?}")`
|
|
|
|
#### Inside Modules
|
|
|
|
- `tfn` -> `#[test] fn f(){}`
|
|
|