Skip to content

Commit 0694f18

Browse files
committed
Sort struct fields
1 parent 643f393 commit 0694f18

File tree

1 file changed

+117
-3
lines changed

1 file changed

+117
-3
lines changed

crates/ide_assists/src/handlers/sort_items.rs

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};
1414
//
1515
pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
1616
if let Some(trait_ast) = ctx.find_node_at_offset::<ast::Trait>() {
17-
sort_methods_assist(acc, trait_ast.assoc_item_list()?)
17+
add_sort_methods_assist(acc, trait_ast.assoc_item_list()?)
1818
} else if let Some(impl_ast) = ctx.find_node_at_offset::<ast::Impl>() {
19-
sort_methods_assist(acc, impl_ast.assoc_item_list()?)
19+
add_sort_methods_assist(acc, impl_ast.assoc_item_list()?)
20+
} else if let Some(struct_ast) = ctx.find_node_at_offset::<ast::Struct>() {
21+
add_sort_fields_assist(acc, struct_ast.field_list()?)
2022
} else {
2123
None
2224
}
2325
}
2426

25-
fn sort_methods_assist(acc: &mut Assists, item_list: ast::AssocItemList) -> Option<()> {
27+
fn add_sort_methods_assist(acc: &mut Assists, item_list: ast::AssocItemList) -> Option<()> {
2628
let methods = get_methods(&item_list);
2729
let sorted = sort_by_name(&methods);
2830

@@ -45,6 +47,36 @@ fn sort_methods_assist(acc: &mut Assists, item_list: ast::AssocItemList) -> Opti
4547
)
4648
}
4749

50+
fn add_sort_fields_assist(acc: &mut Assists, field_list: ast::FieldList) -> Option<()> {
51+
fn record_fields(field_list: &ast::FieldList) -> Option<Vec<ast::RecordField>> {
52+
match field_list {
53+
ast::FieldList::RecordFieldList(it) => Some(it.fields().collect()),
54+
ast::FieldList::TupleFieldList(_) => None,
55+
}
56+
}
57+
58+
let fields = record_fields(&field_list)?;
59+
let sorted = sort_by_name(&fields);
60+
61+
if fields == sorted {
62+
cov_mark::hit!(not_applicable_if_sorted);
63+
return None;
64+
}
65+
66+
acc.add(
67+
AssistId("sort_items", AssistKind::RefactorRewrite),
68+
"Sort methods alphabetically",
69+
field_list.syntax().text_range(),
70+
|builder| {
71+
let methods = fields.into_iter().map(|fn_| builder.make_mut(fn_)).collect::<Vec<_>>();
72+
methods
73+
.into_iter()
74+
.zip(sorted)
75+
.for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
76+
},
77+
)
78+
}
79+
4880
fn sort_by_name<T: NameOwner + Clone>(initial: &[T]) -> Vec<T> {
4981
initial
5082
.iter()
@@ -99,6 +131,22 @@ $0impl Bar {
99131
)
100132
}
101133

134+
#[test]
135+
fn not_applicable_if_struct_sorted() {
136+
cov_mark::check!(not_applicable_if_sorted);
137+
138+
check_assist_not_applicable(
139+
sort_items,
140+
r#"
141+
$0struct Bar {
142+
a: u32,
143+
b: u8,
144+
c: u64,
145+
}
146+
"#,
147+
)
148+
}
149+
102150
#[test]
103151
fn sort_trait() {
104152
check_assist(
@@ -146,4 +194,70 @@ impl Bar {
146194
"#,
147195
)
148196
}
197+
198+
#[test]
199+
fn sort_struct() {
200+
check_assist(
201+
sort_items,
202+
r#"
203+
$0struct Bar {
204+
b: u8,
205+
a: u32,
206+
c: u64,
207+
}
208+
"#,
209+
r#"
210+
struct Bar {
211+
a: u32,
212+
b: u8,
213+
c: u64,
214+
}
215+
"#,
216+
)
217+
}
218+
219+
#[test]
220+
fn sort_generic_struct_with_lifetime() {
221+
check_assist(
222+
sort_items,
223+
r#"
224+
$0struct Bar<'a, T> {
225+
d: &'a str,
226+
b: u8,
227+
a: T,
228+
c: u64,
229+
}
230+
"#,
231+
r#"
232+
struct Bar<'a, T> {
233+
a: T,
234+
b: u8,
235+
c: u64,
236+
d: &'a str,
237+
}
238+
"#,
239+
)
240+
}
241+
242+
#[test]
243+
fn sort_struct_fields_diff_len() {
244+
check_assist(
245+
sort_items,
246+
r#"
247+
$0struct Bar {
248+
aaa: u8,
249+
a: usize,
250+
b: u8,
251+
}
252+
"#,
253+
r#"
254+
struct Bar {
255+
a: usize,
256+
aaa: u8,
257+
b: u8,
258+
}
259+
"#,
260+
)
261+
}
262+
149263
}

0 commit comments

Comments
 (0)