Allow several samples in "// Assist:" comments.

This commit is contained in:
vsrs 2021-07-31 09:52:02 +03:00
parent 580e5e277a
commit 0088f84c88
6 changed files with 223 additions and 42 deletions

View File

@ -33,9 +33,9 @@ static ASSIST_LABEL: &str = "Introduce named lifetime";
// }
// }
// ```
// FIXME: How can we handle renaming any one of multiple anonymous lifetimes?
// FIXME: should also add support for the case fun(f: &Foo) -> &$0Foo
pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
// FIXME: How can we handle renaming any one of multiple anonymous lifetimes?
// FIXME: should also add support for the case fun(f: &Foo) -> &$0Foo
let lifetime =
ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?;
let lifetime_loc = lifetime.lifetime_ident_token()?.text_range();

View File

@ -20,7 +20,6 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
// struct Foo {foo: i32, bar: i32};
// const test: Foo = Foo {foo: 1, bar: 0}
// ```
//
pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let record = ctx
.find_node_at_offset::<ast::RecordExpr>()

View File

@ -44,7 +44,6 @@ use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};
// fn c() {}
// }
// ```
//
pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?;
let items = impl_ast.assoc_item_list()?;

View File

@ -11,6 +11,77 @@ use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};
// Assist: sort_items
//
// Sorts item members alphabetically: fields, enum variants and methods.
//
// ```
// struct $0Foo { second: u32, first: String }
// ```
// ->
// ```
// struct Foo { first: String, second: u32 }
// ```
// ---
// ```
// trait $0Bar {
// fn second(&self) -> u32;
// fn first(&self) -> String;
// }
// ```
// ->
// ```
// trait Bar {
// fn first(&self) -> String;
// fn second(&self) -> u32;
// }
// ```
// ---
// ```
// struct Baz;
// impl $0Baz {
// fn second(&self) -> u32;
// fn first(&self) -> String;
// }
// ```
// ->
// ```
// struct Baz;
// impl Baz {
// fn first(&self) -> String;
// fn second(&self) -> u32;
// }
// ```
// ---
// There is a difference between sorting enum variants:
//
// ```
// en$0um Animal {
// Dog(String, f64),
// Cat { weight: f64, name: String },
// }
// ```
// ->
// ```
// enum Animal {
// // variants sorted
// Cat { weight: f64, name: String },
// Dog(String, f64),
// }
// ```
// and sorting a single enum struct variant:
//
// ```
// enum Animal {
// Dog(String, f64),
// Cat {$0 weight: f64, name: String },
// }
// ```
// ->
// ```
// enum Animal {
// Dog(String, f64),
// Cat { name: String, weight: f64 }, // Cat fields sorted
// }
// ```
pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
if let Some(trait_ast) = ctx.find_node_at_offset::<ast::Trait>() {
add_sort_methods_assist(acc, trait_ast.assoc_item_list()?)
@ -155,7 +226,7 @@ t$0rait Bar {
check_assist_not_applicable(
sort_items,
r#"
struct Bar;
struct Bar;
$0impl Bar {
}
"#,
@ -221,7 +292,7 @@ t$0rait Bar {
check_assist_not_applicable(
sort_items,
r#"
struct Bar;
struct Bar;
$0impl Bar {
fn a() {}
fn b() {}

View File

@ -1523,6 +1523,98 @@ fn main() {
)
}
#[test]
fn doctest_sort_items() {
check_doc_test(
"sort_items",
r#####"
struct $0Foo { second: u32, first: String }
"#####,
r#####"
struct Foo { first: String, second: u32 }
"#####,
)
}
#[test]
fn doctest_sort_items_1() {
check_doc_test(
"sort_items_1",
r#####"
trait $0Bar {
fn second(&self) -> u32;
fn first(&self) -> String;
}
"#####,
r#####"
trait Bar {
fn first(&self) -> String;
fn second(&self) -> u32;
}
"#####,
)
}
#[test]
fn doctest_sort_items_2() {
check_doc_test(
"sort_items_2",
r#####"
struct Baz;
impl $0Baz {
fn second(&self) -> u32;
fn first(&self) -> String;
}
"#####,
r#####"
struct Baz;
impl Baz {
fn first(&self) -> String;
fn second(&self) -> u32;
}
"#####,
)
}
#[test]
fn doctest_sort_items_3() {
check_doc_test(
"sort_items_3",
r#####"
en$0um Animal {
Dog(String, f64),
Cat { weight: f64, name: String },
}
"#####,
r#####"
enum Animal {
// variants sorted
Cat { weight: f64, name: String },
Dog(String, f64),
}
"#####,
)
}
#[test]
fn doctest_sort_items_4() {
check_doc_test(
"sort_items_4",
r#####"
enum Animal {
Dog(String, f64),
Cat {$0 weight: f64, name: String },
}
"#####,
r#####"
enum Animal {
Dog(String, f64),
Cat { name: String, weight: f64 }, // Cat fields sorted
}
"#####,
)
}
#[test]
fn doctest_split_import() {
check_doc_test(

View File

@ -16,7 +16,9 @@ use super::check_doc_test;
"
.to_string();
for assist in assists.iter() {
let test = format!(
for (idx, section) in assist.sections.iter().enumerate() {
let id = if idx == 0 { assist.id.clone() } else { format!("{}_{}", &assist.id, idx)};
let test = format!(
r######"
#[test]
fn doctest_{}() {{
@ -27,13 +29,14 @@ r#####"
{}"#####)
}}
"######,
assist.id,
assist.id,
reveal_hash_comments(&assist.before),
reveal_hash_comments(&assist.after)
);
buf.push_str(&test)
&id,
&id,
reveal_hash_comments(&section.before),
reveal_hash_comments(&section.after)
);
buf.push_str(&test)
}
}
let buf = sourcegen::add_preamble("sourcegen_assists_docs", sourcegen::reformat(buf));
sourcegen::ensure_file_contents(
@ -55,14 +58,17 @@ r#####"
fs::write(dst, contents).unwrap();
}
}
#[derive(Debug)]struct Section {
doc: String,
before: String,
after: String,
}
#[derive(Debug)]
struct Assist {
id: String,
location: sourcegen::Location,
doc: String,
before: String,
after: String,
sections: Vec<Section>
}
impl Assist {
@ -89,22 +95,28 @@ impl Assist {
"invalid assist id: {:?}",
id
);
let mut lines = block.contents.iter();
let doc = take_until(lines.by_ref(), "```").trim().to_string();
assert!(
doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.'),
"\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n",
id, doc,
);
let before = take_until(lines.by_ref(), "```");
assert_eq!(lines.next().unwrap().as_str(), "->");
assert_eq!(lines.next().unwrap().as_str(), "```");
let after = take_until(lines.by_ref(), "```");
let mut lines = block.contents.iter().peekable();
let location = sourcegen::Location { file: path.to_path_buf(), line: block.line };
acc.push(Assist { id, location, doc, before, after })
let mut assist = Assist { id, location, sections: Vec::new() };
while lines.peek().is_some() {
let doc = take_until(lines.by_ref(), "```").trim().to_string();
assert!(
(doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.')) || assist.sections.len() > 0,
"\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n",
&assist.id, doc,
);
let before = take_until(lines.by_ref(), "```");
assert_eq!(lines.next().unwrap().as_str(), "->");
assert_eq!(lines.next().unwrap().as_str(), "```");
let after = take_until(lines.by_ref(), "```");
assist.sections.push(Section{doc, before, after});
}
acc.push(assist)
}
}
@ -123,13 +135,20 @@ impl Assist {
impl fmt::Display for Assist {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let before = self.before.replace("$0", ""); // Unicode pseudo-graphics bar
let after = self.after.replace("$0", "");
writeln!(
let _ = writeln!(
f,
"[discrete]\n=== `{}`
**Source:** {}
**Source:** {}",
self.id,
self.location,
);
for section in &self.sections {
let before = section.before.replace("$0", ""); // Unicode pseudo-graphics bar
let after = section.after.replace("$0", "");
let _= writeln!(
f,
"
{}
.Before
@ -139,12 +158,13 @@ impl fmt::Display for Assist {
.After
```rust
{}```",
self.id,
self.location,
self.doc,
hide_hash_comments(&before),
hide_hash_comments(&after)
)
section.doc,
hide_hash_comments(&before),
hide_hash_comments(&after)
);
}
Ok(())
}
}