mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 01:38:13 +00:00
Sort trait and impl methods
This commit is contained in:
parent
29506b5a26
commit
643f3931f7
4 changed files with 164 additions and 13 deletions
|
@ -8,7 +8,7 @@ use syntax::{
|
|||
ted, AstNode,
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists, utils::get_methods};
|
||||
|
||||
// Assist: reorder_impl
|
||||
//
|
||||
|
@ -76,7 +76,7 @@ pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
|
|||
let target = items.syntax().text_range();
|
||||
acc.add(
|
||||
AssistId("reorder_impl", AssistKind::RefactorRewrite),
|
||||
"Sort methods",
|
||||
"Sort methods by trait definition",
|
||||
target,
|
||||
|builder| {
|
||||
let methods = methods.into_iter().map(|fn_| builder.make_mut(fn_)).collect::<Vec<_>>();
|
||||
|
@ -111,17 +111,6 @@ fn trait_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<
|
|||
}
|
||||
}
|
||||
|
||||
fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
|
||||
items
|
||||
.assoc_items()
|
||||
.flat_map(|i| match i {
|
||||
ast::AssocItem::Fn(f) => Some(f),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|f| f.name().is_some())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
|
|
149
crates/ide_assists/src/handlers/sort_items.rs
Normal file
149
crates/ide_assists/src/handlers/sort_items.rs
Normal file
|
@ -0,0 +1,149 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use hir::known::Option;
|
||||
use itertools::Itertools;
|
||||
|
||||
use syntax::{
|
||||
ast::{self, NameOwner},
|
||||
ted, AstNode,
|
||||
};
|
||||
|
||||
use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};
|
||||
|
||||
// Assist: sort_items
|
||||
//
|
||||
pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
if let Some(trait_ast) = ctx.find_node_at_offset::<ast::Trait>() {
|
||||
sort_methods_assist(acc, trait_ast.assoc_item_list()?)
|
||||
} else if let Some(impl_ast) = ctx.find_node_at_offset::<ast::Impl>() {
|
||||
sort_methods_assist(acc, impl_ast.assoc_item_list()?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_methods_assist(acc: &mut Assists, item_list: ast::AssocItemList) -> Option<()> {
|
||||
let methods = get_methods(&item_list);
|
||||
let sorted = sort_by_name(&methods);
|
||||
|
||||
if methods == sorted {
|
||||
cov_mark::hit!(not_applicable_if_sorted);
|
||||
return None;
|
||||
}
|
||||
|
||||
acc.add(
|
||||
AssistId("sort_items", AssistKind::RefactorRewrite),
|
||||
"Sort methods alphabetically",
|
||||
item_list.syntax().text_range(),
|
||||
|builder| {
|
||||
let methods = methods.into_iter().map(|fn_| builder.make_mut(fn_)).collect::<Vec<_>>();
|
||||
methods
|
||||
.into_iter()
|
||||
.zip(sorted)
|
||||
.for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn sort_by_name<T: NameOwner + Clone>(initial: &[T]) -> Vec<T> {
|
||||
initial
|
||||
.iter()
|
||||
.cloned()
|
||||
.sorted_by(|a, b| match (a.name(), b.name()) {
|
||||
(Some(a), Some(b)) => Ord::cmp(&a.to_string(), &b.to_string()),
|
||||
|
||||
// unexpected, but just in case
|
||||
(None, None) => Ordering::Equal,
|
||||
(None, Some(_)) => Ordering::Less,
|
||||
(Some(_), None) => Ordering::Greater,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn not_applicable_if_trait_sorted() {
|
||||
cov_mark::check!(not_applicable_if_sorted);
|
||||
|
||||
check_assist_not_applicable(
|
||||
sort_items,
|
||||
r#"
|
||||
t$0rait Bar {
|
||||
fn a() {}
|
||||
fn b() {}
|
||||
fn c() {}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_applicable_if_impl_sorted() {
|
||||
cov_mark::check!(not_applicable_if_sorted);
|
||||
|
||||
check_assist_not_applicable(
|
||||
sort_items,
|
||||
r#"
|
||||
struct Bar;
|
||||
$0impl Bar {
|
||||
fn a() {}
|
||||
fn b() {}
|
||||
fn c() {}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_trait() {
|
||||
check_assist(
|
||||
sort_items,
|
||||
r#"
|
||||
$0trait Bar {
|
||||
fn a() {}
|
||||
fn c() {}
|
||||
fn z() {}
|
||||
fn b() {}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
trait Bar {
|
||||
fn a() {}
|
||||
fn b() {}
|
||||
fn c() {}
|
||||
fn z() {}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_impl() {
|
||||
check_assist(
|
||||
sort_items,
|
||||
r#"
|
||||
struct Bar;
|
||||
$0impl Bar {
|
||||
fn c() {}
|
||||
fn a() {}
|
||||
fn z() {}
|
||||
fn d() {}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
fn a() {}
|
||||
fn c() {}
|
||||
fn d() {}
|
||||
fn z() {}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -110,6 +110,7 @@ mod handlers {
|
|||
mod replace_qualified_name_with_use;
|
||||
mod replace_string_with_char;
|
||||
mod split_import;
|
||||
mod sort_items;
|
||||
mod toggle_ignore;
|
||||
mod unmerge_use;
|
||||
mod unwrap_block;
|
||||
|
@ -181,6 +182,7 @@ mod handlers {
|
|||
replace_impl_trait_with_generic::replace_impl_trait_with_generic,
|
||||
replace_let_with_if_let::replace_let_with_if_let,
|
||||
replace_qualified_name_with_use::replace_qualified_name_with_use,
|
||||
sort_items::sort_items,
|
||||
split_import::split_import,
|
||||
toggle_ignore::toggle_ignore,
|
||||
unmerge_use::unmerge_use,
|
||||
|
|
|
@ -516,3 +516,14 @@ fn ty_ctor(ty: &String, ctor: &str) -> Option<String> {
|
|||
let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string();
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub(crate) fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
|
||||
items
|
||||
.assoc_items()
|
||||
.flat_map(|i| match i {
|
||||
ast::AssocItem::Fn(f) => Some(f),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|f| f.name().is_some())
|
||||
.collect()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue