Move assists documentation into the manual

This commit is contained in:
Aleksey Kladov
2020-05-31 15:02:12 +02:00
parent 5a2f4548e5
commit 46292c7cec
6 changed files with 366 additions and 189 deletions
@@ -1,18 +1,16 @@
# Assists
Cursor position or selection is signified by `┃` character.
## `add_custom_impl`
[discrete]
=== `add_custom_impl`
Adds impl block for derived trait.
.Before
```rust
// BEFORE
#[derive(Deb┃ug, Display)]
struct S;
```
// AFTER
.After
```rust
#[derive(Display)]
struct S;
@@ -21,18 +19,22 @@ impl Debug for S {
}
```
## `add_derive`
[discrete]
=== `add_derive`
Adds a new `#[derive()]` clause to a struct or enum.
.Before
```rust
// BEFORE
struct Point {
x: u32,
y: u32,┃
}
```
// AFTER
.After
```rust
#[derive($0)]
struct Point {
x: u32,
@@ -40,31 +42,39 @@ struct Point {
}
```
## `add_explicit_type`
[discrete]
=== `add_explicit_type`
Specify type for a let binding.
.Before
```rust
// BEFORE
fn main() {
let x┃ = 92;
}
```
// AFTER
.After
```rust
fn main() {
let x: i32 = 92;
}
```
## `add_from_impl_for_enum`
[discrete]
=== `add_from_impl_for_enum`
Adds a From impl for an enum variant with one tuple field.
.Before
```rust
// BEFORE
enum A { ┃One(u32) }
```
// AFTER
.After
```rust
enum A { One(u32) }
impl From<u32> for A {
@@ -74,20 +84,24 @@ impl From<u32> for A {
}
```
## `add_function`
[discrete]
=== `add_function`
Adds a stub function with a signature matching the function under the cursor.
.Before
```rust
// BEFORE
struct Baz;
fn baz() -> Baz { Baz }
fn foo() {
bar┃("", baz());
}
```
// AFTER
.After
```rust
struct Baz;
fn baz() -> Baz { Baz }
fn foo() {
@@ -100,33 +114,41 @@ fn bar(arg: &str, baz: Baz) {
```
## `add_hash`
[discrete]
=== `add_hash`
Adds a hash to a raw string literal.
.Before
```rust
// BEFORE
fn main() {
r#"Hello,┃ World!"#;
}
```
// AFTER
.After
```rust
fn main() {
r##"Hello, World!"##;
}
```
## `add_impl`
[discrete]
=== `add_impl`
Adds a new inherent impl for a type.
.Before
```rust
// BEFORE
struct Ctx<T: Clone> {
data: T,┃
}
```
// AFTER
.After
```rust
struct Ctx<T: Clone> {
data: T,
}
@@ -136,12 +158,14 @@ impl<T: Clone> Ctx<T> {
}
```
## `add_impl_default_members`
[discrete]
=== `add_impl_default_members`
Adds scaffold for overriding default impl members.
.Before
```rust
// BEFORE
trait Trait {
Type X;
fn foo(&self);
@@ -153,8 +177,10 @@ impl Trait for () {
fn foo(&self) {}┃
}
```
// AFTER
.After
```rust
trait Trait {
Type X;
fn foo(&self);
@@ -169,12 +195,14 @@ impl Trait for () {
}
```
## `add_impl_missing_members`
[discrete]
=== `add_impl_missing_members`
Adds scaffold for required impl members.
.Before
```rust
// BEFORE
trait Trait<T> {
Type X;
fn foo(&self) -> T;
@@ -184,8 +212,10 @@ trait Trait<T> {
impl Trait<u32> for () {┃
}
```
// AFTER
.After
```rust
trait Trait<T> {
Type X;
fn foo(&self) -> T;
@@ -200,17 +230,21 @@ impl Trait<u32> for () {
}
```
## `add_new`
[discrete]
=== `add_new`
Adds a new inherent impl for a type.
.Before
```rust
// BEFORE
struct Ctx<T: Clone> {
data: T,┃
}
```
// AFTER
.After
```rust
struct Ctx<T: Clone> {
data: T,
}
@@ -221,25 +255,31 @@ impl<T: Clone> Ctx<T> {
```
## `add_turbo_fish`
[discrete]
=== `add_turbo_fish`
Adds `::<_>` to a call of a generic method or function.
.Before
```rust
// BEFORE
fn make<T>() -> T { todo!() }
fn main() {
let x = make┃();
}
```
// AFTER
.After
```rust
fn make<T>() -> T { todo!() }
fn main() {
let x = make::<${0:_}>();
}
```
## `apply_demorgan`
[discrete]
=== `apply_demorgan`
Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
This transforms expressions of the form `!l || !r` into `!(l && r)`.
@@ -247,29 +287,35 @@ This also works with `&&`. This assist can only be applied with the cursor
on either `||` or `&&`, with both operands being a negation of some kind.
This means something of the form `!x` or `x != y`.
.Before
```rust
// BEFORE
fn main() {
if x != 4 ||┃ !y {}
}
```
// AFTER
.After
```rust
fn main() {
if !(x == 4 && y) {}
}
```
## `auto_import`
[discrete]
=== `auto_import`
If the name is unresolved, provides all possible imports for it.
.Before
```rust
// BEFORE
fn main() {
let map = HashMap┃::new();
}
```
// AFTER
.After
```rust
use std::collections::HashMap;
fn main() {
@@ -277,12 +323,14 @@ fn main() {
}
```
## `change_lifetime_anon_to_named`
[discrete]
=== `change_lifetime_anon_to_named`
Change an anonymous lifetime to a named lifetime.
.Before
```rust
// BEFORE
impl Cursor<'_┃> {
fn node(self) -> &SyntaxNode {
match self {
@@ -290,8 +338,10 @@ impl Cursor<'_┃> {
}
}
}
```
// AFTER
.After
```rust
impl<'a> Cursor<'a> {
fn node(self) -> &SyntaxNode {
match self {
@@ -301,44 +351,56 @@ impl<'a> Cursor<'a> {
}
```
## `change_return_type_to_result`
[discrete]
=== `change_return_type_to_result`
Change the function's return type to Result.
.Before
```rust
// BEFORE
fn foo() -> i32┃ { 42i32 }
```
// AFTER
.After
```rust
fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
```
## `change_visibility`
[discrete]
=== `change_visibility`
Adds or changes existing visibility specifier.
.Before
```rust
// BEFORE
┃fn frobnicate() {}
```
// AFTER
.After
```rust
pub(crate) fn frobnicate() {}
```
## `convert_to_guarded_return`
[discrete]
=== `convert_to_guarded_return`
Replace a large conditional with a guarded return.
.Before
```rust
// BEFORE
fn main() {
┃if cond {
foo();
bar();
}
}
```
// AFTER
.After
```rust
fn main() {
if !cond {
return;
@@ -348,12 +410,14 @@ fn main() {
}
```
## `fill_match_arms`
[discrete]
=== `fill_match_arms`
Adds missing clauses to a `match` expression.
.Before
```rust
// BEFORE
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -361,8 +425,10 @@ fn handle(action: Action) {
}
}
```
// AFTER
.After
```rust
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -373,20 +439,24 @@ fn handle(action: Action) {
}
```
## `fix_visibility`
[discrete]
=== `fix_visibility`
Makes inaccessible item public.
.Before
```rust
// BEFORE
mod m {
fn frobnicate() {}
}
fn main() {
m::frobnicate┃() {}
}
```
// AFTER
.After
```rust
mod m {
$0pub(crate) fn frobnicate() {}
}
@@ -395,154 +465,192 @@ fn main() {
}
```
## `flip_binexpr`
[discrete]
=== `flip_binexpr`
Flips operands of a binary expression.
.Before
```rust
// BEFORE
fn main() {
let _ = 90 +┃ 2;
}
```
// AFTER
.After
```rust
fn main() {
let _ = 2 + 90;
}
```
## `flip_comma`
[discrete]
=== `flip_comma`
Flips two comma-separated items.
.Before
```rust
// BEFORE
fn main() {
((1, 2),┃ (3, 4));
}
```
// AFTER
.After
```rust
fn main() {
((3, 4), (1, 2));
}
```
## `flip_trait_bound`
[discrete]
=== `flip_trait_bound`
Flips two trait bounds.
.Before
```rust
// BEFORE
fn foo<T: Clone +┃ Copy>() { }
```
// AFTER
.After
```rust
fn foo<T: Copy + Clone>() { }
```
## `inline_local_variable`
[discrete]
=== `inline_local_variable`
Inlines local variable.
.Before
```rust
// BEFORE
fn main() {
let x┃ = 1 + 2;
x * 4;
}
```
// AFTER
.After
```rust
fn main() {
(1 + 2) * 4;
}
```
## `introduce_variable`
[discrete]
=== `introduce_variable`
Extracts subexpression into a variable.
.Before
```rust
// BEFORE
fn main() {
┃(1 + 2)┃ * 4;
}
```
// AFTER
.After
```rust
fn main() {
let $0var_name = (1 + 2);
var_name * 4;
}
```
## `invert_if`
[discrete]
=== `invert_if`
Apply invert_if
This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
This also works with `!=`. This assist can only be applied with the cursor
on `if`.
.Before
```rust
// BEFORE
fn main() {
if┃ !y { A } else { B }
}
```
// AFTER
.After
```rust
fn main() {
if y { B } else { A }
}
```
## `make_raw_string`
[discrete]
=== `make_raw_string`
Adds `r#` to a plain string literal.
.Before
```rust
// BEFORE
fn main() {
"Hello,┃ World!";
}
```
// AFTER
.After
```rust
fn main() {
r#"Hello, World!"#;
}
```
## `make_usual_string`
[discrete]
=== `make_usual_string`
Turns a raw string into a plain string.
.Before
```rust
// BEFORE
fn main() {
r#"Hello,┃ "World!""#;
}
```
// AFTER
.After
```rust
fn main() {
"Hello, \"World!\"";
}
```
## `merge_imports`
[discrete]
=== `merge_imports`
Merges two imports with a common prefix.
.Before
```rust
// BEFORE
use std::┃fmt::Formatter;
use std::io;
```
// AFTER
.After
```rust
use std::{fmt::Formatter, io};
```
## `merge_match_arms`
[discrete]
=== `merge_match_arms`
Merges identical match arms.
.Before
```rust
// BEFORE
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -551,8 +659,10 @@ fn handle(action: Action) {
Action::Stop => foo(),
}
}
```
// AFTER
.After
```rust
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -562,12 +672,14 @@ fn handle(action: Action) {
}
```
## `move_arm_cond_to_match_guard`
[discrete]
=== `move_arm_cond_to_match_guard`
Moves if expression from match arm body into a guard.
.Before
```rust
// BEFORE
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -576,8 +688,10 @@ fn handle(action: Action) {
_ => (),
}
}
```
// AFTER
.After
```rust
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -588,28 +702,34 @@ fn handle(action: Action) {
}
```
## `move_bounds_to_where_clause`
[discrete]
=== `move_bounds_to_where_clause`
Moves inline type bounds to a where clause.
.Before
```rust
// BEFORE
fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U {
f(x)
}
```
// AFTER
.After
```rust
fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
f(x)
}
```
## `move_guard_to_arm_body`
[discrete]
=== `move_guard_to_arm_body`
Moves match guard into match arm body.
.Before
```rust
// BEFORE
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -618,8 +738,10 @@ fn handle(action: Action) {
_ => (),
}
}
```
// AFTER
.After
```rust
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -630,75 +752,93 @@ fn handle(action: Action) {
}
```
## `remove_dbg`
[discrete]
=== `remove_dbg`
Removes `dbg!()` macro call.
.Before
```rust
// BEFORE
fn main() {
┃dbg!(92);
}
```
// AFTER
.After
```rust
fn main() {
92;
}
```
## `remove_hash`
[discrete]
=== `remove_hash`
Removes a hash from a raw string literal.
.Before
```rust
// BEFORE
fn main() {
r#"Hello,┃ World!"#;
}
```
// AFTER
.After
```rust
fn main() {
r"Hello, World!";
}
```
## `remove_mut`
[discrete]
=== `remove_mut`
Removes the `mut` keyword.
.Before
```rust
// BEFORE
impl Walrus {
fn feed(&mut┃ self, amount: u32) {}
}
```
// AFTER
.After
```rust
impl Walrus {
fn feed(&self, amount: u32) {}
}
```
## `reorder_fields`
[discrete]
=== `reorder_fields`
Reorder the fields of record literals and record patterns in the same order as in
the definition.
.Before
```rust
// BEFORE
struct Foo {foo: i32, bar: i32};
const test: Foo = ┃Foo {bar: 0, foo: 1}
```
// AFTER
.After
```rust
struct Foo {foo: i32, bar: i32};
const test: Foo = Foo {foo: 1, bar: 0}
```
## `replace_if_let_with_match`
[discrete]
=== `replace_if_let_with_match`
Replaces `if let` with an else branch with a `match` expression.
.Before
```rust
// BEFORE
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -708,8 +848,10 @@ fn handle(action: Action) {
bar()
}
}
```
// AFTER
.After
```rust
enum Action { Move { distance: u32 }, Stop }
fn handle(action: Action) {
@@ -720,20 +862,24 @@ fn handle(action: Action) {
}
```
## `replace_let_with_if_let`
[discrete]
=== `replace_let_with_if_let`
Replaces `let` with an `if-let`.
.Before
```rust
// BEFORE
fn main(action: Action) {
┃let x = compute();
}
fn compute() -> Option<i32> { None }
```
// AFTER
.After
```rust
fn main(action: Action) {
if let Some(x) = compute() {
@@ -743,33 +889,41 @@ fn main(action: Action) {
fn compute() -> Option<i32> { None }
```
## `replace_qualified_name_with_use`
[discrete]
=== `replace_qualified_name_with_use`
Adds a use statement for a given fully-qualified name.
.Before
```rust
// BEFORE
fn process(map: std::collections::┃HashMap<String, String>) {}
```
// AFTER
.After
```rust
use std::collections::HashMap;
fn process(map: HashMap<String, String>) {}
```
## `replace_unwrap_with_match`
[discrete]
=== `replace_unwrap_with_match`
Replaces `unwrap` a `match` expression. Works for Result and Option.
.Before
```rust
// BEFORE
enum Result<T, E> { Ok(T), Err(E) }
fn main() {
let x: Result<i32, i32> = Result::Ok(92);
let y = x.┃unwrap();
}
```
// AFTER
.After
```rust
enum Result<T, E> { Ok(T), Err(E) }
fn main() {
let x: Result<i32, i32> = Result::Ok(92);
@@ -780,31 +934,39 @@ fn main() {
}
```
## `split_import`
[discrete]
=== `split_import`
Wraps the tail of import into braces.
.Before
```rust
// BEFORE
use std::┃collections::HashMap;
```
// AFTER
.After
```rust
use std::{collections::HashMap};
```
## `unwrap_block`
[discrete]
=== `unwrap_block`
This assist removes if...else, for, while and loop control statements to just keep the body.
.Before
```rust
// BEFORE
fn foo() {
if true {┃
println!("foo");
}
}
```
// AFTER
.After
```rust
fn foo() {
println!("foo");
}
+2 -1
View File
@@ -278,5 +278,6 @@ include::./generated_features.adoc[]
Assists, or code actions, are small local refactorings, available in a particular context.
They are usually triggered by a shortcut or by clicking a light bulb icon in the editor.
Cursor position or selection is signified by `┃` character.
See [assists.md](./assists.md) for the list of available assists.
include::./generated_assists.adoc[]
+30 -3
View File
@@ -10,9 +10,12 @@
mod gen_assists_docs;
mod gen_feature_docs;
use std::{mem, path::Path};
use std::{
fmt, mem,
path::{Path, PathBuf},
};
use crate::{not_bash::fs2, Result};
use crate::{not_bash::fs2, project_root, Result};
pub use self::{
gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs,
@@ -29,7 +32,6 @@
const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers";
const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs";
const ASSISTS_DOCS: &str = "docs/user/assists.md";
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Mode {
@@ -107,3 +109,28 @@ fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lines: bool) ->
}
res
}
#[derive(Debug)]
struct Location {
file: PathBuf,
}
impl Location {
fn new(file: PathBuf) -> Self {
Self { file }
}
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let path = self.file.strip_prefix(&project_root()).unwrap().display().to_string();
let path = path.replace('\\', "/");
let name = self.file.file_name().unwrap();
write!(
f,
"https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]",
path,
name.to_str().unwrap()
)
}
}
+36 -35
View File
@@ -1,22 +1,28 @@
//! Generates `assists.md` documentation.
use std::{fs, path::Path};
use std::{fmt, fs, path::Path};
use crate::{
codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode},
project_root, rust_files, Result,
};
pub fn generate_assists_docs(mode: Mode) -> Result<()> {
let assists = Assist::collect()?;
generate_tests(&assists, mode)?;
generate_docs(&assists, mode)?;
let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
let contents = contents.trim().to_string() + "\n";
let dst = project_root().join("docs/user/generated_assists.adoc");
codegen::update(&dst, &contents, mode)?;
Ok(())
}
#[derive(Debug)]
struct Assist {
id: String,
location: Location,
doc: String,
before: String,
after: String,
@@ -58,7 +64,8 @@ fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
assert_eq!(lines.next().unwrap().as_str(), "->");
assert_eq!(lines.next().unwrap().as_str(), "```");
let after = take_until(lines.by_ref(), "```");
acc.push(Assist { id, doc, before, after })
let location = Location::new(path.to_path_buf());
acc.push(Assist { id, location, doc, before, after })
}
fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String {
@@ -76,6 +83,31 @@ fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> Stri
}
}
impl fmt::Display for Assist {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let before = self.before.replace("<|>", ""); // Unicode pseudo-graphics bar
let after = self.after.replace("<|>", "");
writeln!(
f,
"[discrete]\n=== `{}`
{}
.Before
```rust
{}```
.After
```rust
{}```",
self.id,
self.doc,
hide_hash_comments(&before),
hide_hash_comments(&after)
)
}
}
fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> {
let mut buf = String::from("use super::check_doc_test;\n");
@@ -103,37 +135,6 @@ fn doctest_{}() {{
codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode)
}
fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> {
let mut buf = String::from(
"# Assists\n\nCursor position or selection is signified by `┃` character.\n\n",
);
for assist in assists {
let before = assist.before.replace("<|>", ""); // Unicode pseudo-graphics bar
let after = assist.after.replace("<|>", "");
let docs = format!(
"
## `{}`
{}
```rust
// BEFORE
{}
// AFTER
{}```
",
assist.id,
assist.doc,
hide_hash_comments(&before),
hide_hash_comments(&after)
);
buf.push_str(&docs);
}
codegen::update(&project_root().join(codegen::ASSISTS_DOCS), &buf, mode)
}
fn hide_hash_comments(text: &str) -> String {
text.split('\n') // want final newline
.filter(|&it| !(it.starts_with("# ") || it == "#"))
+4 -18
View File
@@ -3,7 +3,7 @@
use std::{fmt, fs, path::PathBuf};
use crate::{
codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode},
project_root, rust_files, Result,
};
@@ -19,7 +19,7 @@ pub fn generate_feature_docs(mode: Mode) -> Result<()> {
#[derive(Debug)]
struct Feature {
id: String,
path: PathBuf,
location: Location,
doc: String,
}
@@ -40,7 +40,7 @@ fn collect_file(acc: &mut Vec<Feature>, path: PathBuf) -> Result<()> {
let id = block.id;
assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id);
let doc = block.contents.join("\n");
acc.push(Feature { id, path: path.clone(), doc })
acc.push(Feature { id, location: Location::new(path.clone()), doc })
}
Ok(())
@@ -69,20 +69,6 @@ fn is_valid_feature_name(feature: &str) -> bool {
impl fmt::Display for Feature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "=== {}", self.id)?;
let path = self.path.strip_prefix(&project_root()).unwrap().display().to_string();
let path = path.replace('\\', "/");
let name = self.path.file_name().unwrap();
//FIXME: generate line number as well
writeln!(
f,
"**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]",
path,
name.to_str().unwrap(),
)?;
writeln!(f, "{}", self.doc)?;
Ok(())
writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc)
}
}
+1 -1
View File
@@ -191,7 +191,7 @@ pub fn run_release(dry_run: bool) -> Result<()> {
let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
fs2::write(&path, &contents)?;
for &adoc in ["manual.adoc", "generated_features.adoc"].iter() {
for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
let src = project_root().join("./docs/user/").join(adoc);
let dst = website_root.join(adoc);
fs2::copy(src, dst)?;