diff --git a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs index 16f8f9d70ba..aa32c698a2b 100644 --- a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs @@ -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::().filter(|lifetime| lifetime.text() == "'_")?; let lifetime_loc = lifetime.lifetime_ident_token()?.text_range(); diff --git a/crates/ide_assists/src/handlers/reorder_fields.rs b/crates/ide_assists/src/handlers/reorder_fields.rs index f6a926042c1..cd4eb7c15e9 100644 --- a/crates/ide_assists/src/handlers/reorder_fields.rs +++ b/crates/ide_assists/src/handlers/reorder_fields.rs @@ -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::() diff --git a/crates/ide_assists/src/handlers/reorder_impl.rs b/crates/ide_assists/src/handlers/reorder_impl.rs index 17d419cee64..d398373c341 100644 --- a/crates/ide_assists/src/handlers/reorder_impl.rs +++ b/crates/ide_assists/src/handlers/reorder_impl.rs @@ -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::()?; let items = impl_ast.assoc_item_list()?; diff --git a/crates/ide_assists/src/handlers/sort_items.rs b/crates/ide_assists/src/handlers/sort_items.rs index 7ceadd06c00..75e501d3dd3 100644 --- a/crates/ide_assists/src/handlers/sort_items.rs +++ b/crates/ide_assists/src/handlers/sort_items.rs @@ -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::() { 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() {} diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index ebf312aa3f8..7ed89ce88a1 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs @@ -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( diff --git a/crates/ide_assists/src/tests/sourcegen.rs b/crates/ide_assists/src/tests/sourcegen.rs index bf29c5e536f..46c71048dd9 100644 --- a/crates/ide_assists/src/tests/sourcegen.rs +++ b/crates/ide_assists/src/tests/sourcegen.rs @@ -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(§ion.before), + reveal_hash_comments(§ion.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
} 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(()) } }